Numerous changes more than can be stated here.

Basically all the modules made by hand from the SAML XML schemas has been replaced
with modules made by a XML Schema -> Python module script.
This change has caused a lot of necessary changes in code that depends on the format/content
of the SAML modules.
The configuration has changed, partly because the need to support more than one endpoint.
This commit is contained in:
Roland Hedberg
2010-07-21 13:04:15 +02:00
parent c21ffda573
commit 046204bf6b
42 changed files with 6986 additions and 10390 deletions

View File

@@ -36,7 +36,7 @@ from repoze.who.plugins.form import FormPluginBase
from saml2.client import Saml2Client
from saml2.attribute_resolver import AttributeResolver
from saml2.config import Config
from saml2.cache import Cache
from saml2.population import Population
def construct_came_from(environ):
""" The URL that the user used when the process where interupted
@@ -55,7 +55,12 @@ def cgi_fieldStorage_to_dict( fieldStorage ):
params = {}
for key in fieldStorage.keys():
try:
params[ key ] = fieldStorage[ key ].value
except AttributeError:
if isinstance(fieldStorage[ key ], basestring):
params[key] = fieldStorage[key]
return params
class SAML2Plugin(FormPluginBase):
@@ -92,18 +97,7 @@ class SAML2Plugin(FormPluginBase):
self.outstanding_queries = {}
self.iam = os.uname()[1]
if cache:
self.cache = Cache(cache)
else:
self.cache = Cache()
def _cache_session(self, session_info):
name_id = session_info["name_id"]
issuer = session_info["issuer"]
del session_info["issuer"]
self.cache.set(name_id, issuer, session_info,
session_info["not_on_or_after"])
return name_id
self.users = Population(cache)
def _pick_idp(self, environ):
"""
@@ -234,7 +228,7 @@ class SAML2Plugin(FormPluginBase):
session_info = ar.session_info()
# Cache it
name_id = self._cache_session(session_info)
name_id = self.users.add_information_about_person(session_info)
if self.debug:
self.log and self.log.info("stored %s with key %s" % (
session_info, name_id))
@@ -299,56 +293,6 @@ class SAML2Plugin(FormPluginBase):
else:
return None
def _vo_members_to_ask(self, subject_id):
# Find the member of the Virtual Organization that I haven't
# alrady spoken too
vo_members = [
member for member in self.metadata.vo_members(self.vorg)\
if member not in self.srv["idp"].keys()]
self.log and self.log.info("VO members: %s" % vo_members)
# Remove the ones I have cached data from about this subject
vo_members = [m for m in vo_members \
if not self.cache.active(subject_id, m)]
self.log and self.log.info(
"VO members (not cached): %s" % vo_members)
return vo_members
def _do_vo_aggregation(self, subject_id):
if self.log:
self.log.info("** Do VO aggregation **")
self.log.info("SubjectID: %s, VO:%s" % (subject_id, self.vorg))
vo_members = self._vo_members_to_ask(subject_id)
if vo_members:
# Find the NameIDFormat and the SPNameQualifier
if self.vorg_conf and "name_id_format" in self.vorg_conf:
name_id_format = self.vorg_conf["name_id_format"]
sp_name_qualifier = ""
else:
sp_name_qualifier = self.vorg
name_id_format = ""
resolver = AttributeResolver(environ, self.metadata, self.conf)
# extends returns a list of session_infos
for session_info in resolver.extend(subject_id,
self.conf["entityid"], vo_members,
name_id_format=name_id_format,
sp_name_qualifier=sp_name_qualifier,
log=self.log):
_ignore = self._cache_session(session_info)
self.log.info(
">Issuers: %s" % self.cache.entities(subject_id))
self.log.info(
"AVA: %s" % (self.cache.get_identity(subject_id),))
return True
else:
return False
# IMetadataProvider
def add_metadata(self, environ, identity):
@@ -381,7 +325,7 @@ class SAML2Plugin(FormPluginBase):
if "pysaml2_vo_expanded" not in identity:
# is this a Virtual Organization situation
if self.vorg:
if self._do_vo_aggregation(subject_id):
if self.vorg.do_vo_aggregation(subject_id):
# Get the extended identity
identity["user"] = self.cache.get_identity(subject_id)[0]
# Only do this once, mark that the identity has been

View File

@@ -31,6 +31,22 @@
provides methods and functions to convert SAML classes to and from strings.
"""
# try:
# # lxml: best performance for XML processing
# import lxml.etree as ET
# except ImportError:
# try:
# # Python 2.5+: batteries included
# import xml.etree.cElementTree as ET
# except ImportError:
# try:
# # Python <2.5: standalone ElementTree install
# import elementtree.cElementTree as ET
# except ImportError:
# raise ImportError, "lxml or ElementTree are not installed, "\
# +"see http://codespeak.net/lxml "\
# +"or http://effbot.org/zone/element-index.htm"
try:
from xml.etree import cElementTree as ElementTree
except ImportError:
@@ -45,7 +61,7 @@ NAMESPACE = 'urn:oasis:names:tc:SAML:2.0:assertion'
NAMEID_FORMAT_EMAILADDRESS = (
"urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress")
URN_PASSWORD = "urn:oasis:names:tc:SAML:2.0:ac:classes:Password"
NAME_FORMAT_UNSPECIFIED = (
"urn:oasis:names:tc:SAML:2.0:attrnam-format:unspecified")
NAME_FORMAT_URI = "urn:oasis:names:tc:SAML:2.0:attrnam-format:uri"
@@ -83,10 +99,10 @@ def create_class_from_xml_string(target_class, xml_string):
not match those of the target class.
"""
tree = ElementTree.fromstring(xml_string)
return _create_class_from_element_tree(target_class, tree)
return create_class_from_element_tree(target_class, tree)
def _create_class_from_element_tree(target_class, tree, namespace=None,
def create_class_from_element_tree(target_class, tree, namespace=None,
tag=None):
"""Instantiates the class and populates members according to the tree.
@@ -411,6 +427,9 @@ class SamlBase(ExtensionContainer):
c_children = {}
c_attributes = {}
c_attribute_type = {}
#c_attribute_use = {}
c_attribute_required = {}
c_child_order = []
def _get_all_c_children_with_order(self):
@@ -433,11 +452,11 @@ class SamlBase(ExtensionContainer):
if getattr(self, member_name) is None:
setattr(self, member_name, [])
getattr(self, member_name).append(
_create_class_from_element_tree(
create_class_from_element_tree(
member_class[0], child_tree))
else:
setattr(self, member_name,
_create_class_from_element_tree(member_class,
create_class_from_element_tree(member_class,
child_tree))
else:
ExtensionContainer._convert_element_tree_to_member(self,
@@ -449,7 +468,7 @@ class SamlBase(ExtensionContainer):
# Find the member of this class which corresponds to the XML
# attribute(lookup in current_class.c_attributes) and set this
# member to the desired value (using self.__dict__).
setattr(self, self.__class__.c_attributes[attribute], value)
setattr(self, self.__class__.c_attributes[attribute][0], value)
else:
# If it doesn't appear in the attribute list it's an extension
ExtensionContainer._convert_element_attribute_to_member(self,
@@ -470,8 +489,9 @@ class SamlBase(ExtensionContainer):
else:
member.become_child_element_of(tree)
# Convert the members of this class which are XML attributes.
for xml_attribute, member_name in \
for xml_attribute, attribute_info in \
self.__class__.c_attributes.iteritems():
(member_name, member_type, required) = attribute_info
member = getattr(self, member_name)
if member is not None:
tree.attrib[xml_attribute] = member
@@ -514,7 +534,8 @@ class SamlBase(ExtensionContainer):
def _init_attribute(self, extension_attribute_id,
extension_attribute_name, value=None):
self.c_attributes[extension_attribute_id] = extension_attribute_name
self.c_attributes[extension_attribute_id] = (extension_attribute_name,
None, False)
if value:
self.__dict__[extension_attribute_name] = value
@@ -532,7 +553,7 @@ class SamlBase(ExtensionContainer):
:return: list of keys
"""
keys = ['text']
keys.extend(self.c_attributes.values())
keys.extend([n for (n, t, r) in self.c_attributes.values()])
keys.extend([v[1] for v in self.c_children.values()])
return keys
@@ -592,7 +613,7 @@ class SamlBase(ExtensionContainer):
:return: The instance
"""
for prop in self.c_attributes.values():
for prop, _typ, _req in self.c_attributes.values():
#print "# %s" % (prop)
if prop in ava:
if isinstance(ava[prop], bool):
@@ -641,7 +662,7 @@ def element_to_extension_element(element):
exel = ExtensionElement(element.c_tag, element.c_namespace,
text=element.text)
for xml_attribute, member_name in element.c_attributes.iteritems():
for xml_attribute, (member_name, typ, req) in element.c_attributes.iteritems():
member_value = getattr(element, member_name)
if member_value is not None:
exel.attributes[xml_attribute] = member_value

View File

@@ -23,12 +23,14 @@ from saml2 import saml
from saml2.time_util import instant, in_a_while
from saml2.attribute_converter import from_local
from saml2.utils import sid, MissingValue
from saml2.utils import args2dict
from saml2.utils import assertion_factory
from saml2.s_utils import sid, MissingValue
from saml2.s_utils import factory
from saml2.s_utils import assertion_factory
from saml2.s_utils import do_attribute_statement
def _filter_values(vals, required=None, optional=None):
""" Removes values from *val* that does not appear in *attributes*.
""" Removes values from *vals* that does not appear in *required*
or *optional*.
:param val: The values that are to be filtered
:param required: The required values
@@ -314,12 +316,13 @@ class Policy(object):
return self.filter(ava, sp_entity_id, required, optional)
def conditions(self, sp_entity_id):
return args2dict(
return factory( saml.Conditions,
not_before=instant(),
# How long might depend on who's getting it
not_on_or_after=self._not_on_or_after(sp_entity_id),
audience_restriction=args2dict(
audience=args2dict(sp_entity_id)))
audience_restriction=[factory( saml.AudienceRestriction,
audience=factory(saml.Audience,
text=sp_entity_id))])
class Assertion(dict):
""" Handles assertions about subjects """
@@ -327,14 +330,28 @@ class Assertion(dict):
def __init__(self, dic=None):
dict.__init__(self, dic)
def _authn_statement(self):
return args2dict(authn_instant=instant(), session_index=sid())
def _authn_context(self, authn_class):
return factory(saml.AuthnContext,
authn_context_class_ref=factory(
saml.AuthnContextClassRef, text=authn_class))
def _authn_statement(self, authn_class):
if authn_class:
return factory(saml.AuthnStatement,
authn_instant=instant(),
session_index=sid(),
authn_context=self._authn_context(authn_class))
else:
return factory(saml.AuthnStatement,
authn_instant=instant(),
session_index=sid())
def construct(self, sp_entity_id, in_response_to, name_id, attrconvs,
policy, issuer):
policy, issuer, authn_class=None):
attr_statement = from_local(attrconvs, self,
policy.get_name_form(sp_entity_id))
attr_statement = saml.AttributeStatement(attribute=from_local(
attrconvs, self,
policy.get_name_form(sp_entity_id)))
# start using now and for a hour
conds = policy.conditions(sp_entity_id)
@@ -342,14 +359,15 @@ class Assertion(dict):
return assertion_factory(
issuer=issuer,
attribute_statement = attr_statement,
authn_statement = self._authn_statement(),
authn_statement = self._authn_statement(authn_class),
conditions = conds,
subject=args2dict(
subject=factory( saml.Subject,
name_id=name_id,
method=saml.SUBJECT_CONFIRMATION_METHOD_BEARER,
subject_confirmation=args2dict(
subject_confirmation_data = \
args2dict(in_response_to=in_response_to))),
subject_confirmation=factory( saml.SubjectConfirmation,
subject_confirmation_data=factory(
saml.SubjectConfirmationData,
in_response_to=in_response_to))),
)
def apply_policy(self, sp_entity_id, policy, metadata=None):

View File

@@ -16,7 +16,8 @@
# limitations under the License.
import os
from saml2.utils import args2dict
from saml2.s_utils import factory, do_ava
from saml2 import saml
from saml2.saml import NAME_FORMAT_URI
class UnknownNameFormat(Exception):
@@ -64,7 +65,7 @@ def from_local(acs, ava, name_format):
#print ac.format, name_format
if aconv.name_format == name_format:
#print "Found a name_form converter"
return aconv.to(ava)
return aconv.to_(ava)
return None
@@ -73,7 +74,7 @@ def from_local_name(acs, attr, name_format):
:param acs: List of AttributeConverter instances
:param attr: attribute name as string
:param name_format: Which name-format it should be translated to
:return: A dictionary suitable to feed to make_instance
:return: An Attribute instance
"""
for aconv in acs:
#print ac.format, name_format
@@ -118,7 +119,7 @@ class AttributeConverter(object):
self._to = eval(open(filename).read())
def adjust(self):
if self._fro == None and self.to != None:
if self._fro == None and self._to != None:
self._fro = dict([(value, key) for key, value in self._to.items()])
if self._to == None and self.fro != None:
self._to = dict([(value, key) for key, value in self._fro.items()])
@@ -184,10 +185,12 @@ class AttributeConverter(object):
def to_format(self, attr):
try:
return args2dict(name=self._to[attr], name_format=self.name_format,
return factory(saml.Attribute,
name=self._to[attr],
name_format=self.name_format,
friendly_name=attr)
except KeyError:
return args2dict(name=attr)
return factory(saml.Attribute, name=attr)
def from_format(self, attr):
"""
@@ -201,18 +204,18 @@ class AttributeConverter(object):
pass
return ""
def to(self, ava):
def to_(self, attrvals):
attributes = []
for key, value in ava.items():
for key, value in attrvals.items():
try:
attributes.append(args2dict(name=self._to[key],
attributes.append(factory(saml.Attribute,
name=self._to[key],
name_format=self.name_format,
friendly_name=key,
attribute_value=value))
attribute_value=do_ava(value)))
except KeyError:
# TODO
# Should this be made different ???
attributes.append(args2dict(name=key,
attribute_value=value))
attributes.append(factory(saml.Attribute,
name=key,
attribute_value=do_ava(value)))
return {"attribute": attributes}
return attributes

View File

@@ -20,7 +20,6 @@ Contains classes and functions that a SAML2.0 Service Provider (SP) may use
to do attribute aggregation.
"""
import saml2
from saml2.client import Saml2Client
DEFAULT_BINDING = saml2.BINDING_HTTP_REDIRECT
@@ -32,7 +31,7 @@ class AttributeResolver(object):
if saml2client:
self.saml2client = saml2client
else:
self.saml2client = Saml2Client(environ, config)
self.saml2client = saml2.client.Saml2Client(environ, config)
def extend(self, subject_id, issuer, vo_members, name_id_format=None,
sp_name_qualifier=None, log=None):

View File

@@ -31,6 +31,11 @@ from saml2.time_util import daylight_corrected_now
# ---------------------------------------------------------------------------
class IncorrectlySigned(Exception):
pass
# ---------------------------------------------------------------------------
def _use_on_or_after(condition, slack):
now = daylight_corrected_now()
#print "NOW: %d" % now
@@ -57,8 +62,9 @@ def _use_before(condition, slack):
return True
def for_me(condition, myself ):
# Am I among the intended audiences
for restriction in condition.audience_restriction:
audience = restriction.audience
for audience in restriction.audience:
if audience.text.strip() == myself:
return True
else:
@@ -67,13 +73,6 @@ def for_me(condition, myself ):
return False
# ---------------------------------------------------------------------------
class IncorrectlySigned(Exception):
pass
# ---------------------------------------------------------------------------
def authn_response(conf, requestor, outstanding_queries=None, log=None,
timeslack=0, debug=0):
sec = security_context(conf)
@@ -128,7 +127,6 @@ class AuthnResponse(object):
self.response = self.sec.correctly_signed_response(decoded_xml)
except Exception, excp:
self.log and self.log.info("EXCEPTION: %s", excp)
raise
if not self.response:
if self.log:
@@ -180,7 +178,7 @@ class AuthnResponse(object):
self.not_on_or_after = _use_on_or_after(condition, self.timeslack)
_use_before(condition, self.timeslack)
except Exception, excp:
self.log.error("Exception on condition: %s" % (excp,))
self.log and self.log.error("Exception on condition: %s" % (excp,))
if not lax:
raise
else:
@@ -230,6 +228,7 @@ class AuthnResponse(object):
# The subject must contain a name_id
assert subject.name_id
self.name_id = subject.name_id.text.strip()
return self.name_id
def _assertion(self, assertion):
self.assertion = assertion
@@ -294,7 +293,7 @@ class AuthnResponse(object):
return True
def verify(self):
""" Verify that the assertion is syntaktically correct and
""" Verify that the assertion is syntactically correct and
the signature is correct if present."""
self.status_ok()

View File

@@ -2,6 +2,7 @@
import shelve
import time
from saml2 import time_util
# The assumption is that any subject may consist of data
# gathered from several different sources, all with their own
@@ -19,6 +20,9 @@ class Cache(object):
self._db = {}
self._sync = False
def delete(self, subject_id):
del self._db[subject_id]
def get_identity(self, subject_id, entities=None):
""" Get all the identity information that has been received and
are still valid about the subject.
@@ -53,24 +57,27 @@ class Cache(object):
return (res, oldees)
def get(self, subject_id, entity_id):
""" Get seesion information about a the session when an
assertion was received from an IdP or an AA or sent to a SP.
""" Get session information about a subject gotten from a
specified IdP.
:param subject_id: The identifier of the subject
:param entity_id: The identifier of the entity_id
:return: The session information
"""
(not_on_or_after, info) = self._db[subject_id][entity_id]
now = time.gmtime()
if isinstance(not_on_or_after, time.struct_time):
not_on_or_after = time.mktime(not_on_or_after)
now = time_util.daylight_corrected_now()
if not_on_or_after < now:
self.reset(subject_id, entity_id)
raise ToOld()
#self.reset(subject_id, entity_id)
raise ToOld("%s < %s" % (not_on_or_after, now))
else:
return info
def set( self, subject_id, entity_id, info, not_on_or_after=0):
""" Stores session information in the cache
""" Stores session information in the cache. Assumes that the subject_id
is unique within the context of the Service Provider.
:param subject_id: The subjects identifier
:param entity_id: The identifier of the entity_id/receiver of an

View File

@@ -25,14 +25,16 @@ import saml2
import base64
from saml2.time_util import instant
from saml2.utils import sid, deflate_and_base64_encode
from saml2.utils import do_attributes, args2dict
from saml2.s_utils import sid, deflate_and_base64_encode
from saml2.s_utils import do_attributes, factory
from saml2 import samlp, saml
from saml2 import VERSION, make_instance
from saml2 import samlp, saml, class_name
from saml2 import VERSION
from saml2.sigver import pre_signature_part
from saml2.sigver import security_context, signed_instance_factory
from saml2.soap import SOAPClient
from saml2.population import Population
from saml2.virtual_org import VirtualOrg
from saml2.authnresponse import authn_response
@@ -46,19 +48,32 @@ FORM_SPEC = """<form method="post" action="%s">
LAX = False
class IdpUnspecified(Exception):
pass
class VerifyError(Exception):
pass
class Saml2Client(object):
""" The basic pySAML2 service provider class """
def __init__(self, environ, config=None, debug=0):
def __init__(self, environ, config=None, debug=0, vorg=None,
persistent_cache=None):
"""
:param environ:
:param config: A saml2.config.Config instance
"""
self.environ = environ
self.vorg = None
self.users = Population(persistent_cache)
if config:
self.config = config
if "metadata" in config:
self.metadata = config["metadata"]
if vorg:
self.vorg = VirtualOrg(self.metadata, vorg,
self.users.cache,
log=None, vorg_conf=None)
self.sec = security_context(config)
self.debug = debug
@@ -71,32 +86,23 @@ class Saml2Client(object):
return request
def idp_entry(self, name=None, location=None, provider_id=None):
res = {}
res = samlp.IDPEntry()
if name:
res["name"] = name
res.name = name
if location:
res["loc"] = location
res.loc = location
if provider_id:
res["provider_id"] = provider_id
if res:
res.provider_id = provider_id
return res
else:
return None
def scoping(self, idp_ents):
return {
"idp_list": {
"idp_entry": idp_ents
}
}
def scoping_from_metadata(self, entityid, location):
def scoping_from_metadata(self, entityid, location=None):
name = self.metadata.name(entityid)
return make_instance(samlp.Scoping,
self.scoping([self.idp_entry(name, location)]))
idp_ent = self.idp_entry(name, location)
return samlp.Scoping(idp_list=samlp.IDPList(idp_entry=[idp_ent]))
def response(self, post, requestor, outstanding, log=None):
""" Deal with the AuthnResponse
""" Deal with an AuthnResponse
:param post: The reply as a dictionary
:param requestor: The issuer of the AuthN request
@@ -104,10 +110,8 @@ class Saml2Client(object):
the original web request from the user before redirection
as values.
:param log: where loggin should go.
:return: A 2-tuple of identity information (in the form of a
dictionary) and where the user should really be sent. This
might differ from what the IdP thinks since I don't want
to reveal verything to it and it might not trust me.
:return: An authnresponse.AuthnResponse instance which among other
things contains a verified saml2.AuthnResponse instance.
"""
# If the request contains a samlResponse, try to validate it
try:
@@ -115,15 +119,18 @@ class Saml2Client(object):
except KeyError:
return None
aresp = None
if saml_response:
aresp = authn_response(self.config, requestor, outstanding, log,
debug=self.debug)
aresp.loads(saml_response)
if self.debug:
log and log.info(aresp)
return aresp.verify()
aresp = aresp.verify()
if aresp:
self.users.add_information_about_person(aresp.session_info())
return None
return aresp
def authn_request(self, query_id, destination, service_url, spentityid,
my_name, vorg="", scoping=None, log=None, sign=False):
@@ -139,45 +146,78 @@ class Saml2Client(object):
:param log: A service to which logs should be written
:param sign: Whether the request should be signed or not.
"""
prel = {
"id": query_id,
"version": VERSION,
"issue_instant": instant(),
"destination": destination,
"assertion_consumer_service_url": service_url,
"protocol_binding": saml2.BINDING_HTTP_POST,
"provider_name": my_name,
}
request = samlp.AuthnRequest(
id= query_id,
version= VERSION,
issue_instant= instant(),
destination= destination,
assertion_consumer_service_url= service_url,
protocol_binding= saml2.BINDING_HTTP_POST,
provider_name= my_name
)
if scoping:
prel["scoping"] = scoping
request.scoping = scoping
name_id_policy = {
"allow_create": "true"
}
# Profile stuff, should be configurable
name_id_policy = samlp.NameIDPolicy(allow_create="true",
format=saml.NAMEID_FORMAT_TRANSIENT)
name_id_policy["format"] = saml.NAMEID_FORMAT_TRANSIENT
if vorg:
try:
name_id_policy["sp_name_qualifier"] = vorg
name_id_policy["format"] = saml.NAMEID_FORMAT_PERSISTENT
name_id_policy.sp_name_qualifier = vorg
name_id_policy.format = saml.NAMEID_FORMAT_PERSISTENT
except KeyError:
pass
if sign:
prel["signature"] = pre_signature_part(prel["id"],
self.sec.my_cert, id=1)
request.signature = pre_signature_part(request.id,
self.sec.my_cert, 1)
to_sign = [(class_name(request), request.id)]
else:
to_sign = []
prel["name_id_policy"] = name_id_policy
prel["issuer"] = { "text": spentityid }
request.name_id_policy = name_id_policy
request.issuer = factory(saml.Issuer, text=spentityid )
if log:
log.info("DICT VERSION: %s" % prel)
log.info("REQUEST: %s" % request)
return "%s" % signed_instance_factory(samlp.AuthnRequest, prel,
self.sec)
return "%s" % signed_instance_factory(request, self.sec, to_sign)
def authenticate(self, spentityid, location="", service_url="",
def issuer(self):
""" Return an Issuer instance """
return saml.Issuer(text=self.config["entityid"],
format=saml.NAMEID_FORMAT_ENTITY)
def _spentityid(self, spentityid=None):
if self.config:
return self.config["entityid"]
else:
return spentityid
def _location(self, location=None):
if not location :
# get the idp location from the configuration alternative the metadata
# If there is more than one IdP in the configuration raise exception
urls = self.config.idps()
if len(urls) > 1:
raise IdpUnspecified("Too many IdPs to choose from: %s" % urls)
return urls[0]
else:
return location
def _service_url(self, url=None):
if not url:
return self.config.endpoint("sp", "assertion_consumer_service")[0]
def _my_name(self, name=None):
if not name:
return self.config["service"]["sp"]["name"]
else:
return name
def authenticate(self, spentityid=None, location="", service_url="",
my_name="", relay_state="",
binding=saml2.BINDING_HTTP_REDIRECT, log=None,
vorg="", scoping=None):
@@ -199,11 +239,17 @@ class Saml2Client(object):
:return: AuthnRequest response
"""
spentityid = self._spentityid(spentityid)
location = self._location(location)
service_url = self._service_url(service_url)
my_name = self._my_name(my_name)
if log:
log.info("spentityid: %s" % spentityid)
log.info("location: %s" % location)
log.info("service_url: %s" % service_url)
log.info("my_name: %s" % my_name)
session_id = sid()
authen_req = self.authn_request(session_id, location,
service_url, spentityid, my_name, vorg,
@@ -229,7 +275,8 @@ class Saml2Client(object):
lista = ["SAMLRequest=%s" % urllib.quote_plus(
deflate_and_base64_encode(
authen_req)),
"spentityid=%s" % spentityid]
#"spentityid=%s" % spentityid
]
if relay_state:
lista.append("RelayState=%s" % relay_state)
login_url = "?".join([location, "&".join(lista)])
@@ -263,35 +310,35 @@ class Saml2Client(object):
"""
subject = args2dict(
name_id = args2dict(subject_id, format=nameid_format,
subject = saml.Subject(
name_id = saml.NameID(
text=subject_id,
format=nameid_format,
sp_name_qualifier=sp_name_qualifier,
name_qualifier=name_qualifier),
)
prequery = {
"id": session_id,
"version": VERSION,
"issue_instant": instant(),
"destination": destination,
"issuer": issuer,
"subject":subject,
}
query = samlp.AttributeQuery(
id=session_id,
version=VERSION,
issue_instant=instant(),
destination=destination,
issuer=self.issuer(),
subject=subject,
)
if sign:
prequery["signature"] = pre_signature_part(prequery["id"],
self.sec.my_cert, 1)
query.signature = pre_signature_part(query.id, self.sec.my_cert, 1)
if attribute:
prequery["attribute"] = do_attributes(attribute)
query.attribute = do_attributes(attribute)
request = make_instance(samlp.AttributeQuery, prequery)
if sign:
signed_req = self.sec.sign_assertion_using_xmlsec("%s" % request)
return samlp.attribute_query_from_string(signed_req)
signed_query = self.sec.sign_assertion_using_xmlsec("%s" % query)
return samlp.attribute_query_from_string(signed_query)
else:
return request
return query
def attribute_query(self, subject_id, issuer, destination,
@@ -334,14 +381,17 @@ class Saml2Client(object):
aresp = authn_response(self.config, issuer, {session_id:""}, log)
session_info = aresp.loads(response).verify().session_info()
if session_info:
self.users.add_information_about_person(session_info)
log and log.info("session: %s" % session_info)
return session_info
else:
log and log.info("No response")
return None
def make_logout_request(self, session_id, destination, issuer,
reason=None, not_on_or_after=None):
def make_logout_requests(self, subject_id, reason=None,
not_on_or_after=None):
""" Constructs a LogoutRequest
:param subject_id: The identifier of the subject
@@ -349,31 +399,67 @@ class Saml2Client(object):
form of a URI reference.
:param not_on_or_after: The time at which the request expires,
after which the recipient may discard the message.
:return: An AttributeQuery instance
:return: A LogoutRequest instance
"""
prel = {
"id": sid(),
"version": VERSION,
"issue_instant": instant(),
"destination": destination,
"issuer": issuer,
"session_index": session_id,
}
result = []
for entity_id in self.users.issuers_of_info(subject_id):
destination = self.config["service"]["sp"]["idp"][entity_id]
# create NameID from subject_id
name_id = NameID(
text=self.client.users.get_entityid(subject_id,
entity_id)["name_id"])
request = samlp.LogoutRequest(
id=sid(),
version=VERSION,
issue_instant=instant(),
destination=destination,
issuer=self.issuer(),
session_index=session_id,
name_id = name_id
)
if reason:
prel["reason"] = reason
request.reason = reason
if not_on_or_after:
prel["not_on_or_after"] = not_on_or_after
request.not_on_or_after = not_on_or_after
return make_instance(samlp.LogoutRequest, prel)
result.append(request)
def logout(self, session_id, destination,
issuer, reason="", not_on_or_after=None):
return self.make_logout_request(session_id, destination,
issuer, reason, not_on_or_after)
return result
def global_logout(self, subject_id, reason="", not_on_or_after=None):
requests = self.make_logout_requests(subject_id, reason,
not_on_or_after)
return [r.id for r in requests]
def local_logout(self, subject_id, reason="", not_on_or_after=None):
# Remove the user from the cache, equals local logout
self.users.remove_person(subject_id)
return True
def add_vo_information_about_user(self, subject_id):
""" Add information to the knowledge I have about the user """
try:
(ava, _) = self.users.get_identity(subject_id)
except KeyError:
pass
# is this a Virtual Organization situation
if self.vorg:
if self.vorg.do_vo_aggregation(subject_id):
# Get the extended identity
ava = self.users.get_identity(subject_id)[0]
return ava
def is_session_valid(session_id):
return True
# ----------------------------------------------------------------------

View File

@@ -43,11 +43,11 @@ class Config(dict):
assert "idp" in config
assert len(config["idp"]) > 0
assert "url" in config
assert "endpoints" in config
assert "name" in config
def _idp_aa_check(self, config):
assert "url" in config
assert "endpoints" in config
if "assertions" in config:
config["policy"] = Policy(config["assertions"])
del config["assertions"]
@@ -95,6 +95,7 @@ class Config(dict):
config["metadata"] = self.load_metadata(config["metadata"],
config["xmlsec_binary"],
config["attrconverters"])
self.metadata = config["metadata"]
if "sp" in config["service"]:
#print config["service"]["sp"]
@@ -130,11 +131,11 @@ class Config(dict):
except KeyError:
return Policy()
def aa_url(self):
return self["service"]["aa"]["url"]
def idp_url(self):
return self["service"]["idp"]["url"]
def endpoint(self, typ, service):
try:
return self["service"][typ]["endpoints"][service]
except KeyError:
return None
def vo_conf(self, name):
return self["virtual_organization"][name]
@@ -142,3 +143,24 @@ class Config(dict):
def attribute_converters(self):
return self["attrconverters"]
def idps(self):
""" Returns a list of URLs of the IdP this SP can
use according to the configuration"""
try:
return [u for u in self["service"]["sp"]["idp"].values()]
except KeyError:
return []
def is_wayf_needed(self):
if len(self["service"]["sp"]["idp"]) > 1:
return True
else: # not really true, what if it's zero (0)
return False
def get_available_idps(self):
lista = []
for eid, url in self["service"]["sp"]["idp"].items():
namn = self.metadata.name(eid)
lista.append((eid, namn))
return lista

File diff suppressed because it is too large Load Diff

View File

@@ -88,7 +88,7 @@ class MetaData(object):
:param entity_descriptor: A EntityDescriptor instance
"""
try:
ssd = entity_descriptor.sp_sso_descriptor
ssd = entity_descriptor.spsso_descriptor
except AttributeError:
return
@@ -141,7 +141,7 @@ class MetaData(object):
:param entity_descriptor: A EntityDescriptor instance
"""
try:
isd = entity_descriptor.idp_sso_descriptor
isd = entity_descriptor.idpsso_descriptor
except AttributeError:
return
@@ -280,7 +280,7 @@ class MetaData(object):
except AttributeError:
pass
try:
entity["contact"] = entity_descriptor.contact
entity["contact_person"] = entity_descriptor.contact_person
except AttributeError:
pass
@@ -394,23 +394,26 @@ class MetaData(object):
:param entityid: The Entity ID
:return: A name
"""
try:
org = self.entity[entity_id]["organization"]
try:
names = org.organization_display_name
except KeyError:
try:
names = org.organization_name
except KeyError:
try:
names = org.organization_url
except KeyError:
names = None
if names:
name = names[0].text
except KeyError:
name = ""
try:
for org in self.entity[entity_id]["organization"]:
try:
name = org.organization_display_name[0]
except IndexError:
try:
name = org.organization_name[0]
except IndexError:
try:
name = org.organization_url[0]
except IndexError:
pass
if name:
name = name.text
except KeyError:
pass
return name
@keep_updated

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -24,13 +24,13 @@ import sys
from saml2 import saml, samlp, VERSION, class_name
from saml2.utils import sid, decode_base64_and_inflate
from saml2.utils import response_factory
from saml2.utils import MissingValue, args2dict
from saml2.utils import success_status_factory
from saml2.utils import OtherError
from saml2.utils import VersionMismatch, UnknownPrincipal, UnsupportedBinding
from saml2.utils import status_from_exception_factory
from saml2.s_utils import sid, decode_base64_and_inflate
from saml2.s_utils import response_factory
from saml2.s_utils import MissingValue, factory
from saml2.s_utils import success_status_factory
from saml2.s_utils import OtherError
from saml2.s_utils import VersionMismatch, UnknownPrincipal, UnsupportedBinding
from saml2.s_utils import status_from_exception_factory
from saml2.sigver import security_context, signed_instance_factory
from saml2.sigver import pre_signature_part
@@ -105,8 +105,11 @@ class Identifier(object):
except KeyError:
nameid_format = saml.NAMEID_FORMAT_PERSISTENT
return args2dict(subj_id, format=nameid_format,
sp_name_qualifier=sp_name_qualifier)
return saml.NameID(format=nameid_format,
sp_name_qualifier=sp_name_qualifier,
text=subj_id)
# return args2dict(subj_id, format=nameid_format,
# sp_name_qualifier=sp_name_qualifier)
def persistent_nameid(self, sp_name_qualifier, userid):
""" Get or create a persistent identifier for this object to be used
@@ -117,8 +120,18 @@ class Identifier(object):
:return: A persistent random identifier.
"""
subj_id = self.persistent(sp_name_qualifier, userid)
return args2dict(subj_id, format=saml.NAMEID_FORMAT_PERSISTENT,
sp_name_qualifier=sp_name_qualifier)
return saml.NameID(format=saml.NAMEID_FORMAT_PERSISTENT,
sp_name_qualifier=sp_name_qualifier,
text=subj_id)
# return args2dict(subj_id, format=saml.NAMEID_FORMAT_PERSISTENT,
# sp_name_qualifier=sp_name_qualifier)
def temporary_nameid(self):
""" Returns a random one-time identifier """
return saml.NameID(format=saml.NAMEID_FORMAT_TRANSIENT,
text=sid())
#return args2dict(sid(), format=saml.NAMEID_FORMAT_TRANSIENT)
def construct_nameid(self, local_policy, userid, sp_entity_id,
identity=None, name_id_policy=None):
@@ -143,9 +156,6 @@ class Identifier(object):
elif nameid_format == saml.NAMEID_FORMAT_TRANSIENT:
return self.temporary_nameid()
def temporary_nameid(self):
""" Returns a random one-time identifier """
return args2dict(sid(), format=saml.NAMEID_FORMAT_TRANSIENT)
class Server(object):
@@ -181,10 +191,9 @@ class Server(object):
def issuer(self):
""" Return an Issuer precursor """
return args2dict( self.conf["entityid"],
return saml.Issuer(text=self.conf["entityid"],
format=saml.NAMEID_FORMAT_ENTITY)
def parse_authn_request(self, enc_request):
"""Parse a Authentication Request
@@ -298,6 +307,8 @@ class Server(object):
:return: A Response instance
"""
to_sign = []
if not status:
status = success_status_factory()
@@ -323,19 +334,21 @@ class Server(object):
policy, issuer=_issuer)
if sign:
assertion["signature"] = pre_signature_part(assertion["id"],
assertion.signature = pre_signature_part(assertion.id,
self.sec.my_cert, 1)
# Just the assertion or the response and the assertion ?
to_sign = [(class_name(assertion), assertion.id)]
# Store which assertion that has been sent to which SP about which
# subject.
self.cache.set(assertion["subject"]["name_id"]["text"],
self.cache.set(assertion.subject.name_id.text,
sp_entity_id, assertion,
assertion["conditions"]["not_on_or_after"])
assertion.conditions.not_on_or_after)
response.update({"assertion":assertion})
response.assertion = assertion
return signed_instance_factory(samlp.Response, response, self.sec)
return signed_instance_factory(response, self.sec, to_sign)
# ------------------------------------------------------------------------

View File

@@ -19,7 +19,7 @@
Based on the use of xmlsec1 binaries and not the python xmlsec module.
"""
from saml2 import samlp, class_name, saml, make_instance
from saml2 import samlp, class_name, saml, ExtensionElement
from saml2 import create_class_from_xml_string
import xmldsig as ds
from tempfile import NamedTemporaryFile
@@ -27,7 +27,6 @@ from subprocess import Popen, PIPE
import base64
import random
import os
import copy
def get_xmlsec_binary():
for path in os.environ["PATH"].split(":"):
@@ -91,7 +90,7 @@ def _make_vals(val, klass, seccont, klass_inst=None, prop=None, part=False,
else:
try:
cinst = klass().set_text(val)
except ValueError, excp:
except ValueError:
if not part:
cis = [_make_vals(sval, klass, seccont, klass_inst, prop,
True, base64encode, elements_to_sign) for sval in val]
@@ -150,16 +149,12 @@ def _instance(klass, ava, seccont, base64encode=False, elements_to_sign=None):
return instance
def signed_instance_factory(klass, ava, seccont, base64encode=False):
elements_to_sign = []
instance = _instance(klass, ava, seccont, base64encode=False,
elements_to_sign=elements_to_sign)
def signed_instance_factory(instance, seccont, elements_to_sign=None):
if elements_to_sign:
signed_xml = "%s" % instance
for (node_name, nodeid) in elements_to_sign:
signed_xml = seccont.sign_statement_using_xmlsec(signed_xml,
class_name=node_name, nodeid=nodeid)
klass_namn=node_name, nodeid=nodeid)
#print "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
#print "%s" % signed_xml
@@ -351,6 +346,7 @@ class SecurityContext(object):
# Your private key
self.key_file = key_file
self.key_type = key_type
# Your certificate
self.cert_file = cert_file
@@ -379,7 +375,7 @@ class SecurityContext(object):
ntf = NamedTemporaryFile()
com_list = [self.xmlsec, "--decrypt",
"--privkey-pem", key_file,
"--privkey-pem", self.key_file,
"--output", ntf.name,
"--id-attr:%s" % ID_ATTR,
ENC_NODE_NAME, fil]
@@ -503,11 +499,11 @@ class SecurityContext(object):
return response
#----------------------------------------------------------------------------
#--------------------------------------------------------------------------
# SIGNATURE PART
#----------------------------------------------------------------------------
#--------------------------------------------------------------------------
def sign_statement_using_xmlsec(self, statement, class_name, key=None,
def sign_statement_using_xmlsec(self, statement, klass_namn, key=None,
key_file=None, nodeid=None):
"""Sign a SAML statement using xmlsec.
@@ -530,7 +526,7 @@ class SecurityContext(object):
com_list = [self.xmlsec, "--sign",
"--output", ntf.name,
"--privkey-pem", key_file,
"--id-attr:%s" % ID_ATTR, class_name,
"--id-attr:%s" % ID_ATTR, klass_namn,
#"--store-signatures"
]
if nodeid:
@@ -543,9 +539,9 @@ class SecurityContext(object):
# this doesn't work if --store-signatures are used
if out == "":
#print " ".join(com_list)
#print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
#print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
#print out
#print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
#print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
ntf.seek(0)
return ntf.read()
else:
@@ -568,39 +564,65 @@ class SecurityContext(object):
# ===========================================================================
PRE_SIGNATURE = {
"signed_info": {
"signature_method": {
"algorithm": ds.SIG_RSA_SHA1
},
"canonicalization_method": {
"algorithm": ds.ALG_EXC_C14N
},
"reference": {
# must be replace by a uriref based on the assertion ID
"uri": None,
"transforms": {
"transform": [{
"algorithm": ds.TRANSFORM_ENVELOPED,
},
{
"algorithm": ds.ALG_EXC_C14N,
"inclusive_namespaces": {
"prefix_list": "ds saml2 saml2p xenc",
}
}
]
},
"digest_method":{
"algorithm": ds.DIGEST_SHA1,
},
"digest_value": "",
}
},
"signature_value": None,
}
# PRE_SIGNATURE = {
# "signed_info": {
# "signature_method": {
# "algorithm": ds.SIG_RSA_SHA1
# },
# "canonicalization_method": {
# "algorithm": ds.ALG_EXC_C14N
# },
# "reference": {
# # must be replace by a uriref based on the assertion ID
# "uri": None,
# "transforms": {
# "transform": [{
# "algorithm": ds.TRANSFORM_ENVELOPED,
# },
# {
# "algorithm": ds.ALG_EXC_C14N,
# "inclusive_namespaces": {
# "prefix_list": "ds saml2 saml2p xenc",
# }
# }
# ]
# },
# "digest_method":{
# "algorithm": ds.DIGEST_SHA1,
# },
# "digest_value": "",
# }
# },
# "signature_value": None,
# }
#
# def pre_signature_part(ident, public_key=None, id=None):
# """
# If an assertion is to be signed the signature part has to be preset
# with which algorithms to be used, this function returns such a
# preset part.
#
# :param ident: The identifier of the assertion, so you know which assertion
# was signed
# :param public_key: The base64 part of a PEM file
# :return: A preset signature part
# """
#
# presig = copy.deepcopy(PRE_SIGNATURE)
# presig["signed_info"]["reference"]["uri"] = "#%s" % ident
# if id:
# presig["id"] = "Signature%d" % id
# if public_key:
# presig["key_info"] = {
# "x509_data": {
# "x509_certificate": public_key,
# }
# }
#
# return presig
def pre_signature_part(ident, public_key=None, id=None):
def pre_signature_part(ident, public_key=None, identifier=None):
"""
If an assertion is to be signed the signature part has to be preset
with which algorithms to be used, this function returns such a
@@ -612,15 +634,33 @@ def pre_signature_part(ident, public_key=None, id=None):
:return: A preset signature part
"""
presig = copy.deepcopy(PRE_SIGNATURE)
presig["signed_info"]["reference"]["uri"] = "#%s" % ident
if id:
presig["id"] = "Signature%d" % id
if public_key:
presig["key_info"] = {
"x509_data": {
"x509_certificate": public_key,
}
}
signature_method = ds.SignatureMethod(algorithm = ds.SIG_RSA_SHA1)
canonicalization_method = ds.CanonicalizationMethod(
algorithm = ds.ALG_EXC_C14N)
trans0 = ds.Transform(algorithm = ds.TRANSFORM_ENVELOPED)
trans1 = ds.Transform(algorithm = ds.ALG_EXC_C14N)
transforms = ds.Transforms(transform = [trans0, trans1])
digest_method = ds.DigestMethod(algorithm = ds.DIGEST_SHA1)
reference = ds.Reference(uri = "#%s" % ident,
digest_value = ds.DigestValue(),
transforms = transforms,
digest_method = digest_method)
signed_info = ds.SignedInfo(signature_method = signature_method,
canonicalization_method = canonicalization_method,
reference = reference)
signature = ds.Signature(signed_info=signed_info,
signature_value=ds.SignatureValue())
if identifier:
signature.id = "Signature%d" % identifier
if public_key:
x509_data = ds.X509Data(x509_certificate=[ds.X509Certificate(text=public_key)])
key_info = ds.KeyInfo(x509_data=x509_data)
signature.key_info = key_info
return signature
return presig

View File

@@ -62,7 +62,7 @@ def parse_soap_enveloped_saml_thingy(text, expected_tag):
else:
return ""
def make_soap_enveloped_saml_thingy(thingy):
def make_soap_enveloped_saml_thingy(thingy, headers=None):
""" Returns a soap envelope containing a SAML request
as a text string.
@@ -72,6 +72,13 @@ def make_soap_enveloped_saml_thingy(thingy):
envelope = ElementTree.Element('')
envelope.tag = '{%s}Envelope' % NAMESPACE
if headers:
header = ElementTree.Element('')
header.tag = '{%s}Header' % NAMESPACE
envelope.append(header)
for head in headers:
head.become_child_element(header)
body = ElementTree.Element('')
body.tag = '{%s}Body' % NAMESPACE
envelope.append(body)

View File

@@ -189,6 +189,17 @@ def response_factory(signature=False, encrypt=False, **kwargs):
pass
return args2dict(**kwargs)
def response_factory_x(signature=False, encrypt=False, **kwargs):
response = samlp.Response(id=sid(), version=VERSION, issue_instant=instant())
if signature:
kwargs["signature"] = sigver.pre_signature_part(kwargs["id"])
if encrypt:
pass
return response
def _attrval(val):
if isinstance(val, list) or isinstance(val, set):
attrval = [args2dict(v) for v in val]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -54,7 +54,7 @@ TEST_PGP_DATA = """<?xml version="1.0" encoding="utf-8"?>
TEST_X509_ISSUER_SERIAL = """<?xml version="1.0" encoding="utf-8"?>
<X509IssuerSerial xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509IssuerName>issuer name</X509IssuerName>
<X509IssuerNumber>1</X509IssuerNumber>
<X509SerialNumber>1</X509SerialNumber>
</X509IssuerSerial>
"""

View File

@@ -3,15 +3,18 @@
"service": {
"idp": {
"name" : "Rolands IdP",
"url": "http://localhost:8088/sso",
"endpoints" : {
"single_sign_on_service" : ["http://localhost:8088/sso"],
},
"policy": {
"default": {
"lifetime": {"minutes":15},
"attribute_restrictions": None, # means all I have
"name_form": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
"name_form": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
},
"urn:mace:example.com:saml:roland:sp": {
"lifetime": {"minutes": 5},
"nameid_format": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
# "attribute_restrictions":{
# "givenName": None,
# "surName": None,

View File

@@ -19,7 +19,7 @@
__author__ = 'tmatsuo@example.com (Takashi MATSUO)'
TEST_ENDPOINT = """<?xml version="1.0" encoding="utf-8"?>
<Endpoint xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
<EndpointType xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://www.example.com/endpoint"
ResponseLocation = "http://www.example.com/response"
@@ -72,7 +72,7 @@ TEST_ASSERTION_ID_REQUEST_SERVICE = """<?xml version="1.0" encoding="utf-8"?>
TEST_INDEXED_ENDPOINT = """<?xml version="1.0" encoding="utf-8"?>
<IndexedEndpoint xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
<IndexedEndpointType xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
index="1"
isDefault="false"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
@@ -115,22 +115,20 @@ TEST_ATTRIBUTE_PROFILE = """<?xml version="1.0" encoding="utf-8"?>
TEST_ORGANIZATION_NAME = """<?xml version="1.0" encoding="utf-8"?>
<OrganizationName xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
ns1:lang="en" xmlns:ns1="http:#www.w3.org/XML/1998/namespace">
SIOS Technology, Inc.
xml:lang="se">
Catalogix
</OrganizationName>
"""
TEST_ORGANIZATION_DISPLAY_NAME = """<?xml version="1.0" encoding="utf-8"?>
<OrganizationDisplayName
xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
ns1:lang="en" xmlns:ns1="http:#www.w3.org/XML/1998/namespace">
SIOS
</OrganizationDisplayName>
TEST_ORGANIZATION_DISPLAY_NAME = """<?xml version='1.0' encoding='UTF-8'?>
<ns0:OrganizationDisplayName xml:lang="se" xmlns:ns0="urn:oasis:names:tc:SAML:2.0:metadata">
Catalogix
</ns0:OrganizationDisplayName>
"""
TEST_ORGANIZATION_URL = """<?xml version="1.0" encoding="utf-8"?>
<OrganizationURL xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
ns1:lang="ja" xmlns:ns1="http:#www.w3.org/XML/1998/namespace">
xml:lang="no">
http://www.example.com/
</OrganizationURL>
"""
@@ -141,15 +139,14 @@ TEST_ORGANIZATION = """<?xml version="1.0" encoding="utf-8"?>
<hoge xmlns="http://hoge.example.com/">hogehoge</hoge>
</Extensions>
<OrganizationName
ns1:lang="en" xmlns:ns1="http:#www.w3.org/XML/1998/namespace">
SIOS Technology, Inc.
xml:lang="se">
Catalogix AB
</OrganizationName>
<OrganizationDisplayName ns1:lang="en"
xmlns:ns1="http:#www.w3.org/XML/1998/namespace">
SIOS
<OrganizationDisplayName xml:lang="no">
Catalogix AS
</OrganizationDisplayName>
<OrganizationURL
ns1:lang="ja" xmlns:ns1="http:#www.w3.org/XML/1998/namespace">
xml:lang="en">
http://www.example.com/
</OrganizationURL>
</Organization>
@@ -447,7 +444,7 @@ TEST_ROLE_DESCRIPTOR = """<?xml version="1.0" encoding="utf-8"?>
TEST_SSO_DESCRIPTOR = """<?xml version="1.0" encoding="utf-8"?>
<SSODescriptor
<SSODescriptorType
xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
ID="ID"
validUntil="2008-09-14T01:05:02Z"
@@ -642,7 +639,7 @@ TEST_SSO_DESCRIPTOR = """<?xml version="1.0" encoding="utf-8"?>
<NameIDFormat xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
</NameIDFormat>
</SSODescriptor>
</SSODescriptorType>
"""
@@ -888,15 +885,15 @@ TEST_REQUESTED_ATTRIBUTE = """<?xml version="1.0" encoding="utf-8"?>
TEST_SERVICE_NAME = """<?xml version="1.0" encoding="utf-8"?>
<ServiceName xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
ns1:lang="en" xmlns:ns1="http:#www.w3.org/XML/1998/namespace">
SIOS mail
xml:lang="en">
Catalogix Whois
</ServiceName>
"""
TEST_SERVICE_DESCRIPTION = """<?xml version="1.0" encoding="utf-8"?>
<ServiceDescription xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
ns1:lang="en" xmlns:ns1="http:#www.w3.org/XML/1998/namespace">
SIOS mail service
xml:lang="en">
Catalogix Whois Service
</ServiceDescription>
"""
@@ -1283,7 +1280,7 @@ TEST_ENTITY_DESCRIPTOR = """<?xml version="1.0" encoding="utf-8"?>
TEST_ENTITIES_DESCRIPTOR = """<?xml version="1.0" encoding="utf-8"?>
<EntitiesDescriptor
xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
name="name"
Name="name"
ID="ID"
validUntil="2008-09-14T01:05:02Z"
cacheDuration="10:00:00:00">

View File

@@ -3,7 +3,9 @@
"service": {
"idp": {
"name" : "Rolands restrictied IdP",
"url": "http://localhost:8089/sso",
"endpoints" : {
"single_sign_on_service" : ["http://localhost:8089/sso"],
},
"assertions": {
"default": {
"lifetime": {"minutes":15},
@@ -22,7 +24,9 @@
},
"aa": {
"name" : "Rolands restrictied AA",
"url": "http://localhost:8089/sso",
"endpoints" : {
"attribute_service" : ["http://localhost:8089/aa"],
},
"assertions": {
"default": {
"lifetime": {"minutes":15},

View File

@@ -96,7 +96,7 @@ TEST_AUTHN_REQUEST = """<?xml version="1.0" encoding="utf-8"?>
AssertionConsumerServiceIndex="1"
AssertionConsumerServiceURL="http://www.example.com/acs"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
AssertionConsumingServiceIndex="2"
AttributeConsumingServiceIndex="2"
ProviderName="provider name"
xmlns="urn:oasis:names:tc:SAML:2.0:protocol">
<Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">

View File

@@ -3,11 +3,14 @@
"service": {
"sp":{
"name" : "urn:mace:example.com:saml:roland:sp",
"url": "http://lingon.catalogix.se:8087/",
"description": "My own SP",
"endpoints":{
"assertion_consumer_service": ["http://lingon.catalogix.se:8087/"],
},
"required_attributes": ["surName", "givenName", "mail"],
"optional_attributes": ["title"],
"idp":{
"entity_id": ["urn:mace:example.com:saml:roland:idp"],
"urn:mace:example.com:saml:roland:idp":None,
},
}
},
@@ -27,4 +30,17 @@
"subject_data": "subject_data.db",
"accept_time_diff": 60,
"attribute_map_dir" : "attributemaps",
"organization": {
"name": ("AB Exempel", "se"),
"display_name": ("AB Exempel", "se"),
"url": "http://www.example.org",
},
"contact_person": [{
"given_name": "Roland",
"sur_name": "Hedberg",
"telephone_number": "+46 70 100 0000",
"email_address": ["tech@eample.com", "tech@example.org"],
"contact_type": "technical"
},
]
}

View File

@@ -1,541 +0,0 @@
#!/usr/bin/env python
from saml2 import create_class_from_xml_string, class_name, make_vals, md
from saml2.saml import NameID, Issuer, SubjectLocality, AuthnContextClassRef
from saml2.saml import SubjectConfirmationData, SubjectConfirmation
from saml2.saml import Attribute
import saml2
from py.test import raises
import saml2_data
try:
from xml.etree import cElementTree as ElementTree
except ImportError:
try:
import cElementTree as ElementTree
except ImportError:
from elementtree import ElementTree
ITEMS = {
NameID:["""<?xml version="1.0" encoding="utf-8"?>
<NameID xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
SPProvidedID="sp provided id">
roland@example.com
</NameID>
""", """<?xml version="1.0" encoding="utf-8"?>
<NameID xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
SPNameQualifier="https://foo.example.com/sp"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_1632879f09d08ea5ede2dc667cbed7e429ebc4335c</NameID>
""", """<?xml version="1.0" encoding="utf-8"?>
<NameID xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
NameQualifier="http://authentic.example.com/saml/metadata"
SPNameQualifier="http://auth.example.com/saml/metadata">test
</NameID>"""],
Issuer:"""<?xml version="1.0" encoding="utf-8"?>
<Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
http://www.example.com/test
</Issuer>
""",
SubjectLocality: """<?xml version="1.0" encoding="utf-8"?>
<SubjectLocality xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
Address="127.0.0.1" DNSName="localhost"/>
""",
SubjectConfirmationData:
"""<?xml version="1.0" encoding="utf-8"?>
<SubjectConfirmationData xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
InResponseTo="_1683146e27983964fbe7bf8f08961108d166a652e5"
NotOnOrAfter="2010-02-18T13:52:13.959Z"
NotBefore="2010-01-16T12:00:00Z"
Recipient="http://192.168.0.10/saml/sp" />""",
SubjectConfirmation:
"""<?xml version="1.0" encoding="utf-8"?>
<SubjectConfirmation xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><NameID
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
NameQualifier="http://authentic.example.com/saml/metadata">test@example.com
</NameID>
<SubjectConfirmationData
NotOnOrAfter="2010-02-17T17:02:38Z"
Recipient="http://auth.example.com/saml/proxySingleSignOnRedirect"
InResponseTo="_59B3A01B03334032C31E434C63F89E3E"/></SubjectConfirmation>"""
}
#def pytest_generate_tests(metafunc):
# if "target_class" in metafunc.funcargnames:
# for tcl,xml in ITEMS.items():
# metafunc.addcall(funcargs={"target_class":tcl,"xml_string":xml})
def _eq(l1,l2):
return set(l1) == set(l2)
def test_create_class_from_xml_string_nameid():
kl = create_class_from_xml_string(NameID, ITEMS[NameID][0])
assert kl != None
assert kl.format == "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
assert kl.sp_provided_id == "sp provided id"
assert kl.text.strip() == "roland@example.com"
assert _eq(kl.keyswv(), ['sp_provided_id', 'format', 'text'])
assert class_name(kl) == "urn:oasis:names:tc:SAML:2.0:assertion:NameID"
assert _eq(kl.keys(), ['sp_provided_id', 'sp_name_qualifier',
'name_qualifier', 'format', 'text'])
kl = create_class_from_xml_string(NameID, ITEMS[NameID][1])
assert kl != None
assert kl.format == "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
assert kl.sp_name_qualifier == "https://foo.example.com/sp"
assert kl.text.strip() == "_1632879f09d08ea5ede2dc667cbed7e429ebc4335c"
assert _eq(kl.keyswv(), ['sp_name_qualifier', 'format', 'text'])
assert class_name(kl) == "urn:oasis:names:tc:SAML:2.0:assertion:NameID"
kl = create_class_from_xml_string(NameID, ITEMS[NameID][2])
assert kl != None
assert kl.format == "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
assert kl.name_qualifier == "http://authentic.example.com/saml/metadata"
assert kl.sp_name_qualifier == "http://auth.example.com/saml/metadata"
assert kl.text.strip() == "test"
assert _eq(kl.keyswv(), ['sp_name_qualifier', 'format', 'name_qualifier',
'text'])
assert class_name(kl) == "urn:oasis:names:tc:SAML:2.0:assertion:NameID"
def test_create_class_from_xml_string_issuer():
kl = create_class_from_xml_string(Issuer, ITEMS[Issuer])
assert kl != None
assert kl.text.strip() == "http://www.example.com/test"
assert _eq(kl.keyswv(), ['text'])
assert class_name(kl) == "urn:oasis:names:tc:SAML:2.0:assertion:Issuer"
def test_create_class_from_xml_string_subject_locality():
kl = create_class_from_xml_string(SubjectLocality, ITEMS[SubjectLocality])
assert kl != None
assert _eq(kl.keyswv(), ['address', "dns_name"])
assert kl.address == "127.0.0.1"
assert kl.dns_name == "localhost"
assert class_name(kl) == "urn:oasis:names:tc:SAML:2.0:assertion:SubjectLocality"
def test_create_class_from_xml_string_subject_confirmation_data():
kl = create_class_from_xml_string(SubjectConfirmationData,
ITEMS[SubjectConfirmationData])
assert kl != None
assert _eq(kl.keyswv(), ['in_response_to', 'not_on_or_after',
'not_before', 'recipient'])
assert kl.in_response_to == "_1683146e27983964fbe7bf8f08961108d166a652e5"
assert kl.not_on_or_after == "2010-02-18T13:52:13.959Z"
assert kl.not_before == "2010-01-16T12:00:00Z"
assert kl.recipient == "http://192.168.0.10/saml/sp"
assert class_name(kl) == \
"urn:oasis:names:tc:SAML:2.0:assertion:SubjectConfirmationData"
def test_create_class_from_xml_string_subject_confirmation():
kl = create_class_from_xml_string(SubjectConfirmation,
ITEMS[SubjectConfirmation])
assert kl != None
assert _eq(kl.keyswv(), ['method', 'name_id',
'subject_confirmation_data'])
assert kl.method == "urn:oasis:names:tc:SAML:2.0:cm:bearer"
name_id = kl.name_id
assert _eq(name_id.keyswv(), ['format', 'name_qualifier', 'text'])
assert name_id.format == "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
assert name_id.name_qualifier == "http://authentic.example.com/saml/metadata"
assert name_id.text.strip() == "test@example.com"
subject_confirmation_data = kl.subject_confirmation_data
assert _eq(subject_confirmation_data.keyswv(), ['not_on_or_after',
'recipient', 'in_response_to'])
assert subject_confirmation_data.recipient == \
"http://auth.example.com/saml/proxySingleSignOnRedirect"
assert subject_confirmation_data.not_on_or_after == "2010-02-17T17:02:38Z"
assert subject_confirmation_data.in_response_to == \
"_59B3A01B03334032C31E434C63F89E3E"
assert class_name(kl) == \
"urn:oasis:names:tc:SAML:2.0:assertion:SubjectConfirmation"
def test_create_class_from_xml_string_wrong_class_spec():
kl = create_class_from_xml_string(SubjectConfirmationData,
ITEMS[SubjectConfirmation])
assert kl == None
def test_ee_1():
ee = saml2.extension_element_from_string(
"""<?xml version='1.0' encoding='UTF-8'?><foo>bar</foo>""")
assert ee != None
print ee.__dict__
assert ee.attributes == {}
assert ee.tag == "foo"
assert ee.namespace == None
assert ee.children == []
assert ee.text == "bar"
def test_ee_2():
ee = saml2.extension_element_from_string(
"""<?xml version='1.0' encoding='UTF-8'?><foo id="xyz">bar</foo>""")
assert ee != None
print ee.__dict__
assert ee.attributes == {"id":"xyz"}
assert ee.tag == "foo"
assert ee.namespace == None
assert ee.children == []
assert ee.text == "bar"
def test_ee_3():
ee = saml2.extension_element_from_string(
"""<?xml version='1.0' encoding='UTF-8'?>
<foo xmlns="urn:mace:example.com:saml:ns"
id="xyz">bar</foo>""")
assert ee != None
print ee.__dict__
assert ee.attributes == {"id":"xyz"}
assert ee.tag == "foo"
assert ee.namespace == "urn:mace:example.com:saml:ns"
assert ee.children == []
assert ee.text == "bar"
def test_ee_4():
ee = saml2.extension_element_from_string(
"""<?xml version='1.0' encoding='UTF-8'?>
<foo xmlns="urn:mace:example.com:saml:ns">
<id>xyz</id><bar>tre</bar></foo>""")
assert ee != None
print ee.__dict__
assert ee.attributes == {}
assert ee.tag == "foo"
assert ee.namespace == "urn:mace:example.com:saml:ns"
assert len(ee.children) == 2
assert ee.text.strip() == ""
id = ee.find_children("id", "urn:mace:example.com:saml:namespace")
assert id == []
ids = ee.find_children("id", "urn:mace:example.com:saml:ns")
assert ids != []
id = ids[0]
print id.__dict__
assert id.attributes == {}
assert id.tag == "id"
assert id.namespace == "urn:mace:example.com:saml:ns"
assert id.children == []
assert id.text.strip() == "xyz"
def test_ee_5():
ee = saml2.extension_element_from_string(
"""<?xml version='1.0' encoding='UTF-8'?>
<foo xmlns="urn:mace:example.com:saml:ns">bar</foo>""")
ce = saml2.extension_element_from_string(
"""<?xml version='1.0' encoding='UTF-8'?>
<educause xmlns="urn:mace:example.com:saml:cu">rev</educause>""")
ee.children.append(ce)
assert ee != None
print ee.__dict__
assert ee.attributes == {}
assert ee.tag == "foo"
assert ee.namespace == "urn:mace:example.com:saml:ns"
assert len(ee.children) == 1
assert ee.text.strip() == "bar"
c = ee.children[0]
print c.__dict__
child = ee.find_children(namespace="urn:mace:example.com:saml:cu")
assert len(child) == 1
child = ee.find_children(namespace="urn:mace:example.com:saml:ns")
assert len(child) == 0
child = ee.find_children("educause","urn:mace:example.com:saml:cu")
assert len(child) == 1
child = ee.find_children("edugain","urn:mace:example.com:saml:cu")
assert len(child) == 0
print ee.to_string()
def test_ee_6():
ee = saml2.extension_element_from_string(
"""<?xml version='1.0' encoding='UTF-8'?>
<foo xmlns="urn:mace:example.com:saml:ns">bar</foo>""")
ce = saml2.extension_element_from_string(
"""<?xml version='1.0' encoding='UTF-8'?>
<educause xmlns="urn:mace:example.com:saml:cu">rev</educause>""")
et = ee.transfer_to_element_tree()
ce.become_child_element_of(et)
pee = saml2._extension_element_from_element_tree(et)
assert pee != None
print pee.__dict__
assert pee.attributes == {}
assert pee.tag == "foo"
assert pee.namespace == "urn:mace:example.com:saml:ns"
assert len(pee.children) == 1
assert pee.text.strip() == "bar"
c = pee.children[0]
print c.__dict__
child = pee.find_children(namespace="urn:mace:example.com:saml:cu")
assert len(child) == 1
child = pee.find_children(namespace="urn:mace:example.com:saml:ns")
assert len(child) == 0
child = pee.find_children("educause","urn:mace:example.com:saml:cu")
assert len(child) == 1
child = pee.find_children("edugain","urn:mace:example.com:saml:cu")
assert len(child) == 0
print pee.to_string()
NAMEID_WITH_ATTRIBUTE_EXTENSION = """<?xml version="1.0" encoding="utf-8"?>
<NameID xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:local="urn:mace:example.com:saml:assertion"
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
SPProvidedID="sp provided id"
local:Foo="BAR">
roland@example.com
</NameID>
"""
def test_nameid_with_extension():
kl = create_class_from_xml_string(NameID, NAMEID_WITH_ATTRIBUTE_EXTENSION)
assert kl != None
print kl.__dict__
assert kl.format == "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
assert kl.sp_provided_id == "sp provided id"
assert kl.text.strip() == "roland@example.com"
assert _eq(kl.keyswv(), ['sp_provided_id', 'format',
'extension_attributes', 'text'])
assert class_name(kl) == "urn:oasis:names:tc:SAML:2.0:assertion:NameID"
assert _eq(kl.keys(), ['sp_provided_id', 'sp_name_qualifier',
'name_qualifier', 'format', 'text'])
assert kl.extension_attributes == {
'{urn:mace:example.com:saml:assertion}Foo': 'BAR'}
SUBJECT_CONFIRMATION_WITH_MEMBER_EXTENSION = """<?xml version="1.0" encoding="utf-8"?>
<SubjectConfirmation xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<NameID
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
NameQualifier="http://authentic.example.com/saml/metadata">test@example.com
</NameID>
<SubjectConfirmationData
NotOnOrAfter="2010-02-17T17:02:38Z"
Recipient="http://auth.example.com/saml/proxySingleSignOnRedirect"
InResponseTo="_59B3A01B03334032C31E434C63F89E3E"/>
<local:Trustlevel xmlns:local="urn:mace:example.com:saml:assertion">
Excellent
</local:Trustlevel>
</SubjectConfirmation>"""
def test_subject_confirmation_with_extension():
kl = create_class_from_xml_string(SubjectConfirmation,
SUBJECT_CONFIRMATION_WITH_MEMBER_EXTENSION)
assert kl != None
print kl.__dict__
assert kl.extension_attributes == {}
assert kl.method == "urn:oasis:names:tc:SAML:2.0:cm:bearer"
name_id = kl.name_id
assert _eq(name_id.keyswv(), ['format', 'name_qualifier', 'text'])
assert name_id.format == "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
assert name_id.name_qualifier == "http://authentic.example.com/saml/metadata"
assert name_id.text.strip() == "test@example.com"
subject_confirmation_data = kl.subject_confirmation_data
assert _eq(subject_confirmation_data.keyswv(), ['not_on_or_after',
'recipient', 'in_response_to'])
assert subject_confirmation_data.recipient == \
"http://auth.example.com/saml/proxySingleSignOnRedirect"
assert subject_confirmation_data.not_on_or_after == "2010-02-17T17:02:38Z"
assert subject_confirmation_data.in_response_to == \
"_59B3A01B03334032C31E434C63F89E3E"
assert len(kl.extension_elements) == 1
ee = kl.extension_elements[0]
assert ee.tag == "Trustlevel"
assert ee.namespace == "urn:mace:example.com:saml:assertion"
assert ee.text.strip() == "Excellent"
def test_to_fro_string_1():
kl = create_class_from_xml_string(SubjectConfirmation,
SUBJECT_CONFIRMATION_WITH_MEMBER_EXTENSION)
str = kl.to_string()
cpy = create_class_from_xml_string(SubjectConfirmation, str)
print kl.__dict__
print cpy.__dict__
assert kl.text.strip() == cpy.text.strip()
assert _eq(kl.keyswv(), cpy.keyswv())
assert len(kl.extension_elements) == len(cpy.extension_elements)
klee = kl.extension_elements[0]
cpyee = cpy.extension_elements[0]
assert klee.text.strip() == cpyee.text.strip()
assert klee.tag == cpyee.tag
assert klee.namespace == cpyee.namespace
def test_make_vals_str():
kl = make_vals("Jeter",md.GivenName, part=True)
assert isinstance(kl, md.GivenName)
assert kl.text == "Jeter"
def test_make_vals_int():
kl = make_vals(1024,md.KeySize, part=True)
assert isinstance(kl, md.KeySize)
assert kl.text == "1024"
def test_exception_make_vals_int_not_part():
raises(TypeError, "make_vals(1024,md.KeySize)")
raises(TypeError, "make_vals(1024,md.KeySize,md.EncryptionMethod())")
raises(AttributeError, "make_vals(1024,md.KeySize,prop='key_size')")
def test_make_vals_list_of_ints():
em = md.EncryptionMethod()
make_vals([1024,2048], md.KeySize, em, "key_size")
assert len(em.key_size) == 2
def test_make_vals_list_of_strs():
cp = md.ContactPerson()
make_vals(["Derek","Sanderson"], md.GivenName, cp, "given_name")
assert len(cp.given_name) == 2
assert _eq([i.text for i in cp.given_name],["Sanderson","Derek"])
def test_exception_make_vals_value_error():
raises(ValueError, "make_vals((1024,'xyz'), md.KeySize, part=True)")
def test_attribute_element_to_extension_element():
attr = create_class_from_xml_string(Attribute, saml2_data.TEST_ATTRIBUTE)
ee = saml2.element_to_extension_element(attr)
print ee.__dict__
assert ee.tag == "Attribute"
assert ee.namespace == 'urn:oasis:names:tc:SAML:2.0:assertion'
assert _eq(ee.attributes.keys(),['FriendlyName', 'Name', 'NameFormat'])
assert ee.attributes["FriendlyName"] == 'test attribute'
assert ee.attributes["Name"] == "testAttribute"
assert ee.attributes["NameFormat"] == \
'urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified'
assert len(ee.children) == 2
for child in ee.children:
# children are also extension element instances
assert child.namespace == 'urn:oasis:names:tc:SAML:2.0:assertion'
assert child.tag == "AttributeValue"
def test_ee_7():
ee = saml2.extension_element_from_string(
"""<?xml version='1.0' encoding='UTF-8'?>
<ExternalEntityAttributeAuthority
xmlns="urn:oasis:names:tc:SAML:metadata:dynamicsaml">
<AssertingEntity>
<NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">
http://federationX.org
</NameID>
</AssertingEntity>
<RetrievalEndpoint>
https://federationX.org/?ID=a87s76a5765da76576a57as
</RetrievalEndpoint>
</ExternalEntityAttributeAuthority>
""")
print ee.__dict__
assert len(ee.children) == 2
for child in ee.children:
assert child.namespace == "urn:oasis:names:tc:SAML:metadata:dynamicsaml"
assert _eq(["AssertingEntity","RetrievalEndpoint"],
[c.tag for c in ee.children])
aes = [c for c in ee.children if c.tag == "AssertingEntity"]
assert len(aes) == 1
assert len(aes[0].children) == 1
assert _eq(aes[0].attributes.keys(),[])
nid = aes[0].children[0]
assert nid.tag == "NameID"
assert nid.namespace == "urn:oasis:names:tc:SAML:metadata:dynamicsaml"
assert len(nid.children) == 0
assert _eq(nid.attributes.keys(),["Format"])
assert nid.text.strip() == "http://federationX.org"
def test_extension_element_loadd():
ava = {'attributes': {},
'tag': 'ExternalEntityAttributeAuthority',
'namespace': 'urn:oasis:names:tc:SAML:metadata:dynamicsaml',
'children': [{
"tag": "AssertingEntity",
"namespace": "urn:oasis:names:tc:SAML:metadata:dynamicsaml",
"children": [{
"tag":"NameID",
"namespace": "urn:oasis:names:tc:SAML:metadata:dynamicsaml",
"text": "http://federationX.org",
"attributes":{
"Format":"urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
},
}]
}, {
"tag":"RetrievalEndpoint",
"namespace": "urn:oasis:names:tc:SAML:metadata:dynamicsaml",
"text":"https://federationX.org/?ID=a87s76a5765da76576a57as",
}],
}
ee = saml2.ExtensionElement(ava["tag"]).loadd(ava)
print ee.__dict__
assert len(ee.children) == 2
for child in ee.children:
assert child.namespace == "urn:oasis:names:tc:SAML:metadata:dynamicsaml"
assert _eq(["AssertingEntity","RetrievalEndpoint"],
[c.tag for c in ee.children])
aes = [c for c in ee.children if c.tag == "AssertingEntity"]
assert len(aes) == 1
assert len(aes[0].children) == 1
assert _eq(aes[0].attributes.keys(),[])
nid = aes[0].children[0]
assert nid.tag == "NameID"
assert nid.namespace == "urn:oasis:names:tc:SAML:metadata:dynamicsaml"
assert len(nid.children) == 0
assert _eq(nid.attributes.keys(),["Format"])
assert nid.text.strip() == "http://federationX.org"
def test_extensions_loadd():
ava = {"extension_elements":[{'attributes': {},
'tag': 'ExternalEntityAttributeAuthority',
'namespace': 'urn:oasis:names:tc:SAML:metadata:dynamicsaml',
'children': [{
"tag": "AssertingEntity",
"namespace": "urn:oasis:names:tc:SAML:metadata:dynamicsaml",
"children": [{
"tag":"NameID",
"namespace": "urn:oasis:names:tc:SAML:metadata:dynamicsaml",
"text": "http://federationX.org",
"attributes":{
"Format":"urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
},
}]
}, {
"tag":"RetrievalEndpoint",
"namespace": "urn:oasis:names:tc:SAML:metadata:dynamicsaml",
"text":"https://federationX.org/?ID=a87s76a5765da76576a57as",
}],
}],
"extension_attributes": {
"foo":"bar",
}
}
extension = saml2.SamlBase()
extension.loadd(ava)
print extension.__dict__
assert len(extension.extension_elements) == 1
ee = extension.extension_elements[0]
assert len(ee.children) == 2
for child in ee.children:
assert child.namespace == "urn:oasis:names:tc:SAML:metadata:dynamicsaml"
assert _eq(["AssertingEntity","RetrievalEndpoint"],
[c.tag for c in ee.children])
aes = [c for c in ee.children if c.tag == "AssertingEntity"]
assert len(aes) == 1
assert len(aes[0].children) == 1
assert _eq(aes[0].attributes.keys(),[])
nid = aes[0].children[0]
assert nid.tag == "NameID"
assert nid.namespace == "urn:oasis:names:tc:SAML:metadata:dynamicsaml"
assert len(nid.children) == 0
assert _eq(nid.attributes.keys(),["Format"])
assert nid.text.strip() == "http://federationX.org"
assert extension.extension_attributes.keys() == ["foo"]
assert extension.extension_attributes["foo"] == "bar"

View File

@@ -1,989 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2010 Umeå University.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
"""Tests for saml2.saml"""
__author__ = 'roland.hedberg@adm.umu.se (Roland Hedberg)'
try:
from xml.etree import ElementTree
except ImportError:
from elementtree import ElementTree
import saml2
from saml2 import saml
import saml2_data, ds_data
import xmldsig as ds
from py.test import raises
class TestNameID:
def setup_class(self):
self.name_id = saml.NameID()
def testEmptyExtensionsList(self):
"""Test if NameID has empty extensions list"""
assert isinstance(self.name_id.extension_elements, list)
assert len(self.name_id.extension_elements) == 0
def testFormatAttribute(self):
"""Test for Format attribute accessors"""
self.name_id.format = saml.NAMEID_FORMAT_EMAILADDRESS
assert self.name_id.format == saml.NAMEID_FORMAT_EMAILADDRESS
assert len(self.name_id.extension_elements) == 0
new_name_id = saml.name_id_from_string(self.name_id.to_string())
assert len(new_name_id.extension_elements) == 0
self.name_id.extension_elements.append(saml2.ExtensionElement(
'foo', text='bar'))
assert len(self.name_id.extension_elements) == 1
assert self.name_id.format == saml.NAMEID_FORMAT_EMAILADDRESS
def testNameIDText(self):
"""Test text value of NameID element"""
self.name_id.text = "tmatsuo@example.com"
assert self.name_id.text == "tmatsuo@example.com"
def testSPProvidedID(self):
"""Test for SPProvidedID attribute accessors"""
self.name_id.sp_provided_id = "provided id"
assert self.name_id.sp_provided_id == "provided id"
def testEmptyNameIDToAndFromStringMatch(self):
"""Test name_id_from_string() with empty NameID"""
string_from_name_id = self.name_id.to_string()
new_name_id = saml.name_id_from_string(string_from_name_id)
string_from_new_name_id = new_name_id.to_string()
assert string_from_name_id == string_from_new_name_id
def testNameIDToAndFromStringMatch(self):
"""Test name_id_from_string() with data"""
self.name_id.format = saml.NAMEID_FORMAT_EMAILADDRESS
self.name_id.text = "tmatsuo@example.com"
self.name_id.name_qualifier = "name_qualifier"
self.name_id.sp_name_qualifier = "sp_name_qualifier"
string_from_name_id = self.name_id.to_string()
new_name_id = saml.name_id_from_string(string_from_name_id)
assert new_name_id.name_qualifier == "name_qualifier"
assert new_name_id.sp_name_qualifier == "sp_name_qualifier"
string_from_new_name_id = new_name_id.to_string()
assert string_from_name_id == string_from_new_name_id
def testExtensionAttributes(self):
"""Test extension attributes"""
self.name_id.extension_attributes['hoge'] = 'fuga'
self.name_id.extension_attributes['moge'] = 'muga'
assert self.name_id.extension_attributes['hoge'] == 'fuga'
assert self.name_id.extension_attributes['moge'] == 'muga'
new_name_id = saml.name_id_from_string(self.name_id.to_string())
assert new_name_id.extension_attributes['hoge'] == 'fuga'
assert new_name_id.extension_attributes['moge'] == 'muga'
def testname_id_from_string(self):
"""Test name_id_from_string() using test data"""
name_id = saml.name_id_from_string(saml2_data.TEST_NAME_ID)
assert name_id.format == saml.NAMEID_FORMAT_EMAILADDRESS
assert name_id.text.strip() == "tmatsuo@example.com"
assert name_id.sp_provided_id == "sp provided id"
class TestIssuer:
def setup_class(self):
self.issuer = saml.Issuer()
def testIssuerToAndFromString(self):
"""Test issuer_from_string()"""
self.issuer.text = "http://www.example.com/test"
self.issuer.name_qualifier = "name_qualifier"
self.issuer.sp_name_qualifier = "sp_name_qualifier"
new_issuer = saml.issuer_from_string(self.issuer.to_string())
assert self.issuer.text == new_issuer.text
assert self.issuer.name_qualifier == new_issuer.name_qualifier
assert self.issuer.sp_name_qualifier == new_issuer.sp_name_qualifier
assert self.issuer.extension_elements == new_issuer.extension_elements
def testUsingTestData(self):
"""Test issuer_from_string() using test data"""
issuer = saml.issuer_from_string(saml2_data.TEST_ISSUER)
assert issuer.text.strip() == "http://www.example.com/test"
new_issuer = saml.issuer_from_string(issuer.to_string())
assert issuer.text == new_issuer.text
assert issuer.extension_elements == new_issuer.extension_elements
class TestSubjectLocality:
def setup_class(self):
self.subject_locality = saml.SubjectLocality()
def testAccessors(self):
"""Test for SubjectLocality accessors"""
self.subject_locality.address = "127.0.0.1"
self.subject_locality.dns_name = "localhost"
assert self.subject_locality.address == "127.0.0.1"
assert self.subject_locality.dns_name == "localhost"
new_subject_locality = saml.subject_locality_from_string(
self.subject_locality.to_string())
assert new_subject_locality.address == "127.0.0.1"
assert new_subject_locality.dns_name == "localhost"
def testUsingTestData(self):
"""Test SubjectLocalityFromString() using test data"""
subject_locality = saml.subject_locality_from_string(
saml2_data.TEST_SUBJECT_LOCALITY)
assert subject_locality.address == "127.0.0.1"
assert subject_locality.dns_name == "localhost"
new_subject_locality = saml.subject_locality_from_string(
subject_locality.to_string())
assert new_subject_locality.address == "127.0.0.1"
assert new_subject_locality.dns_name == "localhost"
assert subject_locality.to_string() == new_subject_locality.to_string()
class TestAuthnContextClassRef:
def setup_class(self):
self.authn_context_class_ref = saml.AuthnContextClassRef()
self.text = "http://www.example.com/authnContextClassRef"
def testAccessors(self):
"""Test for AuthnContextClassRef accessors"""
self.authn_context_class_ref.text = self.text
assert self.authn_context_class_ref.text == self.text
new_authn_context_class_ref = saml.authn_context_class_ref_from_string(
self.authn_context_class_ref.to_string())
assert new_authn_context_class_ref.text == self.text
assert self.authn_context_class_ref.to_string() == \
new_authn_context_class_ref.to_string()
def testUsingTestData(self):
"""Test authn_context_class_ref_from_string() using test data"""
authn_context_class_ref = saml.authn_context_class_ref_from_string(
saml2_data.TEST_AUTHN_CONTEXT_CLASS_REF)
assert authn_context_class_ref.text.strip() == self.text
class TestAuthnContextDeclRef:
def setup_class(self):
self.authn_context_decl_ref = saml.AuthnContextDeclRef()
self.ref = "http://www.example.com/authnContextDeclRef"
def testAccessors(self):
"""Test for AuthnContextDeclRef accessors"""
self.authn_context_decl_ref.text = self.ref
assert self.authn_context_decl_ref.text == self.ref
new_authn_context_decl_ref = saml.authn_context_decl_ref_from_string(
self.authn_context_decl_ref.to_string())
assert new_authn_context_decl_ref.text == self.ref
assert self.authn_context_decl_ref.to_string() == \
new_authn_context_decl_ref.to_string()
def testUsingTestData(self):
"""Test authn_context_decl_ref_from_string() using test data"""
authn_context_decl_ref = saml.authn_context_decl_ref_from_string(
saml2_data.TEST_AUTHN_CONTEXT_DECL_REF)
assert authn_context_decl_ref.text.strip() == self.ref
class TestAuthnContextDecl:
def setup_class(self):
self.authn_context_decl = saml.AuthnContextDecl()
self.text = "http://www.example.com/authnContextDecl"
def testAccessors(self):
"""Test for AuthnContextDecl accessors"""
self.authn_context_decl.text = self.text
assert self.authn_context_decl.text == self.text
new_authn_context_decl = saml.authn_context_decl_from_string(
self.authn_context_decl.to_string())
assert new_authn_context_decl.text == self.text
assert self.authn_context_decl.to_string() == \
new_authn_context_decl.to_string()
def testUsingTestData(self):
"""Test authn_context_decl_from_string() using test data"""
authn_context_decl = saml.authn_context_decl_from_string(
saml2_data.TEST_AUTHN_CONTEXT_DECL)
assert authn_context_decl.text.strip() == self.text
class TestAuthenticatingAuthority:
def setup_class(self):
self.authenticating_authority = saml.AuthenticatingAuthority()
self.text = "http://www.example.com/authenticatingAuthority"
def testAccessors(self):
"""Test for AuthenticatingAuthority accessors"""
self.authenticating_authority.text = self.text
assert self.authenticating_authority.text == self.text
new_authenticating_authority = saml.authenticating_authority_from_string(
self.authenticating_authority.to_string())
assert new_authenticating_authority.text == self.text
assert self.authenticating_authority.to_string() == \
new_authenticating_authority.to_string()
def testUsingTestData(self):
"""Test authenticating_authority_from_string() using test data"""
authenticating_authority = saml.authenticating_authority_from_string(
saml2_data.TEST_AUTHENTICATING_AUTHORITY)
assert authenticating_authority.text.strip() == self.text
class TestAuthnContext:
def setup_class(self):
self.authn_context = saml.AuthnContext()
def testAccessors(self):
"""Test for AuthnContext accessors"""
self.authn_context.authn_context_class_ref = \
saml.authn_context_class_ref_from_string(
saml2_data.TEST_AUTHN_CONTEXT_CLASS_REF)
self.authn_context.authn_context_decl_ref = \
saml.authn_context_decl_ref_from_string(
saml2_data.TEST_AUTHN_CONTEXT_DECL_REF)
self.authn_context.authn_context_decl = \
saml.authn_context_decl_from_string(
saml2_data.TEST_AUTHN_CONTEXT_DECL)
self.authn_context.authenticating_authority.append(
saml.authenticating_authority_from_string(
saml2_data.TEST_AUTHENTICATING_AUTHORITY))
assert self.authn_context.authn_context_class_ref.text.strip() == \
"http://www.example.com/authnContextClassRef"
assert self.authn_context.authn_context_decl_ref.text.strip() == \
"http://www.example.com/authnContextDeclRef"
assert self.authn_context.authn_context_decl.text.strip() == \
"http://www.example.com/authnContextDecl"
assert self.authn_context.authenticating_authority[0].text.strip() == \
"http://www.example.com/authenticatingAuthority"
new_authn_context = saml.authn_context_from_string(
self.authn_context.to_string())
assert self.authn_context.to_string() == new_authn_context.to_string()
def testUsingTestData(self):
"""Test authn_context_from_string() using test data"""
authn_context = saml.authn_context_from_string(saml2_data.TEST_AUTHN_CONTEXT)
assert authn_context.authn_context_class_ref.text.strip() == \
saml.URN_PASSWORD
class TestAuthnStatement:
def setup_class(self):
self.authn_statem = saml.AuthnStatement()
def testAccessors(self):
"""Test for AuthnStatement accessors"""
self.authn_statem.authn_instant = "2007-08-31T01:05:02Z"
self.authn_statem.session_not_on_or_after = "2007-09-14T01:05:02Z"
self.authn_statem.session_index = "sessionindex"
self.authn_statem.authn_context = saml.AuthnContext()
self.authn_statem.authn_context.authn_context_class_ref = \
saml.authn_context_class_ref_from_string(
saml2_data.TEST_AUTHN_CONTEXT_CLASS_REF)
self.authn_statem.authn_context.authn_context_decl_ref = \
saml.authn_context_decl_ref_from_string(
saml2_data.TEST_AUTHN_CONTEXT_DECL_REF)
self.authn_statem.authn_context.authn_context_decl = \
saml.authn_context_decl_from_string(
saml2_data.TEST_AUTHN_CONTEXT_DECL)
self.authn_statem.authn_context.authenticating_authority.append(
saml.authenticating_authority_from_string(
saml2_data.TEST_AUTHENTICATING_AUTHORITY))
new_as = saml.authn_statement_from_string(self.authn_statem.to_string())
assert new_as.authn_instant == "2007-08-31T01:05:02Z"
assert new_as.session_index == "sessionindex"
assert new_as.session_not_on_or_after == "2007-09-14T01:05:02Z"
assert new_as.authn_context.authn_context_class_ref.text.strip() == \
"http://www.example.com/authnContextClassRef"
assert new_as.authn_context.authn_context_decl_ref.text.strip() == \
"http://www.example.com/authnContextDeclRef"
assert new_as.authn_context.authn_context_decl.text.strip() == \
"http://www.example.com/authnContextDecl"
assert new_as.authn_context.authenticating_authority[0].text.strip() \
== "http://www.example.com/authenticatingAuthority"
assert self.authn_statem.to_string() == new_as.to_string()
def testUsingTestData(self):
"""Test authn_statement_from_string() using test data"""
authn_statem = saml.authn_statement_from_string(saml2_data.TEST_AUTHN_STATEMENT)
assert authn_statem.authn_instant == "2007-08-31T01:05:02Z"
assert authn_statem.session_not_on_or_after == "2007-09-14T01:05:02Z"
assert authn_statem.authn_context.authn_context_class_ref.text.strip() == \
saml.URN_PASSWORD
class TestAttributeValue:
def setup_class(self):
self.attribute_value = saml.AttributeValue()
self.text = "value for test attribute"
def testAccessors(self):
"""Test for AttributeValue accessors"""
self.attribute_value.text = self.text
new_attribute_value = saml.attribute_value_from_string(
self.attribute_value.to_string())
assert new_attribute_value.text.strip() == self.text
def testUsingTestData(self):
"""Test attribute_value_from_string() using test data"""
attribute_value = saml.attribute_value_from_string(
saml2_data.TEST_ATTRIBUTE_VALUE)
assert attribute_value.text.strip() == self.text
BASIC_STR_AV = """<?xml version="1.0" encoding="utf-8"?>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
Name="FirstName">
<AttributeValue xsi:type="xs:string">By-Tor</AttributeValue>
</Attribute>"""
BASIC_INT_AV = """<?xml version="1.0" encoding="utf-8"?>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
Name="age">
<AttributeValue xsi:type="xs:int">23</AttributeValue>
</Attribute>"""
BASIC_NOT_INT_AV = """<?xml version="1.0" encoding="utf-8"?>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
Name="age">
<AttributeValue xsi:type="xs:int">foo</AttributeValue>
</Attribute>"""
BASIC_BOOLEAN_TRUE_AV = """<?xml version="1.0" encoding="utf-8"?>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
Name="on-off">
<AttributeValue xsi:type="xs:boolean">true</AttributeValue>
</Attribute>"""
BASIC_BOOLEAN_FALSE_AV = """<?xml version="1.0" encoding="utf-8"?>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
Name="on-off">
<AttributeValue xsi:type="xs:boolean">false</AttributeValue>
</Attribute>"""
BASIC_BASE64_AV = """<?xml version="1.0" encoding="utf-8"?>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
Name="FirstName">
<AttributeValue
xsi:type="xs:base64Binary">VU5JTkVUVA==</AttributeValue>
</Attribute>"""
X500_AV = """<?xml version="1.0" encoding="utf-8"?>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:2.5.4.42" FriendlyName="givenName">
<AttributeValue xsi:type="xs:string" x500:Encoding="LDAP">Steven
</AttributeValue>
</Attribute>"""
UUID_AV = """<?xml version="1.0" encoding="utf-8"?>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:uuid:6c9d0ec8-dd2d-11cc-abdd-080009353559"
FriendlyName="pre_auth_req">
<AttributeValue xsi:type="xs:integer">1</AttributeValue>
</Attribute>"""
class TestAttribute:
def setup_class(self):
self.attribute = saml.Attribute()
self.text = ["value of test attribute",
"value1 of test attribute",
"value2 of test attribute"]
def testAccessors(self):
"""Test for Attribute accessors"""
self.attribute.name = "testAttribute"
self.attribute.name_format = saml.NAME_FORMAT_URI
self.attribute.friendly_name = "test attribute"
self.attribute.attribute_value.append(saml.AttributeValue())
self.attribute.attribute_value[0].text = self.text[0]
new_attribute = saml.attribute_from_string(self.attribute.to_string())
assert new_attribute.name == "testAttribute"
assert new_attribute.name_format == saml.NAME_FORMAT_URI
assert new_attribute.friendly_name == "test attribute"
assert new_attribute.attribute_value[0].text.strip() == self.text[0]
def testUsingTestData(self):
"""Test attribute_from_string() using test data"""
attribute = saml.attribute_from_string(saml2_data.TEST_ATTRIBUTE)
assert attribute.name == "testAttribute"
assert attribute.name_format == saml.NAME_FORMAT_UNSPECIFIED
assert attribute.friendly_name == "test attribute"
assert attribute.attribute_value[0].text.strip() == self.text[1]
assert attribute.attribute_value[1].text.strip() == self.text[2]
# test again
attribute = saml.attribute_from_string(attribute.to_string())
assert attribute.name == "testAttribute"
assert attribute.name_format == saml.NAME_FORMAT_UNSPECIFIED
assert attribute.friendly_name == "test attribute"
assert attribute.attribute_value[0].text.strip() == self.text[1]
assert attribute.attribute_value[1].text.strip() == self.text[2]
def test_basic_str(self):
attribute = saml.attribute_from_string(BASIC_STR_AV)
print attribute
assert attribute.attribute_value[0].text.strip() == "By-Tor"
def test_basic_int(self):
attribute = saml.attribute_from_string(BASIC_INT_AV)
print attribute
assert attribute.attribute_value[0].text == "23"
def test_basic_not_int(self):
raises(ValueError, "saml.attribute_from_string(BASIC_NOT_INT_AV)")
def test_basic_base64(self):
attribute = saml.attribute_from_string(BASIC_BASE64_AV)
print attribute
assert attribute.attribute_value[0].text == "VU5JTkVUVA=="
assert attribute.attribute_value[0].type == "xs:base64Binary"
def test_basic_boolean_true(self):
attribute = saml.attribute_from_string(BASIC_BOOLEAN_TRUE_AV)
print attribute
assert attribute.attribute_value[0].text.lower() == "true"
def test_basic_boolean_false(self):
attribute = saml.attribute_from_string(BASIC_BOOLEAN_FALSE_AV)
print attribute
assert attribute.attribute_value[0].text.lower() == "false"
class TestAttributeStatement:
def setup_class(self):
self.attr_statem = saml.AttributeStatement()
self.text = ["value of test attribute",
"value1 of test attribute",
"value2 of test attribute",
"value1 of test attribute2",
"value2 of test attribute2",]
def testAccessors(self):
"""Test for Attribute accessors"""
self.attr_statem.attribute.append(saml.Attribute())
self.attr_statem.attribute.append(saml.Attribute())
self.attr_statem.attribute[0].name = "testAttribute"
self.attr_statem.attribute[0].name_format = saml.NAME_FORMAT_URI
self.attr_statem.attribute[0].friendly_name = "test attribute"
self.attr_statem.attribute[0].attribute_value.append(saml.AttributeValue())
self.attr_statem.attribute[0].attribute_value[0].text = self.text[0]
self.attr_statem.attribute[1].name = "testAttribute2"
self.attr_statem.attribute[1].name_format = saml.NAME_FORMAT_UNSPECIFIED
self.attr_statem.attribute[1].friendly_name = self.text[2]
self.attr_statem.attribute[1].attribute_value.append(saml.AttributeValue())
self.attr_statem.attribute[1].attribute_value[0].text = self.text[2]
new_as = saml.attribute_statement_from_string(self.attr_statem.to_string())
assert new_as.attribute[0].name == "testAttribute"
assert new_as.attribute[0].name_format == saml.NAME_FORMAT_URI
assert new_as.attribute[0].friendly_name == "test attribute"
assert new_as.attribute[0].attribute_value[0].text.strip() == self.text[0]
assert new_as.attribute[1].name == "testAttribute2"
assert new_as.attribute[1].name_format == saml.NAME_FORMAT_UNSPECIFIED
assert new_as.attribute[1].friendly_name == "value2 of test attribute"
assert new_as.attribute[1].attribute_value[0].text.strip() == self.text[2]
def testUsingTestData(self):
"""Test attribute_statement_from_string() using test data"""
attr_statem = saml.attribute_statement_from_string( \
saml2_data.TEST_ATTRIBUTE_STATEMENT)
assert attr_statem.attribute[0].name == "testAttribute"
assert attr_statem.attribute[0].name_format == saml.NAME_FORMAT_UNSPECIFIED
assert attr_statem.attribute[0].friendly_name == "test attribute"
assert attr_statem.attribute[0].attribute_value[0].text.strip() == self.text[1]
assert attr_statem.attribute[0].attribute_value[1].text.strip() == self.text[2]
assert attr_statem.attribute[1].name == "http://www.example.com/testAttribute2"
assert attr_statem.attribute[1].name_format == saml.NAME_FORMAT_URI
assert attr_statem.attribute[1].friendly_name == "test attribute2"
assert attr_statem.attribute[1].attribute_value[0].text.strip() == self.text[3]
assert attr_statem.attribute[1].attribute_value[1].text.strip() == self.text[4]
# test again
attr_statem2 = saml.attribute_statement_from_string(attr_statem.to_string())
assert attr_statem2.attribute[0].name == "testAttribute"
assert attr_statem2.attribute[0].name_format == saml.NAME_FORMAT_UNSPECIFIED
assert attr_statem2.attribute[0].friendly_name == "test attribute"
assert attr_statem2.attribute[0].attribute_value[0].text.strip() == self.text[1]
assert attr_statem2.attribute[0].attribute_value[1].text.strip() == self.text[2]
assert attr_statem2.attribute[1].name == "http://www.example.com/testAttribute2"
assert attr_statem2.attribute[1].name_format == saml.NAME_FORMAT_URI
assert attr_statem2.attribute[1].friendly_name == "test attribute2"
assert attr_statem2.attribute[1].attribute_value[0].text.strip() == self.text[3]
assert attr_statem2.attribute[1].attribute_value[1].text.strip() == self.text[4]
class TestSubjectConfirmationData:
def setup_class(self):
self.scd = saml.SubjectConfirmationData()
def testAccessors(self):
"""Test for SubjectConfirmationData accessors"""
self.scd.not_before = "2007-08-31T01:05:02Z"
self.scd.not_on_or_after = "2007-09-14T01:05:02Z"
self.scd.recipient = "recipient"
self.scd.in_response_to = "responseID"
self.scd.address = "127.0.0.1"
new_scd = saml.subject_confirmation_data_from_string(self.scd.to_string())
assert new_scd.not_before == "2007-08-31T01:05:02Z"
assert new_scd.not_on_or_after == "2007-09-14T01:05:02Z"
assert new_scd.recipient == "recipient"
assert new_scd.in_response_to == "responseID"
assert new_scd.address == "127.0.0.1"
def testUsingTestData(self):
"""Test subject_confirmation_data_from_string() using test data"""
scd = saml.subject_confirmation_data_from_string(
saml2_data.TEST_SUBJECT_CONFIRMATION_DATA)
assert scd.not_before == "2007-08-31T01:05:02Z"
assert scd.not_on_or_after == "2007-09-14T01:05:02Z"
assert scd.recipient == "recipient"
assert scd.in_response_to == "responseID"
assert scd.address == "127.0.0.1"
class TestSubjectConfirmation:
def setup_class(self):
self.sc = saml.SubjectConfirmation()
def testAccessors(self):
"""Test for SubjectConfirmation accessors"""
self.sc.name_id = saml.name_id_from_string(saml2_data.TEST_NAME_ID)
self.sc.method = saml.SUBJECT_CONFIRMATION_METHOD_BEARER
self.sc.subject_confirmation_data = saml.subject_confirmation_data_from_string(
saml2_data.TEST_SUBJECT_CONFIRMATION_DATA)
new_sc = saml.subject_confirmation_from_string(self.sc.to_string())
assert new_sc.name_id.sp_provided_id == "sp provided id"
assert new_sc.method == saml.SUBJECT_CONFIRMATION_METHOD_BEARER
assert new_sc.subject_confirmation_data.not_before == \
"2007-08-31T01:05:02Z"
assert new_sc.subject_confirmation_data.not_on_or_after == \
"2007-09-14T01:05:02Z"
assert new_sc.subject_confirmation_data.recipient == "recipient"
assert new_sc.subject_confirmation_data.in_response_to == "responseID"
assert new_sc.subject_confirmation_data.address == "127.0.0.1"
def testUsingTestData(self):
"""Test subject_confirmation_from_string() using test data"""
sc = saml.subject_confirmation_from_string(
saml2_data.TEST_SUBJECT_CONFIRMATION)
assert sc.name_id.sp_provided_id == "sp provided id"
assert sc.method == saml.SUBJECT_CONFIRMATION_METHOD_BEARER
assert sc.subject_confirmation_data.not_before == "2007-08-31T01:05:02Z"
assert sc.subject_confirmation_data.not_on_or_after == "2007-09-14T01:05:02Z"
assert sc.subject_confirmation_data.recipient == "recipient"
assert sc.subject_confirmation_data.in_response_to == "responseID"
assert sc.subject_confirmation_data.address == "127.0.0.1"
class TestSubject:
def setup_class(self):
self.subject = saml.Subject()
def testAccessors(self):
"""Test for Subject accessors"""
self.subject.name_id = saml.name_id_from_string(saml2_data.TEST_NAME_ID)
self.subject.subject_confirmation.append(
saml.subject_confirmation_from_string(
saml2_data.TEST_SUBJECT_CONFIRMATION))
new_subject = saml.subject_from_string(self.subject.to_string())
assert new_subject.name_id.sp_provided_id == "sp provided id"
assert new_subject.name_id.text.strip() == "tmatsuo@example.com"
assert new_subject.name_id.format == saml.NAMEID_FORMAT_EMAILADDRESS
assert isinstance(new_subject.subject_confirmation[0],
saml.SubjectConfirmation)
def testUsingTestData(self):
"""Test for subject_from_string() using test data."""
subject = saml.subject_from_string(saml2_data.TEST_SUBJECT)
assert subject.name_id.sp_provided_id == "sp provided id"
assert subject.name_id.text.strip() == "tmatsuo@example.com"
assert subject.name_id.format == saml.NAMEID_FORMAT_EMAILADDRESS
assert isinstance(subject.subject_confirmation[0],
saml.SubjectConfirmation)
class TestCondition:
def setup_class(self):
self.condition = saml.Condition()
self.name = "{%s}type" % saml.XSI_NAMESPACE
def testAccessors(self):
"""Test for Condition accessors."""
self.condition.extension_attributes[self.name] = "test"
self.condition.extension_attributes['ExtendedAttribute'] = "value"
new_condition = saml.condition_from_string(self.condition.to_string())
assert new_condition.extension_attributes[self.name] == "test"
assert new_condition.extension_attributes["ExtendedAttribute"] == "value"
def testUsingTestData(self):
"""Test for condition_from_string() using test data."""
condition = saml.condition_from_string(saml2_data.TEST_CONDITION)
assert condition.extension_attributes[self.name] == "test"
assert condition.extension_attributes["ExtendedAttribute"] == "value"
class TestAudience:
def setup_class(self):
self.audience = saml.Audience()
def testAccessors(self):
"""Test for Audience accessors"""
self.audience.text = "http://www.example.com/Audience"
new_audience = saml.audience_from_string(self.audience.to_string())
assert new_audience.text.strip() == "http://www.example.com/Audience"
def testUsingTestData(self):
"""Test audience_from_string using test data"""
audience = saml.audience_from_string(saml2_data.TEST_AUDIENCE)
assert audience.text.strip() == "http://www.example.com/Audience"
class TestAudienceRestriction:
def setup_class(self):
self.audience_restriction = saml.AudienceRestriction()
def testAccessors(self):
"""Test for AudienceRestriction accessors"""
self.audience_restriction.audience = \
saml.audience_from_string(saml2_data.TEST_AUDIENCE)
new_audience = saml.audience_restriction_from_string(
self.audience_restriction.to_string())
assert self.audience_restriction.audience.text.strip() == \
"http://www.example.com/Audience"
def testUsingTestData(self):
"""Test audience_restriction_from_string using test data"""
audience_restriction = saml.audience_restriction_from_string(
saml2_data.TEST_AUDIENCE_RESTRICTION)
assert audience_restriction.audience.text.strip() == \
"http://www.example.com/Audience"
class TestOneTimeUse:
def setup_class(self):
self.one_time_use = saml.OneTimeUse()
def testAccessors(self):
"""Test for OneTimeUse accessors"""
assert isinstance(self.one_time_use, saml.OneTimeUse)
assert isinstance(self.one_time_use, saml.Condition)
def testUsingTestData(self):
"""Test one_time_use_from_string() using test data"""
one_time_use = saml.one_time_use_from_string(saml2_data.TEST_ONE_TIME_USE)
assert isinstance(one_time_use, saml.OneTimeUse)
assert isinstance(one_time_use, saml.Condition)
class TestProxyRestriction:
def setup_class(self):
self.proxy_restriction = saml.ProxyRestriction()
def testAccessors(self):
"""Test for ProxyRestriction accessors"""
assert isinstance(self.proxy_restriction, saml.Condition)
self.proxy_restriction.count = "2"
self.proxy_restriction.audience.append(saml.audience_from_string(
saml2_data.TEST_AUDIENCE))
new_proxy_restriction = saml.proxy_restriction_from_string(
self.proxy_restriction.to_string())
assert new_proxy_restriction.count == "2"
assert new_proxy_restriction.audience[0].text.strip() == \
"http://www.example.com/Audience"
def testUsingTestData(self):
"""Test proxy_restriction_from_string() using test data"""
proxy_restriction = saml.proxy_restriction_from_string(
saml2_data.TEST_PROXY_RESTRICTION)
assert proxy_restriction.count == "2"
assert proxy_restriction.audience[0].text.strip() == \
"http://www.example.com/Audience"
class TestConditions:
def setup_class(self):
self.conditions = saml.Conditions()
def testAccessors(self):
"""Test for Conditions accessors"""
self.conditions.not_before = "2007-08-31T01:05:02Z"
self.conditions.not_on_or_after = "2007-09-14T01:05:02Z"
self.conditions.condition.append(saml.Condition())
self.conditions.audience_restriction.append(saml.AudienceRestriction())
self.conditions.one_time_use.append(saml.OneTimeUse())
self.conditions.proxy_restriction.append(saml.ProxyRestriction())
new_conditions = saml.conditions_from_string(self.conditions.to_string())
assert new_conditions.not_before == "2007-08-31T01:05:02Z"
assert new_conditions.not_on_or_after == "2007-09-14T01:05:02Z"
assert isinstance(new_conditions.condition[0], saml.Condition)
assert isinstance(new_conditions.audience_restriction[0],
saml.AudienceRestriction)
assert isinstance(new_conditions.one_time_use[0],
saml.OneTimeUse)
assert isinstance(new_conditions.proxy_restriction[0],
saml.ProxyRestriction)
def testUsingTestData(self):
"""Test conditions_from_string() using test data"""
new_conditions = saml.conditions_from_string(saml2_data.TEST_CONDITIONS)
assert new_conditions.not_before == "2007-08-31T01:05:02Z"
assert new_conditions.not_on_or_after == "2007-09-14T01:05:02Z"
assert isinstance(new_conditions.condition[0], saml.Condition)
assert isinstance(new_conditions.audience_restriction[0],
saml.AudienceRestriction)
assert isinstance(new_conditions.one_time_use[0],
saml.OneTimeUse)
assert isinstance(new_conditions.proxy_restriction[0],
saml.ProxyRestriction)
class TestAssertionIDRef:
def setup_class(self):
self.assertion_id_ref = saml.AssertionIDRef()
def testAccessors(self):
"""Test for AssertionIDRef accessors"""
self.assertion_id_ref.text = "zzlieajngjbkjggjldmgindkckkolcblndbghlhm"
new_assertion_id_ref = saml.assertion_id_ref_from_string(
self.assertion_id_ref.to_string())
assert new_assertion_id_ref.text == \
"zzlieajngjbkjggjldmgindkckkolcblndbghlhm"
def testUsingTestData(self):
"""Test assertion_id_ref_from_string() using test data"""
new_assertion_id_ref = saml.assertion_id_ref_from_string(
saml2_data.TEST_ASSERTION_ID_REF)
assert new_assertion_id_ref.text.strip() == \
"zzlieajngjbkjggjldmgindkckkolcblndbghlhm"
class TestAssertionURIRef:
def setup_class(self):
self.assertion_uri_ref = saml.AssertionURIRef()
def testAccessors(self):
"""Test for AssertionURIRef accessors"""
self.assertion_uri_ref.text = "http://www.example.com/AssertionURIRef"
new_assertion_uri_ref = saml.assertion_uri_ref_from_string(
self.assertion_uri_ref.to_string())
assert new_assertion_uri_ref.text == \
"http://www.example.com/AssertionURIRef"
def testUsingTestData(self):
"""Test assertion_uri_ref_from_string() using test data"""
new_assertion_uri_ref = saml.assertion_uri_ref_from_string(
saml2_data.TEST_ASSERTION_URI_REF)
assert new_assertion_uri_ref.text.strip() == \
"http://www.example.com/AssertionURIRef"
class TestAction:
def setup_class(self):
self.action = saml.Action()
def testAccessors(self):
"""Test for Action accessors"""
self.action.namespace = "http://www.example.com/Namespace"
new_action = saml.action_from_string(self.action.to_string())
assert new_action.namespace == "http://www.example.com/Namespace"
def testUsingTestData(self):
"""Test action_from_string() using test data"""
new_action = saml.action_from_string(saml2_data.TEST_ACTION)
assert new_action.namespace == "http://www.example.com/Namespace"
class TestEvidence:
def setup_class(self):
self.evidence = saml.Evidence()
def testAccessors(self):
"""Test for Evidence accessors"""
self.evidence.assertion_id_ref.append(saml.AssertionIDRef())
self.evidence.assertion_uri_ref.append(saml.AssertionURIRef())
self.evidence.assertion.append(saml.Assertion())
self.evidence.encrypted_assertion.append(saml.EncryptedAssertion())
new_evidence = saml.evidence_from_string(self.evidence.to_string())
print new_evidence
assert self.evidence.to_string() == new_evidence.to_string()
assert isinstance(new_evidence.assertion_id_ref[0],
saml.AssertionIDRef)
assert isinstance(new_evidence.assertion_uri_ref[0],
saml.AssertionURIRef)
assert len(new_evidence.assertion) == 1
assert isinstance(new_evidence.assertion[0], saml.Assertion)
assert len(new_evidence.encrypted_assertion) == 1
assert isinstance(new_evidence.encrypted_assertion[0],
saml.EncryptedAssertion)
def testUsingTestData(self):
"""Test evidence_from_string() using test data"""
# TODO:
pass
class TestAuthzDecisionStatement:
def setup_class(self):
self.authz_decision_statement = saml.AuthzDecisionStatement()
def testAccessors(self):
"""Test for AuthzDecisionStatement accessors"""
self.authz_decision_statement.resource = "http://www.example.com/Resource"
self.authz_decision_statement.decision = saml.DECISION_TYPE_PERMIT
self.authz_decision_statement.action.append(saml.Action())
self.authz_decision_statement.evidence.append(saml.Evidence())
new_authz_decision_statement = saml.authz_decision_statement_from_string(
self.authz_decision_statement.to_string())
assert self.authz_decision_statement.to_string() == \
new_authz_decision_statement.to_string()
assert new_authz_decision_statement.resource == \
"http://www.example.com/Resource"
assert new_authz_decision_statement.decision == \
saml.DECISION_TYPE_PERMIT
assert isinstance(new_authz_decision_statement.action[0],
saml.Action)
assert isinstance(new_authz_decision_statement.evidence[0],
saml.Evidence)
def testUsingTestData(self):
"""Test authz_decision_statement_from_string() using test data"""
# TODO:
pass
class TestAdvice:
def setup_class(self):
self.advice = saml.Advice()
def testAccessors(self):
"""Test for Advice accessors"""
self.advice.assertion_id_ref.append(saml.AssertionIDRef())
self.advice.assertion_uri_ref.append(saml.AssertionURIRef())
self.advice.assertion.append(saml.Assertion())
self.advice.encrypted_assertion.append(saml.EncryptedAssertion())
new_advice = saml.advice_from_string(self.advice.to_string())
assert self.advice.to_string() == new_advice.to_string()
assert isinstance(new_advice.assertion_id_ref[0],
saml.AssertionIDRef)
assert isinstance(new_advice.assertion_uri_ref[0],
saml.AssertionURIRef)
assert isinstance(new_advice.assertion[0], saml.Assertion)
assert isinstance(new_advice.encrypted_assertion[0],
saml.EncryptedAssertion)
def testUsingTestData(self):
"""Test advice_from_string() using test data"""
# TODO:
pass
class TestAssertion:
def setup_class(self):
self.assertion = saml.Assertion()
def testAccessors(self):
"""Test for Assertion accessors"""
self.assertion.id = "assertion id"
self.assertion.version = saml2.VERSION
self.assertion.issue_instant = "2007-08-31T01:05:02Z"
self.assertion.issuer = saml.issuer_from_string(saml2_data.TEST_ISSUER)
self.assertion.signature = ds.signature_from_string(
ds_data.TEST_SIGNATURE)
self.assertion.subject = saml.subject_from_string(saml2_data.TEST_SUBJECT)
self.assertion.conditions = saml.conditions_from_string(
saml2_data.TEST_CONDITIONS)
self.assertion.advice = saml.Advice()
self.assertion.statement.append(saml.Statement())
self.assertion.authn_statement.append(saml.authn_statement_from_string(
saml2_data.TEST_AUTHN_STATEMENT))
self.assertion.authz_decision_statement.append(
saml.AuthzDecisionStatement())
self.assertion.attribute_statement.append(
saml.attribute_statement_from_string(
saml2_data.TEST_ATTRIBUTE_STATEMENT))
new_assertion = saml.assertion_from_string(self.assertion.to_string())
assert new_assertion.id == "assertion id"
assert new_assertion.version == saml2.VERSION
assert new_assertion.issue_instant == "2007-08-31T01:05:02Z"
assert isinstance(new_assertion.issuer, saml.Issuer)
assert isinstance(new_assertion.signature, ds.Signature)
assert isinstance(new_assertion.subject, saml.Subject)
assert isinstance(new_assertion.conditions, saml.Conditions)
assert isinstance(new_assertion.advice, saml.Advice)
assert isinstance(new_assertion.statement[0], saml.Statement)
assert isinstance(new_assertion.authn_statement[0],
saml.AuthnStatement)
assert isinstance(new_assertion.authz_decision_statement[0],
saml.AuthzDecisionStatement)
assert isinstance(new_assertion.attribute_statement[0],
saml.AttributeStatement)
def testUsingTestData(self):
"""Test assertion_from_string() using test data"""
# TODO
pass

File diff suppressed because it is too large Load Diff

View File

@@ -1,535 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2009 Umeå University.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
"""Tests for saml2.samlp"""
__author__ = 'roland.hedberg@adm.umu.se (Roland Hedberg)'
import unittest
try:
from xml.etree import ElementTree
except ImportError:
from elementtree import ElementTree
import saml2
from saml2 import saml, samlp
import saml2_data, ds_data, samlp_data
import xmldsig as ds
class TestAbstractRequest:
def setup_class(self):
self.ar = samlp.AbstractRequest()
def testAccessors(self):
"""Test for AbstractRequest accessors"""
self.ar.id = "request id"
self.ar.version = saml2.VERSION
self.ar.issue_instant = "2007-09-14T01:05:02Z"
self.ar.destination = "http://www.example.com/Destination"
self.ar.consent = saml.CONSENT_UNSPECIFIED
self.ar.issuer = saml.Issuer()
self.ar.signature = ds.get_empty_signature()
self.ar.extensions = samlp.Extensions()
new_ar = samlp.abstract_request_from_string(self.ar.to_string())
assert new_ar.id == "request id"
assert new_ar.version == saml2.VERSION
assert new_ar.issue_instant == "2007-09-14T01:05:02Z"
assert new_ar.destination == "http://www.example.com/Destination"
assert new_ar.consent == saml.CONSENT_UNSPECIFIED
assert isinstance(new_ar.issuer, saml.Issuer)
assert isinstance(new_ar.signature, ds.Signature)
assert isinstance(new_ar.extensions, samlp.Extensions)
def testUsingTestData(self):
"""Test for abstract_request_from_string() using test data"""
# TODO:
pass
class TestStatusDetail:
def setup_class(self):
self.status_detail = samlp.StatusDetail()
def testAccessors(self):
"""Test for StatusDetail accessors"""
# TODO:
pass
class TestStatusMessage:
def setup_class(self):
self.status_message = samlp.StatusMessage()
def testAccessors(self):
"""Test for StatusMessage accessors"""
# TODO:
pass
class TestStatusCode:
def setup_class(self):
self.status_code = samlp.StatusCode()
def testAccessors(self):
"""Test for StatusCode accessors"""
self.status_code.value = samlp.STATUS_RESPONDER
self.status_code.status_code = samlp.StatusCode(
value=samlp.STATUS_REQUEST_DENIED)
print self.status_code.__dict__
new_status_code = samlp.status_code_from_string(self.status_code.to_string())
assert new_status_code.value == samlp.STATUS_RESPONDER
assert new_status_code.status_code.value == \
samlp.STATUS_REQUEST_DENIED
def testUsingTestData(self):
"""Test for status_code_from_string() using test data"""
new_status_code = samlp.status_code_from_string(
samlp_data.TEST_STATUS_CODE)
assert new_status_code.value == samlp.STATUS_RESPONDER
assert new_status_code.status_code.value == \
samlp.STATUS_REQUEST_DENIED
class TestStatus:
def setup_class(self):
self.status = samlp.Status()
def testAccessors(self):
"""Test for Status accessors"""
self.status.status_code = samlp.StatusCode()
self.status.status_message = samlp.StatusMessage()
self.status.status_detail = samlp.StatusDetail()
new_status = samlp.status_from_string(self.status.to_string())
assert isinstance(new_status.status_code, samlp.StatusCode)
assert isinstance(new_status.status_message, samlp.StatusMessage)
assert isinstance(new_status.status_detail, samlp.StatusDetail)
def testUsingTestData(self):
"""Test for status_from_string using test data"""
new_status = samlp.status_from_string(samlp_data.TEST_STATUS)
assert isinstance(new_status.status_code, samlp.StatusCode)
assert isinstance(new_status.status_code.status_code,
samlp.StatusCode)
assert isinstance(new_status.status_message, samlp.StatusMessage)
assert isinstance(new_status.status_detail, samlp.StatusDetail)
class TestStatusResponse:
def setup_class(self):
self.sr = samlp.StatusResponse()
def testAccessors(self):
"""Test for StatusResponse accessors"""
self.sr.id = "response id"
self.sr.in_response_to = "request id"
self.sr.version = saml2.VERSION
self.sr.issue_instant = "2007-09-14T01:05:02Z"
self.sr.destination = "http://www.example.com/Destination"
self.sr.consent = saml.CONSENT_UNSPECIFIED
self.sr.issuer = saml.Issuer()
self.sr.signature = ds.get_empty_signature()
self.sr.extensions = samlp.Extensions()
self.sr.status = samlp.Status()
new_sr = samlp.status_response_from_string(self.sr.to_string())
assert new_sr.id == "response id"
assert new_sr.in_response_to == "request id"
assert new_sr.version == saml2.VERSION
assert new_sr.issue_instant == "2007-09-14T01:05:02Z"
assert new_sr.destination == "http://www.example.com/Destination"
assert new_sr.consent == saml.CONSENT_UNSPECIFIED
assert isinstance(new_sr.issuer, saml.Issuer)
assert isinstance(new_sr.signature, ds.Signature)
assert isinstance(new_sr.extensions, samlp.Extensions)
assert isinstance(new_sr.status, samlp.Status)
def testUsingTestData(self):
"""Test for status_response_from_string() using test data"""
# TODO:
pass
class TestResponse:
def setup_class(self):
self.response = samlp.Response()
def testAccessors(self):
"""Test for Response accessors"""
self.response.id = "response id"
self.response.in_response_to = "request id"
self.response.version = saml2.VERSION
self.response.issue_instant = "2007-09-14T01:05:02Z"
self.response.destination = "http://www.example.com/Destination"
self.response.consent = saml.CONSENT_UNSPECIFIED
self.response.issuer = saml.Issuer()
self.response.signature = ds.get_empty_signature()
self.response.extensions = samlp.Extensions()
self.response.status = samlp.Status()
self.response.assertion.append(saml.Assertion())
self.response.encrypted_assertion.append(saml.EncryptedAssertion())
new_response = samlp.response_from_string(self.response.to_string())
assert new_response.id == "response id"
assert new_response.in_response_to == "request id"
assert new_response.version == saml2.VERSION
assert new_response.issue_instant == "2007-09-14T01:05:02Z"
assert new_response.destination == "http://www.example.com/Destination"
assert new_response.consent == saml.CONSENT_UNSPECIFIED
assert isinstance(new_response.issuer, saml.Issuer)
assert isinstance(new_response.signature, ds.Signature)
assert isinstance(new_response.extensions, samlp.Extensions)
assert isinstance(new_response.status, samlp.Status)
assert isinstance(new_response.assertion[0], saml.Assertion)
assert isinstance(new_response.encrypted_assertion[0],
saml.EncryptedAssertion)
def testUsingTestData(self):
"""Test for response_from_string() using test data"""
# TODO:
pass
class TestNameIDPolicy:
def setup_class(self):
self.name_id_policy = samlp.NameIDPolicy()
def testAccessors(self):
"""Test for NameIDPolicy accessors"""
self.name_id_policy.format = saml.NAMEID_FORMAT_EMAILADDRESS
self.name_id_policy.sp_name_qualifier = saml.NAMEID_FORMAT_PERSISTENT
self.name_id_policy.allow_create = 'false'
new_name_id_policy = samlp.name_id_policy_from_string(
self.name_id_policy.to_string())
assert new_name_id_policy.format == saml.NAMEID_FORMAT_EMAILADDRESS
assert new_name_id_policy.sp_name_qualifier == \
saml.NAMEID_FORMAT_PERSISTENT
assert new_name_id_policy.allow_create == 'false'
def testUsingTestData(self):
"""Test for name_id_policy_from_string() using test data"""
new_name_id_policy = samlp.name_id_policy_from_string(
samlp_data.TEST_NAME_ID_POLICY)
assert new_name_id_policy.format == saml.NAMEID_FORMAT_EMAILADDRESS
assert new_name_id_policy.sp_name_qualifier == \
saml.NAMEID_FORMAT_PERSISTENT
assert new_name_id_policy.allow_create == 'false'
class TestIDPEntry:
def setup_class(self):
self.idp_entry = samlp.IDPEntry()
def testAccessors(self):
"""Test for IDPEntry accessors"""
self.idp_entry.provider_id = "http://www.example.com/provider"
self.idp_entry.name = "the provider"
self.idp_entry.loc = "http://www.example.com/Loc"
new_idp_entry = samlp.idp_entry_from_string(self.idp_entry.to_string())
assert new_idp_entry.provider_id == "http://www.example.com/provider"
assert new_idp_entry.name == "the provider"
assert new_idp_entry.loc == "http://www.example.com/Loc"
def testUsingTestData(self):
"""Test for idp_entry_from_string() using test data"""
new_idp_entry = samlp.idp_entry_from_string(samlp_data.TEST_IDP_ENTRY)
assert new_idp_entry.provider_id == "http://www.example.com/provider"
assert new_idp_entry.name == "the provider"
assert new_idp_entry.loc == "http://www.example.com/Loc"
class TestIDPList:
def setup_class(self):
self.idp_list = samlp.IDPList()
def testAccessors(self):
"""Test for IDPList accessors"""
self.idp_list.idp_entry.append(samlp.idp_entry_from_string(
samlp_data.TEST_IDP_ENTRY))
self.idp_list.get_complete = samlp.GetComplete(
text="http://www.example.com/GetComplete")
new_idp_list = samlp.idp_list_from_string(self.idp_list.to_string())
assert isinstance(new_idp_list.idp_entry[0], samlp.IDPEntry)
assert new_idp_list.get_complete.text.strip() == \
"http://www.example.com/GetComplete"
def testUsingTestData(self):
"""Test for idp_list_from_string() using test data"""
new_idp_list = samlp.idp_list_from_string(samlp_data.TEST_IDP_LIST)
assert isinstance(new_idp_list.idp_entry[0], samlp.IDPEntry)
assert new_idp_list.get_complete.text.strip() == \
"http://www.example.com/GetComplete"
class TestScoping:
def setup_class(self):
self.scoping = samlp.Scoping()
def testAccessors(self):
"""Test for Scoping accessors"""
self.scoping.proxy_count = "1"
self.scoping.idp_list = samlp.IDPList()
self.scoping.requester_id.append(samlp.RequesterID())
new_scoping = samlp.scoping_from_string(self.scoping.to_string())
assert new_scoping.proxy_count == "1"
assert isinstance(new_scoping.idp_list, samlp.IDPList)
assert isinstance(new_scoping.requester_id[0], samlp.RequesterID)
def testUsingTestData(self):
"""Test for scoping_from_string() using test data"""
new_scoping = samlp.scoping_from_string(samlp_data.TEST_SCOPING)
assert new_scoping.proxy_count == "1"
assert isinstance(new_scoping.idp_list, samlp.IDPList)
assert isinstance(new_scoping.requester_id[0], samlp.RequesterID)
class TestRequestedAuthnContext:
def setup_class(self):
self.context = samlp.RequestedAuthnContext()
def testAccessors(self):
"""Test for RequestedAuthnContext accessors"""
self.context.authn_context_class_ref.append(saml.AuthnContextClassRef())
self.context.authn_context_decl_ref.append(saml.AuthnContextDeclRef())
self.context.comparison = "exact"
new_context = samlp.requested_authn_context_from_string(
self.context.to_string())
assert isinstance(new_context.authn_context_class_ref[0],
saml.AuthnContextClassRef)
assert isinstance(new_context.authn_context_decl_ref[0],
saml.AuthnContextDeclRef)
assert new_context.comparison == "exact"
def testUsingTestData(self):
"""Test for requested_authn_context_from_string() using test data"""
new_context = samlp.requested_authn_context_from_string(
samlp_data.TEST_REQUESTED_AUTHN_CONTEXT)
assert isinstance(new_context.authn_context_class_ref[0],
saml.AuthnContextClassRef)
assert isinstance(new_context.authn_context_decl_ref[0],
saml.AuthnContextDeclRef)
assert new_context.comparison == "exact"
class TestAuthnRequest:
def setup_class(self):
self.ar = samlp.AuthnRequest()
def testAccessors(self):
"""Test for AuthnRequest accessors"""
self.ar.id = "request id"
self.ar.version = saml2.VERSION
self.ar.issue_instant = "2007-09-14T01:05:02Z"
self.ar.destination = "http://www.example.com/Destination"
self.ar.consent = saml.CONSENT_UNSPECIFIED
self.ar.issuer = saml.Issuer()
self.ar.signature = ds.get_empty_signature()
self.ar.extensions = samlp.Extensions()
self.ar.subject = saml.Subject()
self.ar.name_id_policy = samlp.NameIDPolicy()
self.ar.conditions = saml.Conditions()
self.ar.requested_authn_context = samlp.RequestedAuthnContext()
self.ar.scoping = samlp.Scoping()
self.ar.force_authn = 'true'
self.ar.is_passive = 'true'
self.ar.assertion_consumer_service_index = "1"
self.ar.assertion_consumer_service_url = "http://www.example.com/acs"
self.ar.protocol_binding = saml2.BINDING_HTTP_POST
self.ar.assertion_consuming_service_index = "2"
self.ar.provider_name = "provider name"
new_ar = samlp.authn_request_from_string(self.ar.to_string())
assert new_ar.id == "request id"
assert new_ar.version == saml2.VERSION
assert new_ar.issue_instant == "2007-09-14T01:05:02Z"
assert new_ar.destination == "http://www.example.com/Destination"
assert new_ar.consent == saml.CONSENT_UNSPECIFIED
assert isinstance(new_ar.issuer, saml.Issuer)
assert isinstance(new_ar.signature, ds.Signature)
assert isinstance(new_ar.extensions, samlp.Extensions)
assert isinstance(new_ar.subject, saml.Subject)
assert isinstance(new_ar.name_id_policy, samlp.NameIDPolicy)
assert isinstance(new_ar.conditions, saml.Conditions)
assert isinstance(new_ar.requested_authn_context,
samlp.RequestedAuthnContext)
assert isinstance(new_ar.scoping, samlp.Scoping)
assert new_ar.force_authn == 'true'
assert new_ar.is_passive == 'true'
assert new_ar.assertion_consumer_service_index == '1'
assert new_ar.assertion_consumer_service_url == \
'http://www.example.com/acs'
assert new_ar.protocol_binding == saml2.BINDING_HTTP_POST
assert new_ar.assertion_consuming_service_index == '2'
assert new_ar.provider_name == "provider name"
def testUsingTestData(self):
"""Test for authn_request_from_string() using test data"""
new_ar = samlp.authn_request_from_string(samlp_data.TEST_AUTHN_REQUEST)
assert new_ar.id == "request id"
assert new_ar.version == saml2.VERSION
assert new_ar.issue_instant == "2007-09-14T01:05:02Z"
assert new_ar.destination == "http://www.example.com/Destination"
assert new_ar.consent == saml.CONSENT_UNSPECIFIED
assert isinstance(new_ar.issuer, saml.Issuer)
assert isinstance(new_ar.signature, ds.Signature)
assert isinstance(new_ar.extensions, samlp.Extensions)
assert isinstance(new_ar.subject, saml.Subject)
assert isinstance(new_ar.name_id_policy, samlp.NameIDPolicy)
assert isinstance(new_ar.conditions, saml.Conditions)
assert isinstance(new_ar.requested_authn_context,
samlp.RequestedAuthnContext)
assert isinstance(new_ar.scoping, samlp.Scoping)
assert new_ar.force_authn == 'true'
assert new_ar.is_passive == 'true'
assert new_ar.assertion_consumer_service_index == '1'
assert new_ar.assertion_consumer_service_url == \
'http://www.example.com/acs'
assert new_ar.protocol_binding == saml2.BINDING_HTTP_POST
assert new_ar.assertion_consuming_service_index == '2'
assert new_ar.provider_name == "provider name"
class TestLogoutRequest:
def setup_class(self):
self.lr = samlp.LogoutRequest()
def testAccessors(self):
"""Test for LogoutRequest accessors"""
self.lr.id = "request id"
self.lr.version = saml2.VERSION
self.lr.issue_instant = "2007-09-14T01:05:02Z"
self.lr.destination = "http://www.example.com/Destination"
self.lr.consent = saml.CONSENT_UNSPECIFIED
self.lr.issuer = saml.Issuer()
self.lr.signature = ds.get_empty_signature()
self.lr.extensions = samlp.Extensions()
self.lr.not_on_or_after = "2007-10-14T01:05:02Z"
self.lr.reason = "http://www.example.com/Reason"
self.lr.base_id = saml.BaseID()
self.lr.name_id = saml.NameID()
self.lr.encrypted_id = saml.EncryptedID()
self.lr.session_index = samlp.SessionIndex()
new_lr = samlp.logout_request_from_string(self.lr.to_string())
assert new_lr.id == "request id"
assert new_lr.version == saml2.VERSION
assert new_lr.issue_instant == "2007-09-14T01:05:02Z"
assert new_lr.destination == "http://www.example.com/Destination"
assert new_lr.consent == saml.CONSENT_UNSPECIFIED
assert isinstance(new_lr.issuer, saml.Issuer)
assert isinstance(new_lr.signature, ds.Signature)
assert isinstance(new_lr.extensions, samlp.Extensions)
assert new_lr.not_on_or_after == "2007-10-14T01:05:02Z"
assert new_lr.reason == "http://www.example.com/Reason"
assert isinstance(new_lr.base_id, saml.BaseID)
assert isinstance(new_lr.name_id, saml.NameID)
assert isinstance(new_lr.encrypted_id, saml.EncryptedID)
assert isinstance(new_lr.session_index, samlp.SessionIndex)
def testUsingTestData(self):
"""Test for logout_request_from_string() using test data"""
new_lr = samlp.logout_request_from_string(samlp_data.TEST_LOGOUT_REQUEST)
assert new_lr.id == "request id"
assert new_lr.version == saml2.VERSION
assert new_lr.issue_instant == "2007-09-14T01:05:02Z"
assert new_lr.destination == "http://www.example.com/Destination"
assert new_lr.consent == saml.CONSENT_UNSPECIFIED
assert isinstance(new_lr.issuer, saml.Issuer)
assert isinstance(new_lr.signature, ds.Signature)
assert isinstance(new_lr.extensions, samlp.Extensions)
assert new_lr.not_on_or_after == "2007-10-14T01:05:02Z"
assert new_lr.reason == "http://www.example.com/Reason"
assert isinstance(new_lr.base_id, saml.BaseID)
assert isinstance(new_lr.name_id, saml.NameID)
assert isinstance(new_lr.encrypted_id, saml.EncryptedID)
assert isinstance(new_lr.session_index, samlp.SessionIndex)
assert new_lr.session_index.text.strip() == "session index"
class TestLogoutResponse:
def setup_class(self):
self.lr = samlp.LogoutResponse()
def testAccessors(self):
"""Test for LogoutResponse accessors"""
self.lr.id = "response id"
self.lr.in_response_to = "request id"
self.lr.version = saml2.VERSION
self.lr.issue_instant = "2007-09-14T01:05:02Z"
self.lr.destination = "http://www.example.com/Destination"
self.lr.consent = saml.CONSENT_UNSPECIFIED
self.lr.issuer = saml.Issuer()
self.lr.signature = ds.get_empty_signature()
self.lr.extensions = samlp.Extensions()
self.lr.status = samlp.Status()
new_lr = samlp.logout_response_from_string(self.lr.to_string())
assert new_lr.id == "response id"
assert new_lr.in_response_to == "request id"
assert new_lr.version == saml2.VERSION
assert new_lr.issue_instant == "2007-09-14T01:05:02Z"
assert new_lr.destination == "http://www.example.com/Destination"
assert new_lr.consent == saml.CONSENT_UNSPECIFIED
assert isinstance(new_lr.issuer, saml.Issuer)
assert isinstance(new_lr.signature, ds.Signature)
assert isinstance(new_lr.extensions, samlp.Extensions)
assert isinstance(new_lr.status, samlp.Status)
def testUsingTestData(self):
"""Test for logout_response_from_string() using test data"""
new_lr = samlp.logout_response_from_string(
samlp_data.TEST_LOGOUT_RESPONSE)
assert new_lr.id == "response id"
assert new_lr.in_response_to == "request id"
assert new_lr.version == saml2.VERSION
assert new_lr.issue_instant == "2007-09-14T01:05:02Z"
assert new_lr.destination == "http://www.example.com/Destination"
assert new_lr.consent == saml.CONSENT_UNSPECIFIED
assert isinstance(new_lr.issuer, saml.Issuer)
assert isinstance(new_lr.signature, ds.Signature)
assert isinstance(new_lr.extensions, samlp.Extensions)
assert isinstance(new_lr.status, samlp.Status)

View File

@@ -1,443 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import zlib
import base64
import gzip
from saml2 import utils, saml, samlp, md, make_instance
from saml2.utils import do_attribute_statement
from saml2.sigver import make_temp
from saml2.saml import Attribute, NAME_FORMAT_URI, AttributeValue
from py.test import raises
SUCCESS_STATUS = """<?xml version=\'1.0\' encoding=\'UTF-8\'?>
<ns0:Status xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol"><ns0:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /></ns0:Status>"""
ERROR_STATUS = """<?xml version='1.0' encoding='UTF-8'?>
<ns0:Status xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol"><ns0:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder"><ns0:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal" /></ns0:StatusCode><ns0:StatusMessage>Error resolving principal</ns0:StatusMessage></ns0:Status>"""
def _eq(l1,l2):
return set(l1) == set(l2)
def _oeq(l1,l2):
if len(l1) != len(l2):
print "Different number of items"
return False
for item in l1:
if item not in l2:
print "%s not in l2" % (item,)
for ite in l2:
print "\t%s" % (ite,)
return False
return True
def test_inflate_then_deflate():
str = """Selma Lagerlöf (1858-1940) was born in Östra Emterwik, Värmland,
Sweden. She was brought up on Mårbacka, the family estate, which she did
not leave until 1881, when she went to a teachers' college at Stockholm"""
interm = utils.deflate_and_base64_encode(str)
bis = utils.decode_base64_and_inflate(interm)
assert bis == str
def test_status_success():
stat = utils.args2dict(
status_code=utils.args2dict(value=samlp.STATUS_SUCCESS))
status = make_instance( samlp.Status, stat)
status_text = "%s" % status
assert status_text == SUCCESS_STATUS
assert status.status_code.value == samlp.STATUS_SUCCESS
def test_success_status():
stat = utils.success_status_factory()
status = make_instance(samlp.Status, stat)
status_text = "%s" % status
assert status_text == SUCCESS_STATUS
assert status.status_code.value == samlp.STATUS_SUCCESS
def test_error_status():
stat = utils.args2dict(
status_message=utils.args2dict("Error resolving principal"),
status_code=utils.args2dict(
value=samlp.STATUS_RESPONDER,
status_code=utils.args2dict(
value=samlp.STATUS_UNKNOWN_PRINCIPAL)))
status_text = "%s" % make_instance( samlp.Status, stat )
print status_text
assert status_text == ERROR_STATUS
def test_status_from_exception():
e = utils.UnknownPrincipal("Error resolving principal")
stat = utils.status_from_exception_factory(e)
print stat
status_text = "%s" % make_instance( samlp.Status, stat )
print status_text
assert status_text == ERROR_STATUS
def test_attribute_sn():
attr = utils.do_attributes({"surName":"Jeter"})
assert len(attr) == 1
print attr
inst = make_instance(saml.Attribute, attr[0])
print inst
assert inst.name == "surName"
assert len(inst.attribute_value) == 1
av = inst.attribute_value[0]
assert av.text == "Jeter"
assert av.type == "xs:string"
def test_attribute_age():
attr = utils.do_attributes({"age":37})
assert len(attr) == 1
inst = make_instance(saml.Attribute, attr[0])
print inst
assert inst.name == "age"
assert len(inst.attribute_value) == 1
av = inst.attribute_value[0]
assert av.text == "37"
assert av.type == "xs:integer"
def test_attribute_onoff():
attr = utils.do_attributes({"onoff":False})
assert len(attr) == 1
inst = make_instance(saml.Attribute, attr[0])
print inst
assert inst.name == "onoff"
assert len(inst.attribute_value) == 1
av = inst.attribute_value[0]
assert av.text == "false"
assert av.type == "xs:boolean"
def test_attribute_base64():
attr = utils.do_attributes({"name":"Selma Lagerlöf"})
assert len(attr) == 1
inst = make_instance(saml.Attribute, attr[0], True)
print inst
assert inst.name == "name"
assert len(inst.attribute_value) == 1
av = inst.attribute_value[0]
assert av.type == "xs:base64Binary"
assert av.text.strip() == "U2VsbWEgTGFnZXJsw7Zm"
def test_attribute_statement():
astat = do_attribute_statement({"surName":"Jeter",
"givenName":"Derek"})
print astat
statement = make_instance(saml.AttributeStatement,astat)
print statement
assert statement.keyswv() == ["attribute"]
assert len(statement.attribute) == 2
attr0 = statement.attribute[0]
assert _eq(attr0.keyswv(), ["name","attribute_value"])
assert len(attr0.attribute_value) == 1
attr1 = statement.attribute[1]
assert _eq(attr1.keyswv(), ["name","attribute_value"])
assert len(attr1.attribute_value) == 1
if attr0.name == "givenName":
assert attr0.attribute_value[0].text == "Derek"
assert attr1.name == "surName"
assert attr1.attribute_value[0].text == "Jeter"
else:
assert attr0.name == "surName"
assert attr0.attribute_value[0].text == "Jeter"
assert attr1.name == "givenName"
assert attr1.attribute_value[0].text == "Derek"
def test_audience():
aud_restr = make_instance( saml.AudienceRestriction,
utils.args2dict(
audience=utils.args2dict("urn:foo:bar")))
assert aud_restr.keyswv() == ["audience"]
assert aud_restr.audience.text == "urn:foo:bar"
def test_conditions():
conds_dict = utils.args2dict(
not_before="2009-10-30T07:58:10.852Z",
not_on_or_after="2009-10-30T08:03:10.852Z",
audience_restriction=utils.args2dict(
audience=utils.args2dict("urn:foo:bar")))
conditions = make_instance(saml.Conditions, conds_dict)
assert _eq(conditions.keyswv(), ["not_before", "not_on_or_after",
"audience_restriction"])
assert conditions.not_before == "2009-10-30T07:58:10.852Z"
assert conditions.not_on_or_after == "2009-10-30T08:03:10.852Z"
assert conditions.audience_restriction[0].audience.text == "urn:foo:bar"
def test_value_1():
#FriendlyName="givenName" Name="urn:oid:2.5.4.42"
# NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
adict = utils.args2dict(name="urn:oid:2.5.4.42",
name_format=NAME_FORMAT_URI)
attribute = make_instance(saml.Attribute, adict)
assert _eq(attribute.keyswv(),["name","name_format"])
assert attribute.name == "urn:oid:2.5.4.42"
assert attribute.name_format == saml.NAME_FORMAT_URI
def test_value_2():
adict = utils.args2dict(name="urn:oid:2.5.4.42",
name_format=NAME_FORMAT_URI,
friendly_name="givenName")
attribute = make_instance(saml.Attribute, adict)
assert _eq(attribute.keyswv(),["name","name_format","friendly_name"])
assert attribute.name == "urn:oid:2.5.4.42"
assert attribute.name_format == NAME_FORMAT_URI
assert attribute.friendly_name == "givenName"
def test_value_3():
adict = utils.args2dict(attribute_value="Derek",
name="urn:oid:2.5.4.42",
name_format=NAME_FORMAT_URI,
friendly_name="givenName")
attribute = make_instance(saml.Attribute, adict)
assert _eq(attribute.keyswv(),["name", "name_format",
"friendly_name", "attribute_value"])
assert attribute.name == "urn:oid:2.5.4.42"
assert attribute.name_format == NAME_FORMAT_URI
assert attribute.friendly_name == "givenName"
assert len(attribute.attribute_value) == 1
assert attribute.attribute_value[0].text == "Derek"
def test_value_4():
adict = utils.args2dict(attribute_value="Derek",
friendly_name="givenName")
attribute = make_instance(saml.Attribute, adict)
assert _eq(attribute.keyswv(),["friendly_name", "attribute_value"])
assert attribute.friendly_name == "givenName"
assert len(attribute.attribute_value) == 1
assert attribute.attribute_value[0].text == "Derek"
def test_do_attribute_statement_0():
astat = do_attribute_statement({"vo_attr":"foobar"})
statement = make_instance(saml.AttributeStatement,astat)
assert statement.keyswv() == ["attribute"]
assert len(statement.attribute) == 1
attr0 = statement.attribute[0]
assert _eq(attr0.keyswv(), ["name","attribute_value"])
assert attr0.name == "vo_attr"
assert len(attr0.attribute_value) == 1
assert attr0.attribute_value[0].text == "foobar"
def test_do_attribute_statement():
astat = do_attribute_statement({"surName":"Jeter",
"givenName":["Derek","Sanderson"]})
statement = make_instance(saml.AttributeStatement, astat)
assert statement.keyswv() == ["attribute"]
assert len(statement.attribute) == 2
attr0 = statement.attribute[0]
assert _eq(attr0.keyswv(), ["name","attribute_value"])
attr1 = statement.attribute[1]
assert _eq(attr1.keyswv(), ["name","attribute_value"])
if attr0.name == "givenName":
assert len(attr0.attribute_value) == 2
assert _eq([av.text for av in attr0.attribute_value],
["Derek","Sanderson"])
assert attr1.name == "surName"
assert attr1.attribute_value[0].text == "Jeter"
assert len(attr1.attribute_value) == 1
else:
assert attr0.name == "surName"
assert attr0.attribute_value[0].text == "Jeter"
assert len(attr0.attribute_value) == 1
assert attr1.name == "givenName"
assert len(attr1.attribute_value) == 2
assert _eq([av.text for av in attr1.attribute_value],
["Derek","Sanderson"])
def test_do_attribute_statement_multi():
astat = do_attribute_statement(
{( "urn:oid:1.3.6.1.4.1.5923.1.1.1.7",
"urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
"eduPersonEntitlement"):"Jeter"})
statement = make_instance(saml.AttributeStatement,astat)
assert statement.keyswv() == ["attribute"]
assert len(statement.attribute)
assert _eq(statement.attribute[0].keyswv(),
["name","name_format","friendly_name","attribute_value"])
attribute = statement.attribute[0]
assert attribute.name == "urn:oid:1.3.6.1.4.1.5923.1.1.1.7"
assert attribute.name_format == (
"urn:oasis:names:tc:SAML:2.0:attrname-format:uri")
assert attribute.friendly_name == "eduPersonEntitlement"
def test_subject():
adict = utils.args2dict("_aaa", name_id=saml.NAMEID_FORMAT_TRANSIENT)
subject = make_instance(saml.Subject, adict)
assert _eq(subject.keyswv(),["text", "name_id"])
assert subject.text == "_aaa"
assert subject.name_id.text == saml.NAMEID_FORMAT_TRANSIENT
def test_parse_attribute_map():
(forward, backward) = utils.parse_attribute_map(["attribute.map"])
assert _eq(forward.keys(), backward.values())
assert _eq(forward.values(), backward.keys())
print forward.keys()
assert _oeq(forward.keys(), [
('urn:oid:1.3.6.1.4.1.5923.1.1.1.7', NAME_FORMAT_URI),
('urn:oid:0.9.2342.19200300.100.1.1', NAME_FORMAT_URI),
('urn:oid:1.3.6.1.4.1.5923.1.1.1.1', NAME_FORMAT_URI),
('urn:oid:2.5.4.42', NAME_FORMAT_URI),
('urn:oid:2.5.4.4', NAME_FORMAT_URI),
('urn:oid:0.9.2342.19200300.100.1.3', NAME_FORMAT_URI),
('urn:oid:2.5.4.12', NAME_FORMAT_URI)])
assert _eq(forward.keys(), [
('urn:oid:1.3.6.1.4.1.5923.1.1.1.7', NAME_FORMAT_URI),
('urn:oid:0.9.2342.19200300.100.1.1', NAME_FORMAT_URI),
('urn:oid:1.3.6.1.4.1.5923.1.1.1.1', NAME_FORMAT_URI),
('urn:oid:2.5.4.42', NAME_FORMAT_URI),
('urn:oid:2.5.4.4', NAME_FORMAT_URI),
('urn:oid:0.9.2342.19200300.100.1.3', NAME_FORMAT_URI),
('urn:oid:2.5.4.12', NAME_FORMAT_URI)])
assert _eq(backward.keys(),["surName","givenName","title","uid","mail",
"eduPersonAffiliation",
"eduPersonEntitlement"])
def test_identity_attribute_0():
(forward, backward) = utils.parse_attribute_map(["attribute.map"])
a = Attribute(name="urn:oid:2.5.4.4", name_format=NAME_FORMAT_URI,
friendly_name="surName")
assert utils.identity_attribute("name",a,forward) == "urn:oid:2.5.4.4"
assert utils.identity_attribute("friendly",a,forward) == "surName"
def test_identity_attribute_1():
(forward, backward) = utils.parse_attribute_map(["attribute.map"])
a = Attribute(name="urn:oid:2.5.4.4", name_format=NAME_FORMAT_URI)
assert utils.identity_attribute("name",a,forward) == "urn:oid:2.5.4.4"
assert utils.identity_attribute("friendly",a,forward) == "surName"
def test_identity_attribute_2():
(forward, backward) = utils.parse_attribute_map(["attribute.map"])
a = Attribute(name="urn:oid:2.5.4.5", name_format=NAME_FORMAT_URI)
assert utils.identity_attribute("name",a,forward) == "urn:oid:2.5.4.5"
# if there would be a map it would be serialNumber
assert utils.identity_attribute("friendly",a,forward) == "urn:oid:2.5.4.5"
def test_identity_attribute_3():
a = Attribute(name="urn:oid:2.5.4.5", name_format=NAME_FORMAT_URI)
assert utils.identity_attribute("name",a) == "urn:oid:2.5.4.5"
# if there would be a map it would be serialNumber
assert utils.identity_attribute("friendly",a) == "urn:oid:2.5.4.5"
def test_identity_attribute_4():
a = Attribute(name="urn:oid:2.5.4.5", name_format=NAME_FORMAT_URI,
friendly_name="serialNumber")
assert utils.identity_attribute("name",a) == "urn:oid:2.5.4.5"
# if there would be a map it would be serialNumber
assert utils.identity_attribute("friendly",a) == "serialNumber"
def _givenName(a):
assert a["name"] == "urn:oid:2.5.4.42"
assert a["friendly_name"] == "givenName"
assert len(a["attribute_value"]) == 1
assert a["attribute_value"] == [{"text":"Derek"}]
def _surName(a):
assert a["name"] == "urn:oid:2.5.4.4"
assert a["friendly_name"] == "surName"
assert len(a["attribute_value"]) == 1
assert a["attribute_value"] == [{"text":"Jeter"}]
def test_nameformat_email():
assert utils.valid_email("foo@example.com")
assert utils.valid_email("a@b.com")
assert utils.valid_email("a@b.se")
assert utils.valid_email("john@doe@johndoe.com") == False
def test_args2dict():
n = utils.args2dict("foo", name_qualifier="urn:mace:example.com:nq")
assert _eq(n.keys(), ["text","name_qualifier"])
assert n["text"] == "foo"
assert n["name_qualifier"] == "urn:mace:example.com:nq"
def test_attribute():
a = utils.args2dict(friendly_name="eduPersonScopedAffiliation",
name="urn:oid:1.3.6.1.4.1.5923.1.1.1.9",
name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri")
assert _eq(a.keys(), ["friendly_name","name", "name_format"])
a = utils.args2dict(friendly_name="eduPersonScopedAffiliation",
name="urn:oid:1.3.6.1.4.1.5923.1.1.1.9",
name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
attribute_value=utils.args2dict("member@example.com"))
assert _eq(a.keys(), ["friendly_name","name", "name_format",
"attribute_value"])
def test_attribute_statement():
a = utils.args2dict(
attribute=[
utils.args2dict(attribute_value="Derek",
friendly_name="givenName"),
utils.args2dict(attribute_value="Jeter",
friendly_name="surName"),
])
assert a.keys() == ["attribute"]
assert len(a["attribute"]) == 2
def test_subject_confirmation_data():
s = utils.args2dict(
in_response_to="_12345678",
not_before="2010-02-11T07:30:00Z",
not_on_or_after="2010-02-11T07:35:00Z",
recipient="http://example.com/sp/",
address="192.168.0.10")
assert _eq(s.keys(),["in_response_to","not_before","not_on_or_after",
"recipient", "address"])
def test_subject_confirmation():
s = utils.args2dict(
method="urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser",
base_id="1234",
name_id="abcd",
subject_confirmation_data=utils.args2dict(
in_response_to="_1234567890",
recipient="http://example.com/sp/"))
assert _eq(s.keys(),
["method","base_id","name_id","subject_confirmation_data"])
assert s["method"] == "urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser"
def test_authn_context_class_ref():
a = utils.args2dict(
"urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified")
assert a.keys() == ["text"]
assert a["text"] == "urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified"
def test_authn_context():
accr = utils.args2dict(
"urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified")
a = utils.args2dict(authn_context_class_ref=accr)
assert a.keys() == ["authn_context_class_ref"]
def test_authn_statement():
accr = utils.args2dict(
"urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified")
ac = utils.args2dict(authn_context_class_ref=accr)
a = utils.args2dict(
authn_instant="2010-03-10T12:33:00Z",
session_index="_12345",
session_not_on_or_after="2010-03-11T12:00:00Z",
authn_context=ac
)

View File

@@ -2,7 +2,7 @@ from saml2 import md, assertion
from saml2.saml import Attribute, NAME_FORMAT_URI, AttributeValue
from saml2.assertion import Policy, Assertion, filter_on_attributes
from saml2.assertion import filter_attribute_value_assertions
from saml2.utils import MissingValue
from saml2.s_utils import MissingValue
from saml2 import attribute_converter
from py.test import raises
@@ -152,21 +152,24 @@ def test_ava_filter_2():
}
}}
r = Policy(conf)
policy = Policy(conf)
ava = {"givenName":"Derek",
"surName": "Jeter",
"mail":"derek@example.com"}
# I'm filtering away something the SP deems necessary
raises(MissingValue, r.filter, ava, 'urn:mace:umu.se:saml:roland:sp',
#policy.filter(ava, 'urn:mace:umu.se:saml:roland:sp', [mail], [gn, sn])
raises(MissingValue, policy.filter, ava, 'urn:mace:umu.se:saml:roland:sp',
[mail], [gn, sn])
ava = {"givenName":"Derek",
"surName": "Jeter"}
# it wasn't there to begin with
raises(MissingValue, r.filter, ava, 'urn:mace:umu.se:saml:roland:sp',
raises(MissingValue, policy.filter, ava, 'urn:mace:umu.se:saml:roland:sp',
[gn,sn,mail])
def test_filter_attribute_value_assertions_0(AVA):

View File

@@ -57,21 +57,21 @@ class TestAC():
statement = attribute_converter.from_local(self.acs, ava, BASIC_NF)
assert statement != None
assert len(statement["attribute"]) == 2
a0 = statement["attribute"][0]
a1 = statement["attribute"][1]
if a0["friendly_name"] == 'sn':
assert a0["name"] == 'urn:mace:dir:attribute-def:sn'
assert a0["name_format"] == BASIC_NF
assert a1["friendly_name"] == "givenName"
assert a1["name"] == 'urn:mace:dir:attribute-def:givenName'
assert a1["name_format"] == BASIC_NF
elif a0["friendly_name"] == 'givenName':
assert a0["name"] == 'urn:mace:dir:attribute-def:givenName'
assert a0["name_format"] == BASIC_NF
assert a1["friendly_name"] == "sn"
assert a1["name"] == 'urn:mace:dir:attribute-def:sn'
assert a1["name_format"] == BASIC_NF
assert len(statement) == 2
a0 = statement[0]
a1 = statement[1]
if a0.friendly_name == 'sn':
assert a0.name == 'urn:mace:dir:attribute-def:sn'
assert a0.name_format == BASIC_NF
assert a1.friendly_name == "givenName"
assert a1.name == 'urn:mace:dir:attribute-def:givenName'
assert a1.name_format == BASIC_NF
elif a0.friendly_name == 'givenName':
assert a0.name == 'urn:mace:dir:attribute-def:givenName'
assert a0.name_format == BASIC_NF
assert a1.friendly_name == "sn"
assert a1.name == 'urn:mace:dir:attribute-def:sn'
assert a1.name_format == BASIC_NF
else:
assert False
@@ -80,21 +80,21 @@ class TestAC():
statement = attribute_converter.from_local(self.acs, ava, URI_NF)
assert len(statement["attribute"]) == 2
a0 = statement["attribute"][0]
a1 = statement["attribute"][1]
if a0["friendly_name"] == 'surname':
assert a0["name"] == 'urn:oid:2.5.4.4'
assert a0["name_format"] == URI_NF
assert a1["friendly_name"] == "givenName"
assert a1["name"] == 'urn:oid:2.5.4.42'
assert a1["name_format"] == URI_NF
elif a0["friendly_name"] == 'givenName':
assert a0["name"] == 'urn:oid:2.5.4.42'
assert a0["name_format"] == URI_NF
assert a1["friendly_name"] == "surname"
assert a1["name"] == 'urn:oid:2.5.4.4'
assert a1["name_format"] == URI_NF
assert len(statement) == 2
a0 = statement[0]
a1 = statement[1]
if a0.friendly_name == 'surname':
assert a0.name == 'urn:oid:2.5.4.4'
assert a0.name_format == URI_NF
assert a1.friendly_name == "givenName"
assert a1.name == 'urn:oid:2.5.4.42'
assert a1.name_format == URI_NF
elif a0.friendly_name == 'givenName':
assert a0.name == 'urn:oid:2.5.4.42'
assert a0.name_format == URI_NF
assert a1.friendly_name == "surname"
assert a1.name == 'urn:oid:2.5.4.4'
assert a1.name_format == URI_NF
else:
assert False

View File

@@ -10,7 +10,7 @@ from saml2.attribute_converter import ac_factory
from py.test import raises
SWAMI_METADATA = "swamid-kalmar-1.0.xml"
SWAMI_METADATA = "swamid-1.0.xml"
INCOMMON_METADATA = "InCommon-metadata.xml"
EXAMPLE_METADATA = "metadata_example.xml"
SWITCH_METADATA = "metadata.aaitest.xml"
@@ -53,16 +53,19 @@ def test_swami_1():
ssocerts = md.certs('https://idp.umu.se/saml2/idp/SSOService.php')
print ssocerts
assert len(ssocerts) == 1
print md.wants
print md._wants.keys()
assert _eq(md._wants.keys(),['https://connect.sunet.se/shibboleth',
'https://sp.swamid.se/shibboleth'])
assert _eq(md.wants('https://sp.swamid.se/shibboleth')[1].keys(),
["eduPersonPrincipalName"])
assert md.wants('https://sp.swamid.se/shibboleth')[0] == {}
'https://www.diva-portal.org/shibboleth'])
print md.wants('https://www.diva-portal.org/shibboleth')
assert _eq(md.wants('https://www.diva-portal.org/shibboleth')[1].keys(),
['mail', 'givenName', 'eduPersonPrincipalName', 'sn',
'eduPersonScopedAffiliation'])
assert md.wants('https://connect.sunet.se/shibboleth')[0] == {}
assert _eq(md.wants('https://connect.sunet.se/shibboleth')[1].keys(),
['mail', 'givenName', 'eduPersonPrincipalName', 'sn',
'eduPersonScopedAffiliation'])
assert md.wants('https://connect.sunet.se/shibboleth')[0] == {}
def test_incommon_1():
md = metadata.MetaData(attrconv=ATTRCONV)
@@ -130,8 +133,9 @@ def test_sp_metadata():
print md.entity
assert len(md.entity) == 1
assert md.entity.keys() == ['urn:mace:umu.se:saml:roland:sp']
assert md.entity['urn:mace:umu.se:saml:roland:sp'].keys() == [
'valid_until',"organization","sp_sso"]
assert _eq(md.entity['urn:mace:umu.se:saml:roland:sp'].keys(), [
'valid_until',"organization","sp_sso",
'contact_person'])
print md.entity['urn:mace:umu.se:saml:roland:sp']["sp_sso"][0].keyswv()
(req,opt) = md.attribute_consumer('urn:mace:umu.se:saml:roland:sp')
print req
@@ -174,7 +178,7 @@ def test_construct_organisation_name():
md.OrganizationName, o, "organization_name")
print o
assert str(o) == """<?xml version='1.0' encoding='UTF-8'?>
<ns0:Organization xmlns:ns0="urn:oasis:names:tc:SAML:2.0:metadata"><ns0:OrganizationName ns1:lang="se" xmlns:ns1="http:#www.w3.org/XML/1998/namespace">Exempel AB</ns0:OrganizationName></ns0:Organization>"""
<ns0:Organization xmlns:ns0="urn:oasis:names:tc:SAML:2.0:metadata"><ns0:OrganizationName xml:lang="se">Exempel AB</ns0:OrganizationName></ns0:Organization>"""
def test_make_int_value():
val = make_vals( 1, saml.AttributeValue, part=True)
@@ -260,10 +264,11 @@ def test_construct_entity_descr_1():
assert ed.entity_id == "urn:mace:catalogix.se:sp1"
org = ed.organization
assert _eq(org.keyswv(), ["organization_name","organization_url"])
assert len(org.organization_name) == 1
assert org.organization_name[0].text == "Catalogix"
assert org.organization_url[0].text == "http://www.catalogix.se/"
assert len(org) == 1
assert _eq(org[0].keyswv(), ["organization_name","organization_url"])
assert len(org[0].organization_name) == 1
assert org[0].organization_name[0].text == "Catalogix"
assert org[0].organization_url[0].text == "http://www.catalogix.se/"
def test_construct_entity_descr_2():
ed = make_instance(md.EntityDescriptor,
@@ -281,10 +286,11 @@ def test_construct_entity_descr_2():
assert _eq(ed.keyswv(), ["entity_id", "contact_person", "organization"])
assert ed.entity_id == "urn:mace:catalogix.se:sp1"
org = ed.organization
assert _eq(org.keyswv(), ["organization_name", "organization_url"])
assert len(org.organization_name) == 1
assert org.organization_name[0].text == "Catalogix"
assert org.organization_url[0].text == "http://www.catalogix.se/"
assert len(org) == 1
assert _eq(org[0].keyswv(), ["organization_name", "organization_url"])
assert len(org[0].organization_name) == 1
assert org[0].organization_name[0].text == "Catalogix"
assert org[0].organization_url[0].text == "http://www.catalogix.se/"
assert len(ed.contact_person) == 1
c = ed.contact_person[0]
assert c.given_name.text == "Roland"

View File

@@ -9,7 +9,9 @@ sp1 = {
"entityid" : "urn:mace:umu.se:saml:roland:sp",
"service": {
"sp": {
"url" : "http://lingon.catalogix.se:8087/",
"endpoints" : {
"assertion_consumer_service" : ["http://lingon.catalogix.se:8087/"],
},
"name": "test",
"idp" : {
"urn:mace:example.com:saml:roland:idp":None,
@@ -36,7 +38,9 @@ sp2 = {
"service": {
"sp":{
"name" : "Rolands SP",
"url" : "http://localhost:8087/",
"endpoints" : {
"assertion_consumer_service" : ["http://lingon.catalogix.se:8087/"],
},
"required_attributes": ["surName", "givenName", "mail"],
"optional_attributes": ["title"],
"idp": {
@@ -52,7 +56,9 @@ IDP1 = {
"service": {
"idp":{
"name" : "Rolands IdP",
"url" : "http://localhost:8088/",
"endpoints": {
"single_sign_on_service" : ["http://localhost:8088/"],
},
"assertions":{
"default": {
"attribute_restrictions": {
@@ -79,7 +85,7 @@ def test_1():
service = c["service"]
assert service.keys() == ["sp"]
sp = service["sp"]
assert _eq(sp.keys(),["url","name","idp"])
assert _eq(sp.keys(),["endpoints","name","idp"])
md = c["metadata"]
assert isinstance(md, MetaData)
@@ -94,7 +100,7 @@ def test_2():
service = c["service"]
assert service.keys() == ["sp"]
sp = service["sp"]
assert _eq(sp.keys(),['url', 'idp', 'optional_attributes', 'name',
assert _eq(sp.keys(),['endpoints', 'idp', 'optional_attributes', 'name',
'required_attributes'])
assert len(sp["idp"]) == 1
@@ -111,7 +117,9 @@ def test_missing_must():
no_entity_id = {
"service": {
"sp": {
"url" : "http://lingon.catalogix.se:8087/",
"endpoints" : {
"assertion_consumer_service" : ["http://lingon.catalogix.se:8087/"],
},
"name" : "test"
}
},
@@ -122,7 +130,9 @@ def test_missing_must():
"entityid" : "urn:mace:umu.se:saml:roland:sp",
"service": {
"sp": {
"url" : "http://lingon.catalogix.se:8087/",
"endpoints" : {
"assertion_consumer_service" : ["http://lingon.catalogix.se:8087/"],
},
"name" : "test"
}
},
@@ -138,7 +148,9 @@ def test_minimum():
"entityid" : "urn:mace:example.com:saml:roland:sp",
"service": {
"sp": {
"url" : "http://sp.example.org/",
"endpoints" : {
"assertion_consumer_service" : ["http://sp.example.org/"],
},
"name" : "test",
"idp": {
"" : "https://example.com/idp/SSOService.php",
@@ -157,8 +169,15 @@ def test_idp():
print c
assert c.services() == ["idp"]
assert c.idp_url() == "http://localhost:8088/"
assert c.endpoint("idp", "single_sign_on_service") == ['http://localhost:8088/']
attribute_restrictions = c.idp_policy().get_attribute_restriction("")
assert attribute_restrictions["eduPersonAffiliation"][0].match("staff")
def test_wayf():
c = Config().load_file("server.config")
idps = c.get_available_idps()
assert idps == [('urn:mace:example.com:saml:roland:idp', 'Example Co')]

View File

@@ -14,7 +14,9 @@ CONFIG = Config().load({
"entityid" : "urn:mace:example.com:idp:2",
"service": {
"idp": {
"url" : "http://idp.example.org/",
"endpoints" : {
"single_sign_on_service" : ["http://idp.example.org/"],
},
"name" : "test",
"assertions": {
"default": {
@@ -69,15 +71,17 @@ class TestIdentifier():
nameid = self.id.construct_nameid(policy, "foobar",
"urn:mace:example.com:sp:1")
assert _eq(nameid.keys(), ['text', 'sp_name_qualifier', 'format'])
assert nameid["sp_name_qualifier"] == CONFIG["entityid"]
assert nameid["format"] == NAMEID_FORMAT_PERSISTENT
assert _eq(nameid.keys(), ['text', 'sp_provided_id',
'sp_name_qualifier', 'name_qualifier', 'format'])
assert _eq(nameid.keyswv(), ['format', 'text', 'sp_name_qualifier'])
assert nameid.sp_name_qualifier == CONFIG["entityid"]
assert nameid.format == NAMEID_FORMAT_PERSISTENT
nameid_2 = self.id.construct_nameid(policy, "foobar",
"urn:mace:example.com:sp:1")
assert nameid == nameid_2
assert nameid["text"] == nameid_2["text"]
assert nameid != nameid_2
assert nameid.text == nameid_2.text
def test_transient_1(self):
policy = Policy({
@@ -92,8 +96,8 @@ class TestIdentifier():
nameid = self.id.construct_nameid(policy, "foobar",
"urn:mace:example.com:sp:1")
assert _eq(nameid.keys(), ['text', 'format'])
assert nameid["format"] == NAMEID_FORMAT_TRANSIENT
assert _eq(nameid.keyswv(), ['text', 'format'])
assert nameid.format == NAMEID_FORMAT_TRANSIENT
def test_vo_1(self):
policy = Policy({
@@ -112,11 +116,11 @@ class TestIdentifier():
{"uid": "foobar01"},
name_id_policy)
assert _eq(nameid.keys(), ['text', 'sp_name_qualifier', 'format'])
assert nameid["sp_name_qualifier"] == 'http://vo.example.org/biomed'
assert nameid["format"] == \
assert _eq(nameid.keyswv(), ['text', 'sp_name_qualifier', 'format'])
assert nameid.sp_name_qualifier == 'http://vo.example.org/biomed'
assert nameid.format == \
CONFIG.vo_conf('http://vo.example.org/biomed')["nameid_format"]
assert nameid["text"] == "foobar01"
assert nameid.text == "foobar01"
def test_vo_2(self):
policy = Policy({
@@ -136,8 +140,8 @@ class TestIdentifier():
{"uid": "foobar01"},
name_id_policy)
assert _eq(nameid.keys(), ['text', 'sp_name_qualifier', 'format'])
assert nameid["sp_name_qualifier"] == 'http://vo.example.org/design'
assert nameid["format"] == NAMEID_FORMAT_PERSISTENT
assert nameid["text"] != "foobar01"
assert _eq(nameid.keyswv(), ['text', 'sp_name_qualifier', 'format'])
assert nameid.sp_name_qualifier == 'http://vo.example.org/design'
assert nameid.format == NAMEID_FORMAT_PERSISTENT
assert nameid.text != "foobar01"

View File

@@ -4,9 +4,10 @@ import os
import base64
from saml2 import sigver, make_instance
from saml2 import utils, class_name
from saml2 import class_name
from saml2 import time_util
from saml2 import saml, samlp
from saml2.s_utils import factory, do_attribute_statement
import xmldsig as ds
from py.test import raises
@@ -21,11 +22,11 @@ PRIV_KEY = "test.key"
def _eq(l1,l2):
return set(l1) == set(l2)
SIGNED_VALUE= """AS1kHHtA4eTOU2XLTWhLMSJQ6V+TSDymRoTF78CqjrYURNLk9wjdPjAReNn9eykv
ryFiHNk0p9wMBknha5pH8aeCI/LmcVhLa5xteGZrtE/Udh5vv8z4kRQX51Uz/5x8
ToiobGw83MEW6A0dRUn0O20NBMMTaFZZPXye7RvVlHY="""
SIGNED_VALUE= """kMuyOK17nyp4CbA1v7KE32rX4+NQQ8EvdglTK61uIMEo3ax0PgFU7bgZGey+Aj8H
hTPVyAzWmBDxHpSCFe050PTtNoKHx7nXprLfhuQXsPq8s0KBoZR+2qYfVCkWYVX7
T3zG/Tn+fesBA1zLo4lYdAovol7C35KAsAWoknmZdOE="""
DIGEST_VALUE = "WFRXmImfoO3M6JOLE6BGGpU9Ud0="
DIGEST_VALUE = "SXw3kqTf+PtTiUnI8nQ6xmrM3qw="
def get_xmlsec():
for path in os.environ["PATH"].split(":"):
@@ -94,24 +95,16 @@ class TestSecurity():
self.sec = sigver.SecurityContext(get_xmlsec(), PRIV_KEY, "pem",
PUB_KEY, "pem", debug=1)
self._assertion = {
"version": "2.0",
"id": "11111",
"issue_instant": "2009-10-30T13:20:28Z",
"signature": sigver.pre_signature_part("11111", self.sec.my_cert,
1),
"attribute_statement": {
"attribute": [{
"friendly_name": "surName",
"attribute_value": "Foo",
},
{
"friendly_name": "givenName",
"attribute_value": "Bar",
}
]
}
}
self._assertion = factory( saml.Assertion,
version="2.0",
id="11111",
issue_instant="2009-10-30T13:20:28Z",
signature=sigver.pre_signature_part("11111", self.sec.my_cert, 1),
attribute_statement=do_attribute_statement({
("","","surName"): ("Foo",""),
("","","givenName") :("Bar",""),
})
)
def test_verify_1(self):
xml_response = open(SIGNED).read()
@@ -130,10 +123,10 @@ class TestSecurity():
xml_response)
def test_sign_assertion(self):
ass = make_instance(saml.Assertion, self._assertion)
ass = self._assertion
print ass
sign_ass = self.sec.sign_assertion_using_xmlsec("%s" % ass, nodeid=ass.id)
print sign_ass
sass = saml.assertion_from_string(sign_ass)
print sass
assert _eq(sass.keyswv(), ['attribute_statement', 'issue_instant',
@@ -144,15 +137,18 @@ class TestSecurity():
sig = sass.signature
assert sig.signature_value.text == SIGNED_VALUE
assert len(sig.signed_info.reference) == 1
assert len(sig.signed_info.reference[0].digest_value) == 1
assert sig.signed_info.reference[0].digest_value[0].text == DIGEST_VALUE
assert sig.signed_info.reference[0].digest_value
assert sig.signed_info.reference[0].digest_value.text == DIGEST_VALUE
def test_sign_response(self):
s_response = sigver.signed_instance_factory(samlp.Response, {
"assertion" : self._assertion,
"id": "22222",
"signature": sigver.pre_signature_part("22222"),
}, self.sec)
response = factory(samlp.Response,
assertion=self._assertion,
id="22222",
signature=sigver.pre_signature_part("22222", self.sec.my_cert))
to_sign = [(class_name(self._assertion), self._assertion.id),
(class_name(response), response.id)]
s_response = sigver.signed_instance_factory( response, self.sec, to_sign)
assert s_response != None
print s_response
@@ -166,37 +162,33 @@ class TestSecurity():
assert sass.id == "11111"
assert time_util.str_to_time(sass.issue_instant)
sig = sass.signature
assert sig.signature_value.text == """xObs8g6Kr11NopsCxv9IXPQZ4Qfxag3zZrxcza+NBZwQ2JIXEw6vQDmu/OG+EgUP\n2miVoAY4nbklsiwXZfjXYU3OOUDJr7UDhAHUuki/kcKCV6SMEUFlOcEzDFVg+Fr+\nFsPJhsmit5uRRP5rYA92y1fKf42vViw8LFj+LqlTv2Y="""
assert sig.signature_value.text == """upeKPE1pkzXLy9BvKFOSTnjn4du59lQQ74TN5CqDGae9D21uY/zLuOWql7LiSTSi\nC945F0WrOvG7s0eZnpuNPZobdfdeCOffCMMrq5RQ2+abPFBamkjmceuEKGdO5PWQ\nt7B1GkzXAMMgeMuU+YmvIJkHbbv5Yn6M0/ICE/COaKQ="""
assert len(sig.signed_info.reference) == 1
assert len(sig.signed_info.reference[0].digest_value) == 1
digest = sig.signed_info.reference[0].digest_value[0].text
assert digest == """z6O3mlLmX1a6Wk1F4cgMsAXdA6Q="""
assert sig.signed_info.reference[0].digest_value
digest = sig.signed_info.reference[0].digest_value.text
assert digest == """uX92C/YDroqITDfDY1IeekGtZac="""
def test_sign_response_2(self):
assertion2 = {
"version": "2.0",
"id": "11122",
"issue_instant": "2009-10-30T13:20:28Z",
"signature": sigver.pre_signature_part("11122"),
"attribute_statement": {
"attribute": [{
"friendly_name": "surName",
"attribute_value": "Fox",
},
{
"friendly_name": "givenName",
"attribute_value": "Bear",
}
]
}
}
assertion2 = factory( saml.Assertion,
version= "2.0",
id= "11122",
issue_instant= "2009-10-30T13:20:28Z",
signature= sigver.pre_signature_part("11122", self.sec.my_cert),
attribute_statement=do_attribute_statement({
("","","surName"): ("Fox",""),
("","","givenName") :("Bear",""),
})
)
response = factory(samlp.Response,
assertion=assertion2,
id="22233",
signature=sigver.pre_signature_part("22233"))
s_response = sigver.signed_instance_factory(samlp.Response, {
"assertion" : [self._assertion,assertion2],
"id": "22233",
"signature": sigver.pre_signature_part("22233"),
}, self.sec)
to_sign = [(class_name(assertion2), assertion2.id),
(class_name(response), response.id)]
s_response = sigver.signed_instance_factory( response, self.sec, to_sign)
assert s_response != None
print s_response
@@ -207,23 +199,26 @@ class TestSecurity():
assert _eq(sass.keyswv(), ['attribute_statement', 'issue_instant',
'version', 'signature', 'id'])
assert sass.version == "2.0"
assert sass.id == "11111"
assert sass.id == "11122"
assert time_util.str_to_time(sass.issue_instant)
sig = sass.signature
assert sig.signature_value.text == """xObs8g6Kr11NopsCxv9IXPQZ4Qfxag3zZrxcza+NBZwQ2JIXEw6vQDmu/OG+EgUP\n2miVoAY4nbklsiwXZfjXYU3OOUDJr7UDhAHUuki/kcKCV6SMEUFlOcEzDFVg+Fr+\nFsPJhsmit5uRRP5rYA92y1fKf42vViw8LFj+LqlTv2Y="""
assert sig.signature_value.text == """xHECLk1jj4NBvk1jhGrb2mwnrLFKXk6JN3NogjMVMtnnarg9vtk7jYzy1M9RPWdj\nRSa2Jph7yVZJENm4bGuBkT91w+FYm2X4jREULPUsnupPHTQyhJEVZ07EhnluOWa3\n95KkqnZ5gbnTxn1ZvpsANzThLmYY3eSGzNXz+S7758M="""
assert len(sig.signed_info.reference) == 1
assert len(sig.signed_info.reference[0].digest_value) == 1
digest = sig.signed_info.reference[0].digest_value[0].text
assert digest == """z6O3mlLmX1a6Wk1F4cgMsAXdA6Q="""
assert sig.signed_info.reference[0].digest_value
digest = sig.signed_info.reference[0].digest_value.text
assert digest == """l36wHa6Lyed9ZeAZ3jFL77wPVQ4="""
def test_sign_verify(self):
s_response = sigver.signed_instance_factory(samlp.Response, {
"assertion" : self._assertion,
"id": "22222",
"signature": sigver.pre_signature_part("22222",
self.sec.my_cert),
}, self.sec)
response = factory(samlp.Response,
assertion=self._assertion,
id="22233",
signature=sigver.pre_signature_part("22233", self.sec.my_cert))
to_sign = [(class_name(self._assertion), self._assertion.id),
(class_name(response), response.id)]
s_response = sigver.signed_instance_factory(response, self.sec, to_sign)
print s_response
res = self.sec.verify_signature("%s" % s_response,
@@ -233,16 +228,25 @@ class TestSecurity():
assert res
def test_sign_verify_with_cert_from_instance(self):
s_response = sigver.signed_instance_factory(samlp.Response, {
"assertion" : self._assertion,
"id": "22222",
"signature": sigver.pre_signature_part("22222",
self.sec.my_cert),
}, self.sec)
response = factory(samlp.Response,
assertion=self._assertion,
id="22222",
signature=sigver.pre_signature_part("22222", self.sec.my_cert))
print s_response
to_sign = [(class_name(self._assertion), self._assertion.id),
(class_name(response), response.id)]
s_response = sigver.signed_instance_factory(response, self.sec, to_sign)
print s_response.keyswv()
print s_response.signature.keyswv()
print s_response.signature.key_info.keyswv()
ci = "".join(sigver.cert_from_instance(s_response)[0].split())
print ci
print self.sec.my_cert
assert ci == self.sec.my_cert
res = self.sec.verify_signature("%s" % s_response,
@@ -254,26 +258,19 @@ class TestSecurity():
assert res == s_response
def test_sign_verify_assertion_with_cert_from_instance(self):
assertion = {
"version": "2.0",
"id": "11111",
"issue_instant": "2009-10-30T13:20:28Z",
"signature": sigver.pre_signature_part("11111", self.sec.my_cert),
"attribute_statement": {
"attribute": [{
"friendly_name": "surName",
"attribute_value": "Foo",
},
{
"friendly_name": "givenName",
"attribute_value": "Bar",
}
]
}
}
assertion = factory( saml.Assertion,
version= "2.0",
id= "11100",
issue_instant= "2009-10-30T13:20:28Z",
signature= sigver.pre_signature_part("11100", self.sec.my_cert),
attribute_statement=do_attribute_statement({
("","","surName"): ("Fox",""),
("","","givenName") :("Bear",""),
})
)
s_assertion = sigver.signed_instance_factory(saml.Assertion,
assertion, self.sec)
to_sign = [(class_name(assertion), assertion.id)]
s_assertion = sigver.signed_instance_factory(assertion, self.sec, to_sign)
print s_assertion
ci = "".join(sigver.cert_from_instance(s_assertion)[0].split())
@@ -289,30 +286,25 @@ class TestSecurity():
assert res
def test_exception_sign_verify_with_cert_from_instance(self):
assertion = {
"version": "2.0",
"id": "11111",
"issue_instant": "2009-10-30T13:20:28Z",
#"signature": sigver.pre_signature_part("11111"),
"attribute_statement": {
"attribute": [{
"friendly_name": "surName",
"attribute_value": "Foo",
},
{
"friendly_name": "givenName",
"attribute_value": "Bar",
}
]
}
}
assertion = factory( saml.Assertion,
version= "2.0",
id= "11100",
issue_instant= "2009-10-30T13:20:28Z",
#signature= sigver.pre_signature_part("11100", self.sec.my_cert),
attribute_statement=do_attribute_statement({
("","","surName"): ("Foo",""),
("","","givenName") :("Bar",""),
})
)
s_response = sigver.signed_instance_factory(samlp.Response, {
"assertion" : assertion,
"id": "22222",
"signature": sigver.pre_signature_part("22222",
self.sec.my_cert),
}, self.sec)
response = factory(samlp.Response,
assertion=assertion,
id="22222",
signature=sigver.pre_signature_part("22222", self.sec.my_cert))
to_sign = [(class_name(response), response.id)]
s_response = sigver.signed_instance_factory(response, self.sec, to_sign)
# Change something that should make everything fail
@@ -320,16 +312,3 @@ class TestSecurity():
raises(sigver.SignatureError, self.sec._check_signature,
"%s" % s_response, s_response, class_name(s_response))
# def test_sign_verify_assertion_in_response(self):
# s_response = sigver.signed_instance_factory(samlp.Response, {
# "assertion" : self._assertion,
# "id": "22222",
# "signature": sigver.pre_signature_part("22222",
# self.sec.my_cert, 2),
# }, self.sec)
#
# print s_response
# res = self.sec.correctly_signed_response("%s" % s_response)
#
# print res
# assert res

View File

@@ -1,655 +0,0 @@
#!/usr/bin/python
#
# Copyright (C) 2007 SIOS Technology, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
"""Tests for xmldsig"""
__author__ = 'tmatsuo@example.com (Takashi MATSUO)'
import unittest
try:
from xml.etree import ElementTree
except ImportError:
from elementtree import ElementTree
import ds_data
import xmldsig as ds
class TestObject:
def setup_class(self):
self.object = ds.Object()
def testAccessors(self):
"""Test for Object accessors"""
self.object.identifier = "object_id"
self.object.mime_type = "test/plain; charset=UTF-8"
self.object.encoding = ds.ENCODING_BASE64
new_object = ds.object_from_string(self.object.to_string())
assert new_object.identifier == "object_id"
assert new_object.mime_type == "test/plain; charset=UTF-8"
assert new_object.encoding == ds.ENCODING_BASE64
def testUsingTestData(self):
"""Test for object_from_string() using test data"""
new_object = ds.object_from_string(ds_data.TEST_OBJECT)
assert new_object.identifier == "object_id"
assert new_object.encoding == ds.ENCODING_BASE64
assert new_object.text.strip() == \
"V2VkIEp1biAgNCAxMjoxMTowMyBFRFQgMjAwMwo"
class TestMgmtData:
def setup_class(self):
self.mgmt_data = ds.MgmtData()
def testAccessors(self):
"""Test for MgmtData accessors"""
self.mgmt_data.text = "mgmt data"
new_mgmt_data = ds.mgmt_data_from_string(self.mgmt_data.to_string())
assert new_mgmt_data.text.strip() == "mgmt data"
def testUsingTestData(self):
"""Test for mgmt_data_from_string() using test data"""
new_mgmt_data = ds.mgmt_data_from_string(ds_data.TEST_MGMT_DATA)
assert new_mgmt_data.text.strip() == "mgmt data"
class TestSPKISexp:
def setup_class(self):
self.spki_sexp = ds.SPKISexp()
def testAccessors(self):
"""Test for SPKISexp accessors"""
self.spki_sexp.text = "spki sexp"
new_spki_sexp = ds.spki_sexp_from_string(self.spki_sexp.to_string())
assert new_spki_sexp.text.strip() == "spki sexp"
def testUsingTestData(self):
"""Test for spki_sexp_from_string() using test data"""
new_spki_sexp = ds.spki_sexp_from_string(ds_data.TEST_SPKI_SEXP)
assert new_spki_sexp.text.strip() == "spki sexp"
class TestSPKIData:
def setup_class(self):
self.spki_data = ds.SPKIData()
def testAccessors(self):
"""Test for SPKIData accessors"""
self.spki_data.spki_sexp.append(
ds.spki_sexp_from_string(ds_data.TEST_SPKI_SEXP))
new_spki_data = ds.spki_data_from_string(self.spki_data.to_string())
assert new_spki_data.spki_sexp[0].text.strip() == "spki sexp"
def testUsingTestData(self):
"""Test for spki_data_from_string() using test data"""
new_spki_data = ds.spki_data_from_string(ds_data.TEST_SPKI_DATA)
assert new_spki_data.spki_sexp[0].text.strip() == "spki sexp"
assert new_spki_data.spki_sexp[1].text.strip() == "spki sexp2"
class TestPGPData:
def setup_class(self):
self.pgp_data = ds.PGPData()
def testAccessors(self):
"""Test for PGPData accessors"""
self.pgp_data.pgp_key_id = ds.PGPKeyID(text="pgp key id")
self.pgp_data.pgp_key_packet = ds.PGPKeyPacket(text="pgp key packet")
new_pgp_data = ds.pgp_data_from_string(self.pgp_data.to_string())
assert isinstance(new_pgp_data.pgp_key_id, ds.PGPKeyID)
assert isinstance(new_pgp_data.pgp_key_packet, ds.PGPKeyPacket)
assert new_pgp_data.pgp_key_id.text.strip() == "pgp key id"
assert new_pgp_data.pgp_key_packet.text.strip() == "pgp key packet"
def testUsingTestData(self):
"""Test for pgp_data_from_string() using test data"""
new_pgp_data = ds.pgp_data_from_string(ds_data.TEST_PGP_DATA)
assert isinstance(new_pgp_data.pgp_key_id, ds.PGPKeyID)
assert isinstance(new_pgp_data.pgp_key_packet, ds.PGPKeyPacket)
assert new_pgp_data.pgp_key_id.text.strip() == "pgp key id"
assert new_pgp_data.pgp_key_packet.text.strip() == "pgp key packet"
class TestX509IssuerSerial:
def setup_class(self):
self.x509_issuer_serial = ds.X509IssuerSerial()
def testAccessors(self):
"""Test for X509IssuerSerial accessors"""
self.x509_issuer_serial.x509_issuer_name = ds.X509IssuerName(
text="issuer name")
self.x509_issuer_serial.x509_issuer_number = ds.X509IssuerNumber(text="1")
new_x509_issuer_serial = ds.x509_issuer_serial_from_string(
self.x509_issuer_serial.to_string())
assert new_x509_issuer_serial.x509_issuer_name.text.strip() == \
"issuer name"
assert new_x509_issuer_serial.x509_issuer_number.text.strip() == "1"
def testUsingTestData(self):
"""Test for x509_issuer_serial_from_string() using test data"""
new_x509_issuer_serial = ds.x509_issuer_serial_from_string(
ds_data.TEST_X509_ISSUER_SERIAL)
assert new_x509_issuer_serial.x509_issuer_name.text.strip() == \
"issuer name"
assert new_x509_issuer_serial.x509_issuer_number.text.strip() == "1"
class TestX509Data:
def setup_class(self):
self.x509_data = ds.X509Data()
def testAccessors(self):
"""Test for X509Data accessors"""
self.x509_data.x509_issuer_serial.append(ds.x509_issuer_serial_from_string(
ds_data.TEST_X509_ISSUER_SERIAL))
self.x509_data.x509_ski.append(ds.X509SKI(text="x509 ski"))
self.x509_data.x509_subject_name.append(ds.X509SubjectName(
text="x509 subject name"))
self.x509_data.x509_certificate.append(ds.X509Certificate(
text="x509 certificate"))
self.x509_data.x509_crl.append(ds.X509CRL(text="x509 crl"))
new_x509_data = ds.x509_data_from_string(self.x509_data.to_string())
assert isinstance(new_x509_data.x509_issuer_serial[0],
ds.X509IssuerSerial)
assert new_x509_data.x509_ski[0].text.strip() == "x509 ski"
assert isinstance(new_x509_data.x509_ski[0], ds.X509SKI)
assert new_x509_data.x509_subject_name[0].text.strip() == \
"x509 subject name"
assert isinstance(new_x509_data.x509_subject_name[0],
ds.X509SubjectName)
assert new_x509_data.x509_certificate[0].text.strip() == \
"x509 certificate"
assert isinstance(new_x509_data.x509_certificate[0],
ds.X509Certificate)
assert new_x509_data.x509_crl[0].text.strip() == "x509 crl"
assert isinstance(new_x509_data.x509_crl[0],ds.X509CRL)
def testUsingTestData(self):
"""Test for x509_data_from_string() using test data"""
new_x509_data = ds.x509_data_from_string(ds_data.TEST_X509_DATA)
assert isinstance(new_x509_data.x509_issuer_serial[0],
ds.X509IssuerSerial)
assert new_x509_data.x509_ski[0].text.strip() == "x509 ski"
assert isinstance(new_x509_data.x509_ski[0], ds.X509SKI)
assert new_x509_data.x509_subject_name[0].text.strip() == \
"x509 subject name"
assert isinstance(new_x509_data.x509_subject_name[0],
ds.X509SubjectName)
assert new_x509_data.x509_certificate[0].text.strip() == \
"x509 certificate"
assert isinstance(new_x509_data.x509_certificate[0],
ds.X509Certificate)
assert new_x509_data.x509_crl[0].text.strip() == "x509 crl"
assert isinstance(new_x509_data.x509_crl[0],ds.X509CRL)
class TestTransform:
def setup_class(self):
self.transform = ds.Transform()
def testAccessors(self):
"""Test for Transform accessors"""
self.transform.xpath.append(ds.XPath(text="xpath"))
self.transform.algorithm = ds.TRANSFORM_ENVELOPED
new_transform = ds.transform_from_string(self.transform.to_string())
assert isinstance(new_transform.xpath[0], ds.XPath)
assert new_transform.xpath[0].text.strip() == "xpath"
assert new_transform.algorithm == ds.TRANSFORM_ENVELOPED
def testUsingTestData(self):
"""Test for transform_from_string() using test data"""
new_transform = ds.transform_from_string(ds_data.TEST_TRANSFORM)
assert isinstance(new_transform.xpath[0], ds.XPath)
assert new_transform.xpath[0].text.strip() == "xpath"
assert new_transform.algorithm == ds.TRANSFORM_ENVELOPED
class TestTransforms:
def setup_class(self):
self.transforms = ds.Transforms()
def testAccessors(self):
"""Test for Transforms accessors"""
self.transforms.transform.append(
ds.transform_from_string(ds_data.TEST_TRANSFORM))
self.transforms.transform.append(
ds.transform_from_string(ds_data.TEST_TRANSFORM))
new_transforms = ds.transforms_from_string(self.transforms.to_string())
assert isinstance(new_transforms.transform[0], ds.Transform)
assert isinstance(new_transforms.transform[1], ds.Transform)
assert new_transforms.transform[0].algorithm == \
ds.TRANSFORM_ENVELOPED
assert new_transforms.transform[1].algorithm == \
ds.TRANSFORM_ENVELOPED
assert new_transforms.transform[0].xpath[0].text.strip() == "xpath"
assert new_transforms.transform[1].xpath[0].text.strip() == "xpath"
def testUsingTestData(self):
"""Test for transform_from_string() using test data"""
new_transforms = ds.transforms_from_string(ds_data.TEST_TRANSFORMS)
assert isinstance(new_transforms.transform[0], ds.Transform)
assert isinstance(new_transforms.transform[1], ds.Transform)
assert new_transforms.transform[0].algorithm == \
ds.TRANSFORM_ENVELOPED
assert new_transforms.transform[1].algorithm == \
ds.TRANSFORM_ENVELOPED
assert new_transforms.transform[0].xpath[0].text.strip() == "xpath"
assert new_transforms.transform[1].xpath[0].text.strip() == "xpath"
class TestRetrievalMethod:
def setup_class(self):
self.retrieval_method = ds.RetrievalMethod()
def testAccessors(self):
"""Test for RetrievalMethod accessors"""
self.retrieval_method.uri = "http://www.example.com/URI"
self.retrieval_method.type = "http://www.example.com/Type"
self.retrieval_method.transforms.append(ds.transforms_from_string(
ds_data.TEST_TRANSFORMS))
new_retrieval_method = ds.retrieval_method_from_string(
self.retrieval_method.to_string())
assert new_retrieval_method.uri == "http://www.example.com/URI"
assert new_retrieval_method.type == "http://www.example.com/Type"
assert isinstance(new_retrieval_method.transforms[0], ds.Transforms)
def testUsingTestData(self):
"""Test for retrieval_method_from_string() using test data"""
new_retrieval_method = ds.retrieval_method_from_string(
ds_data.TEST_RETRIEVAL_METHOD)
assert new_retrieval_method.uri == "http://www.example.com/URI"
assert new_retrieval_method.type == "http://www.example.com/Type"
assert isinstance(new_retrieval_method.transforms[0], ds.Transforms)
class TestRSAKeyValue:
def setup_class(self):
self.rsa_key_value = ds.RSAKeyValue()
def testAccessors(self):
"""Test for RSAKeyValue accessors"""
self.rsa_key_value.modulus = ds.Modulus(text="modulus")
self.rsa_key_value.exponent = ds.Exponent(text="exponent")
new_rsa_key_value = ds.rsa_key_value_from_string(self.rsa_key_value.to_string())
assert isinstance(new_rsa_key_value.modulus, ds.Modulus)
assert isinstance(new_rsa_key_value.exponent, ds.Exponent)
assert new_rsa_key_value.modulus.text.strip() == "modulus"
assert new_rsa_key_value.exponent.text.strip() == "exponent"
def testUsingTestData(self):
"""Test for rsa_key_value_from_string() using test data"""
new_rsa_key_value = ds.rsa_key_value_from_string(
ds_data.TEST_RSA_KEY_VALUE)
assert isinstance(new_rsa_key_value.modulus, ds.Modulus)
assert isinstance(new_rsa_key_value.exponent, ds.Exponent)
assert new_rsa_key_value.modulus.text.strip() == "modulus"
assert new_rsa_key_value.exponent.text.strip() == "exponent"
class TestDSAKeyValue:
def setup_class(self):
self.dsa_key_value = ds.DSAKeyValue()
def testAccessors(self):
"""Test for DSAKeyValue accessors"""
self.dsa_key_value.p = ds.DsP(text="p")
self.dsa_key_value.q = ds.DsQ(text="q")
self.dsa_key_value.g = ds.DsG(text="g")
self.dsa_key_value.y = ds.DsY(text="y")
self.dsa_key_value.j = ds.DsJ(text="j")
self.dsa_key_value.seed = ds.Seed(text="seed")
self.dsa_key_value.pgen_counter = ds.PgenCounter(text="pgen counter")
new_dsa_key_value = ds.dsa_key_value_from_string(self.dsa_key_value.to_string())
assert isinstance(new_dsa_key_value.p, ds.DsP)
assert isinstance(new_dsa_key_value.q, ds.DsQ)
assert isinstance(new_dsa_key_value.g, ds.DsG)
assert isinstance(new_dsa_key_value.y, ds.DsY)
assert isinstance(new_dsa_key_value.j, ds.DsJ)
assert isinstance(new_dsa_key_value.seed, ds.Seed)
assert isinstance(new_dsa_key_value.pgen_counter, ds.PgenCounter)
assert new_dsa_key_value.p.text.strip() == "p"
assert new_dsa_key_value.q.text.strip() == "q"
assert new_dsa_key_value.g.text.strip() == "g"
assert new_dsa_key_value.y.text.strip() == "y"
assert new_dsa_key_value.j.text.strip() == "j"
assert new_dsa_key_value.seed.text.strip() == "seed"
assert new_dsa_key_value.pgen_counter.text.strip() == "pgen counter"
def testUsingTestData(self):
"""Test for dsa_key_value_from_string() using test data"""
new_dsa_key_value = ds.dsa_key_value_from_string(
ds_data.TEST_DSA_KEY_VALUE)
assert isinstance(new_dsa_key_value.p, ds.DsP)
assert isinstance(new_dsa_key_value.q, ds.DsQ)
assert isinstance(new_dsa_key_value.g, ds.DsG)
assert isinstance(new_dsa_key_value.y, ds.DsY)
assert isinstance(new_dsa_key_value.j, ds.DsJ)
assert isinstance(new_dsa_key_value.seed, ds.Seed)
assert isinstance(new_dsa_key_value.pgen_counter, ds.PgenCounter)
assert new_dsa_key_value.p.text.strip() == "p"
assert new_dsa_key_value.q.text.strip() == "q"
assert new_dsa_key_value.g.text.strip() == "g"
assert new_dsa_key_value.y.text.strip() == "y"
assert new_dsa_key_value.j.text.strip() == "j"
assert new_dsa_key_value.seed.text.strip() == "seed"
assert new_dsa_key_value.pgen_counter.text.strip() == "pgen counter"
class TestKeyValue:
def setup_class(self):
self.key_value = ds.KeyValue()
def testAccessors(self):
"""Test for KeyValue accessors"""
self.key_value.dsa_key_value = ds.dsa_key_value_from_string(
ds_data.TEST_DSA_KEY_VALUE)
new_key_value = ds.key_value_from_string(self.key_value.to_string())
assert isinstance(new_key_value.dsa_key_value, ds.DSAKeyValue)
self.key_value.dsa_key_value = None
self.key_value.rsa_key_value = ds.rsa_key_value_from_string(
ds_data.TEST_RSA_KEY_VALUE)
new_key_value = ds.key_value_from_string(self.key_value.to_string())
assert isinstance(new_key_value.rsa_key_value, ds.RSAKeyValue)
def testUsingTestData(self):
"""Test for key_value_from_string() using test data"""
new_key_value = ds.key_value_from_string(ds_data.TEST_KEY_VALUE1)
assert isinstance(new_key_value.dsa_key_value, ds.DSAKeyValue)
self.key_value.dsa_key_value = None
self.key_value.rsa_key_value = ds.rsa_key_value_from_string(
ds_data.TEST_RSA_KEY_VALUE)
new_key_value = ds.key_value_from_string(ds_data.TEST_KEY_VALUE2)
assert isinstance(new_key_value.rsa_key_value, ds.RSAKeyValue)
class TestKeyName:
def setup_class(self):
self.key_name = ds.KeyName()
def testAccessors(self):
"""Test for KeyName accessors"""
self.key_name.text = "key name"
new_key_name = ds.key_name_from_string(self.key_name.to_string())
assert new_key_name.text.strip() == "key name"
def testUsingTestData(self):
"""Test for key_name_from_string() using test data"""
new_key_name = ds.key_name_from_string(ds_data.TEST_KEY_NAME)
assert new_key_name.text.strip() == "key name"
class TestKeyInfo:
def setup_class(self):
self.key_info = ds.KeyInfo()
def testAccessors(self):
"""Test for KeyInfo accessors"""
self.key_info.key_name.append(
ds.key_name_from_string(ds_data.TEST_KEY_NAME))
self.key_info.key_value.append(
ds.key_value_from_string(ds_data.TEST_KEY_VALUE1))
self.key_info.retrieval_method.append(
ds.retrieval_method_from_string(ds_data.TEST_RETRIEVAL_METHOD))
self.key_info.x509_data.append(
ds.x509_data_from_string(ds_data.TEST_X509_DATA))
self.key_info.pgp_data.append(
ds.pgp_data_from_string(ds_data.TEST_PGP_DATA))
self.key_info.spki_data.append(
ds.spki_data_from_string(ds_data.TEST_SPKI_DATA))
self.key_info.mgmt_data.append(
ds.mgmt_data_from_string(ds_data.TEST_MGMT_DATA))
self.key_info.identifier = "id"
new_key_info = ds.key_info_from_string(self.key_info.to_string())
assert isinstance(new_key_info.key_name[0], ds.KeyName)
assert isinstance(new_key_info.key_value[0], ds.KeyValue)
assert isinstance(new_key_info.retrieval_method[0],
ds.RetrievalMethod)
assert isinstance(new_key_info.x509_data[0], ds.X509Data)
assert isinstance(new_key_info.pgp_data[0], ds.PGPData)
assert isinstance(new_key_info.spki_data[0], ds.SPKIData)
assert isinstance(new_key_info.mgmt_data[0], ds.MgmtData)
assert new_key_info.identifier == "id"
def testUsingTestData(self):
"""Test for key_info_from_string() using test data"""
new_key_info = ds.key_info_from_string(ds_data.TEST_KEY_INFO)
assert isinstance(new_key_info.key_name[0], ds.KeyName)
assert isinstance(new_key_info.key_value[0], ds.KeyValue)
assert isinstance(new_key_info.retrieval_method[0],
ds.RetrievalMethod)
assert isinstance(new_key_info.x509_data[0], ds.X509Data)
assert isinstance(new_key_info.pgp_data[0], ds.PGPData)
assert isinstance(new_key_info.spki_data[0], ds.SPKIData)
assert isinstance(new_key_info.mgmt_data[0], ds.MgmtData)
assert new_key_info.identifier == "id"
class TestDigestValue:
def setup_class(self):
self.digest_value = ds.DigestValue()
def testAccessors(self):
"""Test for DigestValue accessors"""
self.digest_value.text = "digest value"
new_digest_value = ds.digest_value_from_string(self.digest_value.to_string())
assert new_digest_value.text.strip() == "digest value"
def testUsingTestData(self):
"""Test for digest_value_from_string() using test data"""
new_digest_value = ds.digest_value_from_string(ds_data.TEST_DIGEST_VALUE)
assert new_digest_value.text.strip() == "digest value"
class TestDigestMethod:
def setup_class(self):
self.digest_method = ds.DigestMethod()
def testAccessors(self):
"""Test for DigestMethod accessors"""
self.digest_method.algorithm = ds.DIGEST_SHA1
new_digest_method = ds.digest_method_from_string(
self.digest_method.to_string())
assert new_digest_method.algorithm == ds.DIGEST_SHA1
def testUsingTestData(self):
"""Test for digest_method_from_string() using test data"""
new_digest_method = ds.digest_method_from_string(
ds_data.TEST_DIGEST_METHOD)
assert new_digest_method.algorithm == ds.DIGEST_SHA1
class TestReference:
def setup_class(self):
self.reference = ds.Reference()
def testAccessors(self):
"""Test for Reference accessors"""
self.reference.transforms.append(ds.transforms_from_string(
ds_data.TEST_TRANSFORMS))
self.reference.digest_method.append(ds.digest_method_from_string(
ds_data.TEST_DIGEST_METHOD))
self.reference.digest_value.append(ds.digest_value_from_string(
ds_data.TEST_DIGEST_VALUE))
self.reference.identifier = "id"
self.reference.uri = "http://www.example.com/URI"
self.reference.type = "http://www.example.com/Type"
new_reference = ds.reference_from_string(self.reference.to_string())
assert isinstance(new_reference.transforms[0], ds.Transforms)
assert isinstance(new_reference.digest_method[0], ds.DigestMethod)
assert isinstance(new_reference.digest_value[0], ds.DigestValue)
assert new_reference.identifier == "id"
assert new_reference.uri == "http://www.example.com/URI"
assert new_reference.type == "http://www.example.com/Type"
def testUsingTestData(self):
"""Test for reference_from_string() using test data"""
new_reference = ds.reference_from_string(ds_data.TEST_REFERENCE)
assert isinstance(new_reference.transforms[0], ds.Transforms)
assert isinstance(new_reference.digest_method[0], ds.DigestMethod)
assert isinstance(new_reference.digest_value[0], ds.DigestValue)
assert new_reference.identifier == "id"
assert new_reference.uri == "http://www.example.com/URI"
assert new_reference.type == "http://www.example.com/Type"
class TestSignatureMethod:
def setup_class(self):
self.signature_method = ds.SignatureMethod()
def testAccessors(self):
"""Test for SignatureMethod accessors"""
self.signature_method.algorithm = ds.SIG_RSA_SHA1
self.signature_method.hmac_output_length = ds.HMACOutputLength(text="8")
new_signature_method = ds.signature_method_from_string(
self.signature_method.to_string())
assert isinstance(new_signature_method.hmac_output_length,
ds.HMACOutputLength)
assert new_signature_method.hmac_output_length.text.strip() == "8"
assert new_signature_method.algorithm == ds.SIG_RSA_SHA1
def testUsingTestData(self):
"""Test for signature_method_from_string() using test data"""
new_signature_method = ds.signature_method_from_string(
ds_data.TEST_SIGNATURE_METHOD)
assert isinstance(new_signature_method.hmac_output_length,
ds.HMACOutputLength)
assert new_signature_method.hmac_output_length.text.strip() == "8"
assert new_signature_method.algorithm == ds.SIG_RSA_SHA1
class TestCanonicalizationMethod:
def setup_class(self):
self.canonicalization_method = ds.CanonicalizationMethod()
def testAccessors(self):
"""Test for CanonicalizationMethod accessors"""
self.canonicalization_method.algorithm = ds.C14N_WITH_C
new_canonicalization_method = ds.canonicalization_method_from_string(
self.canonicalization_method.to_string())
assert new_canonicalization_method.algorithm == ds.C14N_WITH_C
def testUsingTestData(self):
"""Test for canonicalization_method_from_string() using test data"""
new_canonicalization_method = ds.canonicalization_method_from_string(
ds_data.TEST_CANONICALIZATION_METHOD)
assert new_canonicalization_method.algorithm == ds.C14N_WITH_C
class TestSignedInfo:
def setup_class(self):
self.si = ds.SignedInfo()
def testAccessors(self):
"""Test for SignedInfo accessors"""
self.si.identifier = "id"
self.si.canonicalization_method = ds.canonicalization_method_from_string(
ds_data.TEST_CANONICALIZATION_METHOD)
self.si.signature_method = ds.signature_method_from_string(
ds_data.TEST_SIGNATURE_METHOD)
self.si.reference.append(ds.reference_from_string(
ds_data.TEST_REFERENCE))
new_si = ds.signed_info_from_string(self.si.to_string())
assert new_si.identifier == "id"
assert isinstance(new_si.canonicalization_method,
ds.CanonicalizationMethod)
assert isinstance(new_si.signature_method, ds.SignatureMethod)
assert isinstance(new_si.reference[0], ds.Reference)
def testUsingTestData(self):
"""Test for signed_info_from_string() using test data"""
new_si = ds.signed_info_from_string(ds_data.TEST_SIGNED_INFO)
assert new_si.identifier == "id"
assert isinstance(new_si.canonicalization_method,
ds.CanonicalizationMethod)
assert isinstance(new_si.signature_method, ds.SignatureMethod)
assert isinstance(new_si.reference[0], ds.Reference)
class TestSignatureValue:
def setup_class(self):
self.signature_value = ds.SignatureValue()
def testAccessors(self):
"""Test for SignatureValue accessors"""
self.signature_value.identifier = "id"
self.signature_value.text = "signature value"
new_signature_value = ds.signature_value_from_string(
self.signature_value.to_string())
assert new_signature_value.identifier == "id"
assert new_signature_value.text.strip() == "signature value"
def testUsingTestData(self):
"""Test for signature_value_from_string() using test data"""
new_signature_value = ds.signature_value_from_string(
ds_data.TEST_SIGNATURE_VALUE)
assert new_signature_value.identifier == "id"
assert new_signature_value.text.strip() == "signature value"
class TestSignature:
def setup_class(self):
self.signature = ds.Signature()
def testAccessors(self):
"""Test for Signature accessors"""
self.signature.id = "id"
self.signature.signed_info = ds.signed_info_from_string(
ds_data.TEST_SIGNED_INFO)
self.signature.signature_value = ds.signature_value_from_string(
ds_data.TEST_SIGNATURE_VALUE)
self.signature.key_info = ds.key_info_from_string(ds_data.TEST_KEY_INFO)
self.signature.object.append(ds.object_from_string(ds_data.TEST_OBJECT))
new_signature = ds.signature_from_string(self.signature.to_string())
assert new_signature.id == "id"
assert isinstance(new_signature.signed_info, ds.SignedInfo)
assert isinstance(new_signature.signature_value, ds.SignatureValue)
assert isinstance(new_signature.key_info, ds.KeyInfo)
assert isinstance(new_signature.object[0], ds.Object)
def testUsingTestData(self):
"""Test for signature_value_from_string() using test data"""
new_signature = ds.signature_from_string(ds_data.TEST_SIGNATURE)
assert new_signature.id == "id"
assert isinstance(new_signature.signed_info, ds.SignedInfo)
assert isinstance(new_signature.signature_value, ds.SignatureValue)
assert isinstance(new_signature.key_info, ds.KeyInfo)
assert isinstance(new_signature.object[0], ds.Object)
if __name__ == '__main__':
unittest.main()

View File

@@ -1,175 +0,0 @@
import saml2
import xmlenc
import xmldsig
data1 = """<?xml version='1.0'?>
<EncryptedData xmlns='http://www.w3.org/2001/04/xmlenc#'
MimeType='text/xml'>
<CipherData>
<CipherValue>A23B45C56</CipherValue>
</CipherData>
</EncryptedData>"""
def test_1():
ed = xmlenc.encrypted_data_from_string(data1)
assert ed
assert ed.mime_type == "text/xml"
assert len(ed.cipher_data) == 1
cd = ed.cipher_data[0]
assert len(cd.cipher_value) == 1
assert cd.cipher_value[0].text == "A23B45C56"
data2 = """<EncryptedData xmlns='http://www.w3.org/2001/04/xmlenc#'
Type='http://www.w3.org/2001/04/xmlenc#Element'>
<EncryptionMethod
Algorithm='http://www.w3.org/2001/04/xmlenc#tripledes-cbc'/>
<ds:KeyInfo xmlns:ds='http://www.w3.org/2000/09/xmldsig#'>
<ds:KeyName>John Smith</ds:KeyName>
</ds:KeyInfo>
<CipherData><CipherValue>DEADBEEF</CipherValue></CipherData>
</EncryptedData>"""
def test_2():
ed = xmlenc.encrypted_data_from_string(data2)
assert ed
print ed
assert ed.typ == "http://www.w3.org/2001/04/xmlenc#Element"
assert len(ed.encryption_method) == 1
em = ed.encryption_method[0]
assert em.algorithm == 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'
assert len(ed.key_info) == 1
ki = ed.key_info[0]
assert ki.key_name[0].text == "John Smith"
assert len(ed.cipher_data) == 1
cd = ed.cipher_data[0]
assert len(cd.cipher_value) == 1
assert cd.cipher_value[0].text == "DEADBEEF"
data3 = """<EncryptedData Id='ED'
xmlns='http://www.w3.org/2001/04/xmlenc#'>
<EncryptionMethod
Algorithm='http://www.w3.org/2001/04/xmlenc#aes128-cbc'/>
<ds:KeyInfo xmlns:ds='http://www.w3.org/2000/09/xmldsig#'>
<ds:RetrievalMethod URI='#EK'
Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey"/>
<ds:KeyName>Sally Doe</ds:KeyName>
</ds:KeyInfo>
<CipherData><CipherValue>DEADBEEF</CipherValue></CipherData>
</EncryptedData>"""
def test_3():
ed = xmlenc.encrypted_data_from_string(data3)
assert ed
print ed
assert len(ed.encryption_method) == 1
em = ed.encryption_method[0]
assert em.algorithm == 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'
assert len(ed.key_info) == 1
ki = ed.key_info[0]
assert ki.key_name[0].text == "Sally Doe"
assert len(ki.retrieval_method) == 1
rm = ki.retrieval_method[0]
assert rm.uri == "#EK"
assert rm.type == "http://www.w3.org/2001/04/xmlenc#EncryptedKey"
assert len(ed.cipher_data) == 1
cd = ed.cipher_data[0]
assert len(cd.cipher_value) == 1
assert cd.cipher_value[0].text == "DEADBEEF"
data4 = """<EncryptedKey Id='EK' xmlns='http://www.w3.org/2001/04/xmlenc#'>
<EncryptionMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
<ds:KeyInfo xmlns:ds='http://www.w3.org/2000/09/xmldsig#'>
<ds:KeyName>John Smith</ds:KeyName>
</ds:KeyInfo>
<CipherData><CipherValue>xyzabc</CipherValue></CipherData>
<ReferenceList>
<DataReference URI='#ED'/>
</ReferenceList>
<CarriedKeyName>Sally Doe</CarriedKeyName>
</EncryptedKey>"""
def test_4():
ek = xmlenc.encrypted_key_from_string(data4)
assert ek
print ek
assert len(ek.encryption_method) == 1
em = ek.encryption_method[0]
assert em.algorithm == 'http://www.w3.org/2001/04/xmlenc#rsa-1_5'
assert len(ek.key_info) == 1
ki = ek.key_info[0]
assert ki.key_name[0].text == "John Smith"
assert len(ek.reference_list) == 1
rl = ek.reference_list[0]
assert len(rl.data_reference)
dr = rl.data_reference[0]
assert dr.uri == "#ED"
assert len(ek.cipher_data) == 1
cd = ek.cipher_data[0]
assert len(cd.cipher_value) == 1
assert cd.cipher_value[0].text == "xyzabc"
data5 = """<CipherReference URI="http://www.example.com/CipherValues.xml"
xmlns="http://www.w3.org/2001/04/xmlenc#">
<Transforms xmlns:ds='http://www.w3.org/2000/09/xmldsig#'>
<ds:Transform
Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
<ds:XPath xmlns:rep="http://www.example.org/repository">
self::text()[parent::rep:CipherValue[@Id="example1"]]
</ds:XPath>
</ds:Transform>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#base64"/>
</Transforms>
</CipherReference>"""
def test_5():
cr = xmlenc.cipher_reference_from_string(data5)
assert cr
print cr
assert len(cr.transforms) == 1
trs = cr.transforms[0]
assert len(trs.transform) == 2
tr = trs.transform[0]
assert tr.algorithm in ["http://www.w3.org/TR/1999/REC-xpath-19991116",
"http://www.w3.org/2000/09/xmldsig#base64"]
if tr.algorithm == "http://www.w3.org/2000/09/xmldsig#base64":
pass
elif tr.algorithm == "http://www.w3.org/TR/1999/REC-xpath-19991116":
assert len(tr.xpath) == 1
xp = tr.xpath[0]
assert xp.text.strip() == """self::text()[parent::rep:CipherValue[@Id="example1"]]"""
data6 = """<ReferenceList xmlns="http://www.w3.org/2001/04/xmlenc#">
<DataReference URI="#invoice34">
<ds:Transforms xmlns:ds='http://www.w3.org/2000/09/xmldsig#'>
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
<ds:XPath xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
self::xenc:EncryptedData[@Id="example1"]
</ds:XPath>
</ds:Transform>
</ds:Transforms>
</DataReference>
</ReferenceList>"""
def test_6():
rl = xmlenc.reference_list_from_string(data6)
assert rl
print rl
assert len(rl.data_reference) == 1
dr = rl.data_reference[0]
assert dr.uri == "#invoice34"
assert len(dr.extension_elements) == 1
ee = dr.extension_elements[0]
assert ee.tag == "Transforms"
assert ee.namespace == "http://www.w3.org/2000/09/xmldsig#"
trs = saml2.extension_element_to_element(ee, xmldsig.ELEMENT_FROM_STRING,
namespace=xmldsig.NAMESPACE)
assert trs
assert len(trs.transform) == 1
tr = trs.transform[0]
assert tr.algorithm == "http://www.w3.org/TR/1999/REC-xpath-19991116"
assert len(tr.xpath) == 1
assert tr.xpath[0].text.strip() == """self::xenc:EncryptedData[@Id="example1"]"""

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
from saml2 import samlp, BINDING_HTTP_POST
from saml2 import saml, utils, config, class_name, make_instance
from saml2 import saml, config, class_name, make_instance
from saml2.server import Server
from saml2.authnresponse import authn_response
@@ -55,6 +55,7 @@ class TestAuthnResponse:
assert self.ar.came_from == 'http://localhost:8088/sso'
assert self.ar.session_id() == "12"
assert self.ar.ava == {'eduPersonEntitlement': ['Jeter'] }
assert self.ar.name_id
assert self.ar.issuer() == 'urn:mace:example.com:saml:roland:idp'
def test_verify_signed_1(self):
@@ -72,18 +73,20 @@ class TestAuthnResponse:
assert self.ar.session_id() == "12"
assert self.ar.ava == {'eduPersonEntitlement': ['Jeter'] }
assert self.ar.issuer() == 'urn:mace:example.com:saml:roland:idp'
assert self.ar.name_id
def test_parse_2(self):
xml_response = open(XML_RESPONSE_FILE).read()
ID = "bahigehogffohiphlfmplepdpcohkhhmheppcdie"
self.ar.outstanding_queries = {ID: "http://localhost:8088/foo"}
self.ar.requestor = "xenosmilus.umdc.umu.se"
self.ar.timeslack = 20000000
print self.ar.__dict__
# roughly a year, should create the response on the fly
self.ar.timeslack = 31536000
self.ar.loads(xml_response, decode=False)
self.ar.verify()
print self.ar
print self.ar.__dict__
assert self.ar.came_from == 'http://localhost:8088/foo'
assert self.ar.session_id() == ID
assert self.ar.name_id

View File

@@ -3,9 +3,10 @@
from saml2.server import Server, Identifier
from saml2 import server, make_instance
from saml2 import samlp, saml, client, utils, config
from saml2.utils import OtherError
from saml2.utils import do_attribute_statement
from saml2 import samlp, saml, client, config
from saml2 import s_utils
from saml2.s_utils import OtherError
from saml2.s_utils import do_attribute_statement, factory
from py.test import raises
import shelve
import re
@@ -25,7 +26,7 @@ class TestServer1():
self.client = client.Saml2Client({},conf)
def test_issuer(self):
issuer = make_instance( saml.Issuer, self.server.issuer())
issuer = self.server.issuer()
assert isinstance(issuer, saml.Issuer)
assert _eq(issuer.keyswv(), ["text","format"])
assert issuer.format == saml.NAMEID_FORMAT_ENTITY
@@ -33,27 +34,24 @@ class TestServer1():
def test_assertion(self):
tmp = utils.assertion_factory(
subject= utils.args2dict("_aaa",
name_id=saml.NAMEID_FORMAT_TRANSIENT),
attribute_statement = utils.args2dict(
attribute=[
utils.args2dict(attribute_value="Derek",
friendly_name="givenName"),
utils.args2dict(attribute_value="Jeter",
friendly_name="surName"),
]),
assertion = s_utils.assertion_factory(
subject= factory(saml.Subject, text="_aaa",
name_id=factory(saml.NameID,
format=saml.NAMEID_FORMAT_TRANSIENT)),
attribute_statement = do_attribute_statement({
("","","surName"): ("Jeter",""),
("","","givenName") :("Derek",""),
}),
issuer=self.server.issuer(),
)
assertion = make_instance(saml.Assertion, tmp)
assert _eq(assertion.keyswv(),['attribute_statement', 'issuer', 'id',
'subject', 'issue_instant', 'version'])
assert assertion.version == "2.0"
assert assertion.issuer.text == "urn:mace:example.com:saml:roland:idp"
#
assert len(assertion.attribute_statement) == 1
attribute_statement = assertion.attribute_statement[0]
assert assertion.attribute_statement
attribute_statement = assertion.attribute_statement
assert len(attribute_statement.attribute) == 2
attr0 = attribute_statement.attribute[0]
attr1 = attribute_statement.attribute[1]
@@ -70,28 +68,25 @@ class TestServer1():
subject = assertion.subject
assert _eq(subject.keyswv(),["text", "name_id"])
assert subject.text == "_aaa"
assert subject.name_id.text == saml.NAMEID_FORMAT_TRANSIENT
assert subject.name_id.format == saml.NAMEID_FORMAT_TRANSIENT
def test_response(self):
tmp = utils.response_factory(
response = s_utils.response_factory(
in_response_to="_012345",
destination="https:#www.example.com",
status=utils.success_status_factory(),
assertion=utils.assertion_factory(
subject = utils.args2dict("_aaa",
status=s_utils.success_status_factory(),
assertion=s_utils.assertion_factory(
subject = factory( saml.Subject, text="_aaa",
name_id=saml.NAMEID_FORMAT_TRANSIENT),
attribute_statement = [
utils.args2dict(attribute_value="Derek",
friendly_name="givenName"),
utils.args2dict(attribute_value="Jeter",
friendly_name="surName"),
],
attribute_statement = do_attribute_statement({
("","","surName"): ("Jeter",""),
("","","givenName") :("Derek",""),
}),
issuer=self.server.issuer(),
),
issuer=self.server.issuer(),
)
response = make_instance(samlp.Response, tmp)
print response.keyswv()
assert _eq(response.keyswv(),['destination', 'assertion','status',
'in_response_to', 'issue_instant',
@@ -114,7 +109,7 @@ class TestServer1():
my_name = "My real name",
)
intermed = utils.deflate_and_base64_encode(authn_request)
intermed = s_utils.deflate_and_base64_encode(authn_request)
# should raise an error because faulty spentityid
raises(OtherError, self.server.parse_authn_request, intermed)
@@ -127,14 +122,13 @@ class TestServer1():
my_name = "My real name",
)
intermed = utils.deflate_and_base64_encode(authn_request)
intermed = s_utils.deflate_and_base64_encode(authn_request)
try:
self.server.parse_authn_request(intermed)
status = None
except OtherError, oe:
print oe.args
status = make_instance(samlp.Status,
utils.status_from_exception_factory(oe))
status = s_utils.status_from_exception_factory(oe)
assert status
print status
@@ -156,8 +150,9 @@ class TestServer1():
)
print authn_request
intermed = utils.deflate_and_base64_encode(authn_request)
intermed = s_utils.deflate_and_base64_encode(authn_request)
response = self.server.parse_authn_request(intermed)
# returns a dictionary
print response
assert response["consumer_url"] == "http://localhost:8087/"
assert response["id"] == "1"
@@ -185,12 +180,13 @@ class TestServer1():
assert resp.status
assert resp.status.status_code.value == samlp.STATUS_SUCCESS
assert resp.assertion
assert len(resp.assertion) == 1
assertion = resp.assertion[0]
assert len(assertion.authn_statement) == 1
assert resp.assertion
assertion = resp.assertion
print assertion
assert assertion.authn_statement
assert assertion.conditions
assert len(assertion.attribute_statement) == 1
attribute_statement = assertion.attribute_statement[0]
assert assertion.attribute_statement
attribute_statement = assertion.attribute_statement
print attribute_statement
assert len(attribute_statement.attribute) == 1
attribute = attribute_statement.attribute[0]
@@ -200,11 +196,11 @@ class TestServer1():
assert attribute.name_format == "urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
value = attribute.attribute_value[0]
assert value.text.strip() == "Short stop"
assert value.type == "xs:string"
assert value.get_type() == "xs:string"
assert assertion.subject
assert assertion.subject.name_id
assert len(assertion.subject.subject_confirmation) == 1
confirmation = assertion.subject.subject_confirmation[0]
assert assertion.subject.subject_confirmation
confirmation = assertion.subject.subject_confirmation
print confirmation.keyswv()
print confirmation.subject_confirmation_data
assert confirmation.subject_confirmation_data.in_response_to == "12"
@@ -227,7 +223,7 @@ class TestServer1():
assert not resp.assertion
def test_sso_failure_response(self):
exc = utils.MissingValue("eduPersonAffiliation missing")
exc = s_utils.MissingValue("eduPersonAffiliation missing")
resp = self.server.error_response( "http://localhost:8087/", "12",
"urn:mace:example.com:saml:roland:sp", exc )
@@ -253,10 +249,8 @@ class TestServer1():
resp_str = self.server.authn_response(ava,
"1", "http://local:8087/",
"urn:mace:example.com:saml:roland:sp",
make_instance(samlp.NameIDPolicy,
utils.args2dict(
format=saml.NAMEID_FORMAT_TRANSIENT,
allow_create="true")),
samlp.NameIDPolicy(format=saml.NAMEID_FORMAT_TRANSIENT,
allow_create="true"),
"foba0001@example.com")
response = samlp.response_from_string("\n".join(resp_str))
@@ -324,12 +318,12 @@ class TestServer2():
assert response.version == "2.0"
assert response.issuer.text == "urn:mace:example.com:saml:roland:idpr"
assert response.status.status_code.value == samlp.STATUS_SUCCESS
assert len(response.assertion) == 1
assertion = response.assertion[0]
assert response.assertion
assertion = response.assertion
assert assertion.version == "2.0"
subject = assertion.subject
assert subject.name_id.format == saml.NAMEID_FORMAT_TRANSIENT
assert len(subject.subject_confirmation) == 1
subject_confirmation = subject.subject_confirmation[0]
assert subject.subject_confirmation
subject_confirmation = subject.subject_confirmation
assert subject_confirmation.subject_confirmation_data.in_response_to == "aaa"

View File

@@ -2,12 +2,14 @@
# -*- coding: utf-8 -*-
import base64
from urlparse import urlparse, parse_qs
from saml2.client import Saml2Client
from saml2 import samlp, client, BINDING_HTTP_POST
from saml2 import saml, utils, config, class_name, make_instance
from saml2 import saml, s_utils, config, class_name
#from saml2.sigver import correctly_signed_authn_request, verify_signature
from saml2.server import Server
from saml2.s_utils import decode_base64_and_inflate
import os
@@ -27,6 +29,8 @@ def ava(attribute_statement):
result[name].append(value.text.strip())
return result
def _leq(l1, l2):
return set(l1) == set(l2)
# def test_parse_3():
# xml_response = open(XML_RESPONSE_FILE3).read()
@@ -41,7 +45,7 @@ def ava(attribute_statement):
# assert False
REQ1 = """<?xml version='1.0' encoding='UTF-8'?>
<ns0:AttributeQuery Destination="https://idp.example.com/idp/" ID="1" IssueInstant="%s" Version="2.0" xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol"><ns1:Issuer xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion">http://vo.example.com/sp1</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>"""
<ns0:AttributeQuery Destination="https://idp.example.com/idp/" ID="1" 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>"""
class TestClient:
@@ -63,6 +67,7 @@ class TestClient:
nameid_format=saml.NAMEID_FORMAT_PERSISTENT)
str = "%s" % req.to_string()
print str
print REQ1 % req.issue_instant
assert str == REQ1 % req.issue_instant
assert req.destination == "https://idp.example.com/idp/"
assert req.id == "1"
@@ -72,7 +77,7 @@ class TestClient:
assert name_id.format == saml.NAMEID_FORMAT_PERSISTENT
assert name_id.text == "E8042FB4-4D5B-48C3-8E14-8EDD852790DD"
issuer = req.issuer
assert issuer.text == "http://vo.example.com/sp1"
assert issuer.text == "urn:mace:example.com:saml:roland:sp"
def test_create_attribute_query2(self):
req = self.client.create_attribute_query("1",
@@ -130,7 +135,7 @@ class TestClient:
assert req.id == "1"
assert req.version == "2.0"
assert req.issue_instant
assert req.issuer.text == "urn:mace:umu.se:saml/rolandsp"
assert req.issuer.text == "urn:mace:example.com:saml:roland:sp"
nameid = req.subject.name_id
assert nameid.format == saml.NAMEID_FORMAT_TRANSIENT
assert nameid.text == "_e7b68a04488f715cda642fbdd90099f5"
@@ -146,23 +151,22 @@ class TestClient:
assert req == None
def test_idp_entry(self):
idp_entry = make_instance( samlp.IDPEntry,
self.client.idp_entry(name="Umeå Universitet",
location="https://idp.umu.se/"))
idp_entry = self.client.idp_entry(name="Umeå Universitet",
location="https://idp.umu.se/")
assert idp_entry.name == "Umeå Universitet"
assert idp_entry.loc == "https://idp.umu.se/"
def test_scope(self):
scope = make_instance(samlp.Scoping, self.client.scoping(
[self.client.idp_entry(name="Umeå Universitet",
location="https://idp.umu.se/")]))
entity_id = "urn:mace:example.com:saml:roland:idp"
locs = self.client.metadata.single_sign_on_services(entity_id)
scope = self.client.scoping_from_metadata(entity_id, locs)
assert scope.idp_list
assert len(scope.idp_list.idp_entry) == 1
idp_entry = scope.idp_list.idp_entry[0]
assert idp_entry.name == "Umeå Universitet"
assert idp_entry.loc == "https://idp.umu.se/"
assert idp_entry.name == 'Example Co'
assert idp_entry.loc == ['http://localhost:8088/sso/']
def test_create_auth_request_0(self):
ar_str = self.client.authn_request("1",
@@ -186,7 +190,7 @@ class TestClient:
assert self.client.config["virtual_organization"].keys() == [
"urn:mace:example.com:it:tek"]
ar_str = self.client.authn_request("1",
ar_str = self.client.authn_request("666",
"http://www.example.com/sso",
"http://www.example.org/service",
"urn:mace:example.org:saml:sp",
@@ -195,6 +199,7 @@ class TestClient:
ar = samlp.authn_request_from_string(ar_str)
print ar
assert ar.id == "666"
assert ar.assertion_consumer_service_url == "http://www.example.org/service"
assert ar.destination == "http://www.example.com/sso"
assert ar.protocol_binding == BINDING_HTTP_POST
@@ -234,17 +239,19 @@ class TestClient:
self.client.sec.verify_signature(ar_str, node_name=class_name(ar))
def test_response(self):
IDP = "urn:mace:example.com:saml:roland:idp"
ava = { "givenName": ["Derek"], "surname": ["Jeter"],
"mail": ["derek@nyy.mlb.com"]}
resp_str = "\n".join(self.server.authn_response(ava,
"1", "http://local:8087/",
"urn:mace:example.com:saml:roland:sp",
make_instance(samlp.NameIDPolicy,
utils.args2dict(
format=saml.NAMEID_FORMAT_TRANSIENT,
allow_create="true")),
"foba0001@example.com"))
resp_str = "\n".join(self.server.authn_response(
identity=ava,
in_response_to="1",
destination="http://local:8087/",
sp_entity_id="urn:mace:example.com:saml:roland:sp",
name_id_policy=samlp.NameIDPolicy(
format=saml.NAMEID_FORMAT_PERSISTENT),
userid="foba0001@example.com"))
resp_str = base64.encodestring(resp_str)
@@ -253,7 +260,106 @@ class TestClient:
{"1":"http://foo.example.com/service"})
assert authn_response != None
assert authn_response.issuer() == IDP
assert authn_response.response.assertion[0].issuer.text == IDP
session_info = authn_response.session_info()
assert session_info["ava"] != []
print session_info
assert session_info["ava"] == {'mail': ['derek@nyy.mlb.com'], 'givenName': ['Derek'], 'sn': ['Jeter']}
assert session_info["issuer"] == IDP
assert session_info["came_from"] == "http://foo.example.com/service"
response = samlp.response_from_string(authn_response.xmlstr)
assert response.destination == "http://local:8087/"
# One person in the cache
assert len(self.client.users.subjects()) == 1
subject_id = self.client.users.subjects()[0]
print "||||", self.client.users.get_info_from(subject_id, IDP)
# The information I have about the subject comes from one source
assert self.client.users.issuers_of_info(subject_id) == [IDP]
# --- authenticate another person
ava = { "givenName": ["Alfonson"], "surname": ["Soriano"],
"mail": ["alfonson@chc.mlb.com"]}
resp_str = "\n".join(self.server.authn_response(
identity=ava,
in_response_to="2",
destination="http://local:8087/",
sp_entity_id="urn:mace:example.com:saml:roland:sp",
name_id_policy=samlp.NameIDPolicy(
format=saml.NAMEID_FORMAT_PERSISTENT),
userid="also0001@example.com"))
resp_str = base64.encodestring(resp_str)
authn_response = self.client.response({"SAMLResponse":resp_str},
"urn:mace:example.com:saml:roland:sp",
{"2":"http://foo.example.com/service"})
# Two persons in the cache
assert len(self.client.users.subjects()) == 2
issuers = [self.client.users.issuers_of_info(s) for s in self.client.users.subjects()]
# The information I have about the subjects comes from the same source
print issuers
assert issuers == [[IDP], [IDP]]
def test_init_values(self):
print self.client.config["service"]["sp"]
spentityid = self.client._spentityid()
print spentityid
assert spentityid == "urn:mace:example.com:saml:roland:sp"
location = self.client._location()
print location
assert location == 'http://localhost:8088/sso/'
service_url = self.client._service_url()
print service_url
assert service_url == "http://lingon.catalogix.se:8087/"
my_name = self.client._my_name()
print my_name
assert my_name == "urn:mace:example.com:saml:roland:sp"
def test_authenticate(self):
(sid, response) = self.client.authenticate(
"http://www.example.com/sso",
"http://www.example.org/service",
"urn:mace:example.org:saml:sp",
"My Name",
"http://www.example.com/relay_state")
assert sid != None
assert response[0] == "Location"
o = urlparse(response[1])
qdict = parse_qs(o.query)
assert _leq(qdict.keys(), ['SAMLRequest', 'RelayState'])
saml_request = decode_base64_and_inflate(qdict["SAMLRequest"][0])
print saml_request
authnreq = samlp.authn_request_from_string(saml_request)
assert authnreq.id == sid
def test_authenticate_no_args(self):
(sid, request) = self.client.authenticate(relay_state="http://www.example.com/relay_state")
assert sid != None
assert request[0] == "Location"
o = urlparse(request[1])
qdict = parse_qs(o.query)
assert _leq(qdict.keys(), ['SAMLRequest', 'RelayState'])
saml_request = decode_base64_and_inflate(qdict["SAMLRequest"][0])
assert qdict["RelayState"][0] == "http://www.example.com/relay_state"
print saml_request
authnreq = samlp.authn_request_from_string(saml_request)
print authnreq.keyswv()
assert authnreq.id == sid
assert authnreq.destination == "http://localhost:8088/sso/"
assert authnreq.assertion_consumer_service_url == "http://lingon.catalogix.se:8087/"
assert authnreq.provider_name == "urn:mace:example.com:saml:roland:sp"
assert authnreq.protocol_binding == "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
name_id_policy = authnreq.name_id_policy
assert name_id_policy.allow_create == "true"
assert name_id_policy.format == "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
issuer = authnreq.issuer
assert issuer.text == "urn:mace:example.com:saml:roland:sp"
# def test_logout_request(self):

View File

@@ -1,10 +1,12 @@
#!/usr/bin/env python
import os
import getopt
import xmldsig as ds
from saml2 import utils, md, samlp, BINDING_HTTP_POST, BINDING_HTTP_REDIRECT
from saml2 import BINDING_SOAP, class_name, make_instance
from saml2.time_util import in_a_while
from saml2.utils import parse_attribute_map, args2dict
from saml2.s_utils import parse_attribute_map, factory
from saml2.saml import NAME_FORMAT_URI
from saml2.sigver import pre_signature_part, SecurityContext
from saml2.attribute_converter import from_local_name, ac_factory
@@ -30,155 +32,248 @@ class Usage(Exception):
DEFAULTS = {
"want_assertions_signed": "true",
"authn_requests_signed": "false",
"want_authn_requests_signed": "true",
}
ORG_ATTR_TRANSL = {
"organization_name": "name",
"organization_display_name": "display_name",
"organization_url": "url",
"organization_name": ("name", md.OrganizationName),
"organization_display_name": ("display_name", md.OrganizationDisplayName),
"organization_url": ("url", md.OrganizationURL)
}
PERSON_ATTR_TRANSL = {
"company": "company",
"given_name": "givenname",
"sur_name": "surname",
"email_address": "mail",
"telephone_number": "phone",
"type": "type",
def _localized_name(val, klass):
try:
(text,lang) = val
return klass(text=text,lang=lang)
except ValueError:
return klass(text=val)
def do_organization_info(conf):
""" decription of an organization in the configuration is
a dictionary of keys and values, where the values might be tuples.
"organization": {
"name": ("AB Exempel", "se"),
"display_name": ("AB Exempel", "se"),
"url": "http://www.example.org"
}
def _localized_name(tup):
if tup[1]:
return args2dict(tup[0],lang=tup[1])
else:
return tup[0]
def do_organization_info(conf, desc):
""" """
"""
try:
corg = conf["organization"]
dorg = desc["organization"] = {}
for (dkey, ckey) in ORG_ATTR_TRANSL.items():
org = md.Organization()
for dkey, (ckey, klass) in ORG_ATTR_TRANSL.items():
if ckey not in corg:
continue
if isinstance(corg[ckey], basestring):
dorg[dkey] = [corg[ckey]]
elif isinstance(corg[ckey], tuple):
dorg[dkey] = [_localized_name(corg[ckey])]
setattr(org, dkey, [_localized_name(corg[ckey], klass)])
elif isinstance(corg[ckey], list):
setattr(org, dkey, [_localized_name(n, klass) for n in corg[ckey]])
else:
dorg[dkey] = []
for val in corg[ckey]:
if isinstance(val,tuple):
dorg[dkey].append(_localized_name(val))
setattr(org, dkey, [_localized_name(corg[ckey], klass)])
return org
except KeyError:
return None
def do_contact_person_info(conf):
"""
"""
contact_person = md.ContactPerson
cps = []
try:
for corg in conf["contact_person"]:
cp = md.ContactPerson()
for (key, classpec) in contact_person.c_children.values():
try:
value = corg[key]
data = []
if isinstance(classpec, list):
# What if value is not a list ?
if isinstance(value, basestring):
data = [classpec[0](text=value)]
else:
dorg[dkey].append(val)
for val in value:
data.append(classpec[0](text=val))
else:
data = classpec(text=value)
setattr(cp, key, data)
except KeyError:
pass
def do_contact_person_info(conf, desc):
if "contact_person" in conf:
desc["contact_person"] = []
for corg in conf["contact_person"]:
dorg = {}
for (dkey, ckey) in PERSON_ATTR_TRANSL.items():
for (prop, classpec, req) in contact_person.c_attributes.values():
try:
dorg[dkey] = corg[ckey]
except:
# should do a check for valid value
setattr(cp, prop, corg[prop])
except KeyError:
pass
desc["contact_person"].append(dorg)
cps.append(cp)
except KeyError:
pass
return cps
def do_sp_sso_descriptor(sp, cert, acs):
desc = {
"protocol_support_enumeration": samlp.NAMESPACE,
"assertion_consumer_service": {
"binding": BINDING_HTTP_POST ,
"location": sp["url"],
"index": 0,
def do_key_descriptor(cert):
return md.KeyDescriptor(
key_info=ds.KeyInfo(
x509_data=ds.X509Data(
x509_certificate=ds.X509Certificate(text=cert)
)
)
)
def do_requested_attribute(attributes, acs, is_required="false"):
lista = []
for attr in attributes:
attr = from_local_name(acs, attr, NAME_FORMAT_URI)
args = {}
for key in attr.keyswv():
args[key] = getattr(attr,key)
args["is_required"] = is_required
lista.append(md.RequestedAttribute(**args))
return lista
ENDPOINTS = {
"sp": {
"artifact_resolution_service": (md.ArtifactResolutionService, True),
"single_logout_service": (md.SingleLogoutService, False),
"manage_name_id_service": (md.ManageNameIDService, False),
"assertion_consumer_service": (md.AssertionConsumerService, True),
},
"key_descriptor":{
"key_info": {
"x509_data": {
"x509_certificate": cert
}
}
"idp":{
"artifact_resolution_service": (md.ArtifactResolutionService, True),
"single_logout_service": (md.SingleLogoutService, False),
"manage_name_id_service": (md.ManageNameIDService, False),
"single_sign_on_service": (md.SingleSignOnService, False),
"name_id_mapping_service": (md.NameIDMappingService, False),
"assertion_id_request_service": (md.AssertionIDRequestService, False),
},
"aa":{
"artifact_resolution_service": (md.ArtifactResolutionService, True),
"single_logout_service": (md.SingleLogoutService, False),
"manage_name_id_service": (md.ManageNameIDService, False),
"assertion_id_request_service": (md.AssertionIDRequestService, False),
"attribute_service": (md.AttributeService, False)
},
}
DEFAULT_BINDING = {
"assertion_consumer_service": BINDING_HTTP_POST,
"single_sign_on_service": BINDING_HTTP_POST,
"single_logout_service": BINDING_HTTP_POST,
"attribute_service": BINDING_SOAP,
"artifact_resolution_service": BINDING_SOAP
}
def do_endpoints(conf, endpoints):
service = {}
for endpoint, (eclass, indexed) in endpoints.items():
try:
servs = []
i = 1
for args in conf[endpoint]:
if isinstance(args, basestring): # Assume it's the location
args = {"location":args, "binding": DEFAULT_BINDING[endpoint]}
if indexed:
args["index"] = "%d" % i
servs.append(factory(eclass, **args))
i += 1
service[endpoint] = servs
except KeyError:
pass
return service
def do_sp_sso_descriptor(sp, acs, cert=None):
spsso = md.SPSSODescriptor()
spsso.protocol_support_enumeration=samlp.NAMESPACE
if sp["endpoints"]:
for (endpoint, instlist) in do_endpoints(sp["endpoints"],
ENDPOINTS["sp"]).items():
setattr(spsso, endpoint, instlist)
if cert:
spsso.key_descriptor=do_key_descriptor(cert)
for key in ["want_assertions_signed", "authn_requests_signed"]:
try:
desc[key] = "%s" % sp[key]
setattr(spsso, key, "%s" % sp[key])
except KeyError:
desc[key] = DEFAULTS[key]
setattr(spsso, key, DEFAULTS[key])
requested_attribute = []
requested_attributes = []
if "required_attributes" in sp:
for attr in sp["required_attributes"]:
reqa = from_local_name(acs, attr, NAME_FORMAT_URI)
reqa["is_required"] = "true"
requested_attribute.append(reqa)
requested_attributes.extend(do_requested_attribute(
sp["required_attributes"],
acs,
is_required="true"))
if "optional_attributes" in sp:
for attr in sp["optional_attributes"]:
reqa = from_local_name(acs, attr, NAME_FORMAT_URI)
requested_attribute.append(reqa)
requested_attributes.extend(do_requested_attribute(
sp["optional_attributes"],
acs,
is_required="false"))
if requested_attribute:
desc["attribute_consuming_service"] = {
"requested_attribute": requested_attribute,
"service_name": {
"lang":"en",
"text":sp["name"],
}
}
if requested_attributes:
spsso.attribute_consuming_service = [md.AttributeConsumingService(
requested_attribute=requested_attributes,
service_name= [md.ServiceName(lang="en",text=sp["name"])]
)]
try:
spsso.attribute_consuming_service[0].service_description = [
md.ServiceDescription(text=sp["description"])]
except KeyError:
pass
if "discovery_service" in sp:
desc["extensions"] = {"extension_elements":[
{
"tag":"DiscoveryResponse",
"namespace":md.IDPDISC,
"attributes": {
"index":"1",
"binding": md.IDPDISC,
"location":sp["url"]
}
}
]}
# if "discovery_service" in sp:
# spsso.extensions= {"extension_elements":[
# {
# "tag":"DiscoveryResponse",
# "namespace":md.IDPDISC,
# "attributes": {
# "index":"1",
# "binding": md.IDPDISC,
# "location":sp["url"]
# }
# }
# ]}
return desc
return spsso
def do_idp_sso_descriptor(idp, cert):
return {
"protocol_support_enumeration": samlp.NAMESPACE,
"want_authn_requests_signed": True,
"single_sign_on_service": {
"binding": BINDING_HTTP_REDIRECT ,
"location": idp["url"],
},
"key_descriptor":{
"key_info": {
"x509_data": {
"x509_certificate": cert
}
}
},
}
def do_idp_sso_descriptor(idp, cert=None):
idpsso = md.IDPSSODescriptor()
idpsso.protocol_support_enumeration=samlp.NAMESPACE
if idp["endpoints"]:
for (endpoint, instlist) in do_endpoints(idp["endpoints"],
ENDPOINTS["idp"]).items():
setattr(idpsso, endpoint, instlist)
if cert:
idpsso.key_descriptor=do_key_descriptor(cert)
for key in ["want_authn_requests_signed"]:
try:
setattr(idpsso, key, "%s" % idp[key])
except KeyError:
setattr(idpsso, key, DEFAULTS[key])
return idpsso
def do_aa_descriptor(aa, cert):
return {
"protocol_support_enumeration": samlp.NAMESPACE,
"attribute_service": {
"binding": BINDING_SOAP ,
"location": aa["url"],
},
"key_descriptor":{
"key_info": {
"x509_data": {
"x509_certificate": cert
}
}
},
}
aa = md.AttributeAuthorityDescriptor()
aa.protocol_support_enumeration=samlp.NAMESPACE
if idp["endpoints"]:
for (endpoint, instlist) in do_endpoints(aa["endpoints"],
ENDPOINTS["aa"]).items():
setattr(aasso, endpoint, instlist)
if cert:
aa.key_descriptor=do_key_descriptor(cert)
return aa
def entity_descriptor(confd, valid_for):
mycert = "".join(open(confd["cert_file"]).readlines()[1:-1])
@@ -193,45 +288,43 @@ def entity_descriptor(confd, valid_for):
#else:
# backward = {}
ed = {
"entity_id": confd["entityid"],
}
if valid_for:
ed["valid_until"] = in_a_while(hours=valid_for)
ed = md.EntityDescriptor(entity_id=confd["entityid"])
do_organization_info(confd, ed)
do_contact_person_info(confd, ed)
if valid_for:
ed.valid_until = in_a_while(hours=valid_for)
ed.organization = do_organization_info(confd)
ed.contact_person = do_contact_person_info(confd)
if "sp" in confd["service"]:
# The SP
ed["sp_sso_descriptor"] = do_sp_sso_descriptor(confd["service"]["sp"],
mycert, attrconverters)
ed.sp_sso_descriptor = do_sp_sso_descriptor(confd["service"]["sp"],
attrconverters, mycert)
if "idp" in confd["service"]:
ed["idp_sso_descriptor"] = do_idp_sso_descriptor(
ed.idp_sso_descriptor = do_idp_sso_descriptor(
confd["service"]["idp"], mycert)
if "aa" in confd["service"]:
ed["attribute_authority_descriptor"] = do_aa_descriptor(
ed.attribute_authority_descriptor = do_aa_descriptor(
confd["service"]["aa"], mycert)
return ed
def entities_descriptor(eds, valid_for, name, id, sign, sc):
d = {"entity_descriptor": eds}
entities = md.EntitiesDescriptor(entity_descriptor= eds)
if valid_for:
d["valid_until"] = in_a_while(hours=valid_for)
entities.valid_until = in_a_while(hours=valid_for)
if name:
d["name"] = name
entities.name = name
if id:
d["id"] = id
entities.id = id
if sign:
d["signature"] = pre_signature_part(d["id"])
entities.signature = pre_signature_part(id)
statement = make_instance(md.EntitiesDescriptor, d)
if sign:
statement = sc.sign_statement_using_xmlsec("%s" % statement,
class_name(statement))
return statement
entities = sc.sign_statement_using_xmlsec("%s" % entities,
class_name(entities))
return entities
def main(args):