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.client import Saml2Client
from saml2.attribute_resolver import AttributeResolver from saml2.attribute_resolver import AttributeResolver
from saml2.config import Config from saml2.config import Config
from saml2.cache import Cache from saml2.population import Population
def construct_came_from(environ): def construct_came_from(environ):
""" The URL that the user used when the process where interupted """ The URL that the user used when the process where interupted
@@ -55,7 +55,12 @@ def cgi_fieldStorage_to_dict( fieldStorage ):
params = {} params = {}
for key in fieldStorage.keys(): for key in fieldStorage.keys():
params[ key ] = fieldStorage[ key ].value try:
params[ key ] = fieldStorage[ key ].value
except AttributeError:
if isinstance(fieldStorage[ key ], basestring):
params[key] = fieldStorage[key]
return params return params
class SAML2Plugin(FormPluginBase): class SAML2Plugin(FormPluginBase):
@@ -92,18 +97,7 @@ class SAML2Plugin(FormPluginBase):
self.outstanding_queries = {} self.outstanding_queries = {}
self.iam = os.uname()[1] self.iam = os.uname()[1]
if cache: self.users = Population(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
def _pick_idp(self, environ): def _pick_idp(self, environ):
""" """
@@ -234,7 +228,7 @@ class SAML2Plugin(FormPluginBase):
session_info = ar.session_info() session_info = ar.session_info()
# Cache it # Cache it
name_id = self._cache_session(session_info) name_id = self.users.add_information_about_person(session_info)
if self.debug: if self.debug:
self.log and self.log.info("stored %s with key %s" % ( self.log and self.log.info("stored %s with key %s" % (
session_info, name_id)) session_info, name_id))
@@ -299,56 +293,6 @@ class SAML2Plugin(FormPluginBase):
else: else:
return None 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 # IMetadataProvider
def add_metadata(self, environ, identity): def add_metadata(self, environ, identity):
@@ -381,7 +325,7 @@ class SAML2Plugin(FormPluginBase):
if "pysaml2_vo_expanded" not in identity: if "pysaml2_vo_expanded" not in identity:
# is this a Virtual Organization situation # is this a Virtual Organization situation
if self.vorg: if self.vorg:
if self._do_vo_aggregation(subject_id): if self.vorg.do_vo_aggregation(subject_id):
# Get the extended identity # Get the extended identity
identity["user"] = self.cache.get_identity(subject_id)[0] identity["user"] = self.cache.get_identity(subject_id)[0]
# Only do this once, mark that the identity has been # 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. 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: try:
from xml.etree import cElementTree as ElementTree from xml.etree import cElementTree as ElementTree
except ImportError: except ImportError:
@@ -45,7 +61,7 @@ NAMESPACE = 'urn:oasis:names:tc:SAML:2.0:assertion'
NAMEID_FORMAT_EMAILADDRESS = ( NAMEID_FORMAT_EMAILADDRESS = (
"urn:oasis:names:tc:SAML:2.0: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 = ( NAME_FORMAT_UNSPECIFIED = (
"urn:oasis:names:tc:SAML:2.0:attrnam-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" 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. not match those of the target class.
""" """
tree = ElementTree.fromstring(xml_string) 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): tag=None):
"""Instantiates the class and populates members according to the tree. """Instantiates the class and populates members according to the tree.
@@ -411,6 +427,9 @@ class SamlBase(ExtensionContainer):
c_children = {} c_children = {}
c_attributes = {} c_attributes = {}
c_attribute_type = {}
#c_attribute_use = {}
c_attribute_required = {}
c_child_order = [] c_child_order = []
def _get_all_c_children_with_order(self): def _get_all_c_children_with_order(self):
@@ -433,11 +452,11 @@ class SamlBase(ExtensionContainer):
if getattr(self, member_name) is None: if getattr(self, member_name) is None:
setattr(self, member_name, []) setattr(self, member_name, [])
getattr(self, member_name).append( getattr(self, member_name).append(
_create_class_from_element_tree( create_class_from_element_tree(
member_class[0], child_tree)) member_class[0], child_tree))
else: else:
setattr(self, member_name, setattr(self, member_name,
_create_class_from_element_tree(member_class, create_class_from_element_tree(member_class,
child_tree)) child_tree))
else: else:
ExtensionContainer._convert_element_tree_to_member(self, 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 # Find the member of this class which corresponds to the XML
# attribute(lookup in current_class.c_attributes) and set this # attribute(lookup in current_class.c_attributes) and set this
# member to the desired value (using self.__dict__). # 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: else:
# If it doesn't appear in the attribute list it's an extension # If it doesn't appear in the attribute list it's an extension
ExtensionContainer._convert_element_attribute_to_member(self, ExtensionContainer._convert_element_attribute_to_member(self,
@@ -470,8 +489,9 @@ class SamlBase(ExtensionContainer):
else: else:
member.become_child_element_of(tree) member.become_child_element_of(tree)
# Convert the members of this class which are XML attributes. # 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(): self.__class__.c_attributes.iteritems():
(member_name, member_type, required) = attribute_info
member = getattr(self, member_name) member = getattr(self, member_name)
if member is not None: if member is not None:
tree.attrib[xml_attribute] = member tree.attrib[xml_attribute] = member
@@ -514,7 +534,8 @@ class SamlBase(ExtensionContainer):
def _init_attribute(self, extension_attribute_id, def _init_attribute(self, extension_attribute_id,
extension_attribute_name, value=None): 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: if value:
self.__dict__[extension_attribute_name] = value self.__dict__[extension_attribute_name] = value
@@ -532,7 +553,7 @@ class SamlBase(ExtensionContainer):
:return: list of keys :return: list of keys
""" """
keys = ['text'] 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()]) keys.extend([v[1] for v in self.c_children.values()])
return keys return keys
@@ -592,7 +613,7 @@ class SamlBase(ExtensionContainer):
:return: The instance :return: The instance
""" """
for prop in self.c_attributes.values(): for prop, _typ, _req in self.c_attributes.values():
#print "# %s" % (prop) #print "# %s" % (prop)
if prop in ava: if prop in ava:
if isinstance(ava[prop], bool): if isinstance(ava[prop], bool):
@@ -641,7 +662,7 @@ def element_to_extension_element(element):
exel = ExtensionElement(element.c_tag, element.c_namespace, exel = ExtensionElement(element.c_tag, element.c_namespace,
text=element.text) 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) member_value = getattr(element, member_name)
if member_value is not None: if member_value is not None:
exel.attributes[xml_attribute] = member_value 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.time_util import instant, in_a_while
from saml2.attribute_converter import from_local from saml2.attribute_converter import from_local
from saml2.utils import sid, MissingValue from saml2.s_utils import sid, MissingValue
from saml2.utils import args2dict from saml2.s_utils import factory
from saml2.utils import assertion_factory from saml2.s_utils import assertion_factory
from saml2.s_utils import do_attribute_statement
def _filter_values(vals, required=None, optional=None): 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 val: The values that are to be filtered
:param required: The required values :param required: The required values
@@ -314,12 +316,13 @@ class Policy(object):
return self.filter(ava, sp_entity_id, required, optional) return self.filter(ava, sp_entity_id, required, optional)
def conditions(self, sp_entity_id): def conditions(self, sp_entity_id):
return args2dict( return factory( saml.Conditions,
not_before=instant(), not_before=instant(),
# How long might depend on who's getting it # How long might depend on who's getting it
not_on_or_after=self._not_on_or_after(sp_entity_id), not_on_or_after=self._not_on_or_after(sp_entity_id),
audience_restriction=args2dict( audience_restriction=[factory( saml.AudienceRestriction,
audience=args2dict(sp_entity_id))) audience=factory(saml.Audience,
text=sp_entity_id))])
class Assertion(dict): class Assertion(dict):
""" Handles assertions about subjects """ """ Handles assertions about subjects """
@@ -327,14 +330,28 @@ class Assertion(dict):
def __init__(self, dic=None): def __init__(self, dic=None):
dict.__init__(self, dic) dict.__init__(self, dic)
def _authn_statement(self): def _authn_context(self, authn_class):
return args2dict(authn_instant=instant(), session_index=sid()) 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, 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, attr_statement = saml.AttributeStatement(attribute=from_local(
policy.get_name_form(sp_entity_id)) attrconvs, self,
policy.get_name_form(sp_entity_id)))
# start using now and for a hour # start using now and for a hour
conds = policy.conditions(sp_entity_id) conds = policy.conditions(sp_entity_id)
@@ -342,14 +359,15 @@ class Assertion(dict):
return assertion_factory( return assertion_factory(
issuer=issuer, issuer=issuer,
attribute_statement = attr_statement, attribute_statement = attr_statement,
authn_statement = self._authn_statement(), authn_statement = self._authn_statement(authn_class),
conditions = conds, conditions = conds,
subject=args2dict( subject=factory( saml.Subject,
name_id=name_id, name_id=name_id,
method=saml.SUBJECT_CONFIRMATION_METHOD_BEARER, method=saml.SUBJECT_CONFIRMATION_METHOD_BEARER,
subject_confirmation=args2dict( subject_confirmation=factory( saml.SubjectConfirmation,
subject_confirmation_data = \ subject_confirmation_data=factory(
args2dict(in_response_to=in_response_to))), saml.SubjectConfirmationData,
in_response_to=in_response_to))),
) )
def apply_policy(self, sp_entity_id, policy, metadata=None): def apply_policy(self, sp_entity_id, policy, metadata=None):

View File

@@ -16,7 +16,8 @@
# limitations under the License. # limitations under the License.
import os 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 from saml2.saml import NAME_FORMAT_URI
class UnknownNameFormat(Exception): class UnknownNameFormat(Exception):
@@ -64,7 +65,7 @@ def from_local(acs, ava, name_format):
#print ac.format, name_format #print ac.format, name_format
if aconv.name_format == name_format: if aconv.name_format == name_format:
#print "Found a name_form converter" #print "Found a name_form converter"
return aconv.to(ava) return aconv.to_(ava)
return None return None
@@ -73,7 +74,7 @@ def from_local_name(acs, attr, name_format):
:param acs: List of AttributeConverter instances :param acs: List of AttributeConverter instances
:param attr: attribute name as string :param attr: attribute name as string
:param name_format: Which name-format it should be translated to :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: for aconv in acs:
#print ac.format, name_format #print ac.format, name_format
@@ -118,7 +119,7 @@ class AttributeConverter(object):
self._to = eval(open(filename).read()) self._to = eval(open(filename).read())
def adjust(self): 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()]) self._fro = dict([(value, key) for key, value in self._to.items()])
if self._to == None and self.fro != None: if self._to == None and self.fro != None:
self._to = dict([(value, key) for key, value in self._fro.items()]) self._to = dict([(value, key) for key, value in self._fro.items()])
@@ -184,10 +185,12 @@ class AttributeConverter(object):
def to_format(self, attr): def to_format(self, attr):
try: try:
return args2dict(name=self._to[attr], name_format=self.name_format, return factory(saml.Attribute,
friendly_name=attr) name=self._to[attr],
name_format=self.name_format,
friendly_name=attr)
except KeyError: except KeyError:
return args2dict(name=attr) return factory(saml.Attribute, name=attr)
def from_format(self, attr): def from_format(self, attr):
""" """
@@ -201,18 +204,18 @@ class AttributeConverter(object):
pass pass
return "" return ""
def to(self, ava): def to_(self, attrvals):
attributes = [] attributes = []
for key, value in ava.items(): for key, value in attrvals.items():
try: try:
attributes.append(args2dict(name=self._to[key], attributes.append(factory(saml.Attribute,
name=self._to[key],
name_format=self.name_format, name_format=self.name_format,
friendly_name=key, friendly_name=key,
attribute_value=value)) attribute_value=do_ava(value)))
except KeyError: except KeyError:
# TODO attributes.append(factory(saml.Attribute,
# Should this be made different ??? name=key,
attributes.append(args2dict(name=key, attribute_value=do_ava(value)))
attribute_value=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. to do attribute aggregation.
""" """
import saml2 import saml2
from saml2.client import Saml2Client
DEFAULT_BINDING = saml2.BINDING_HTTP_REDIRECT DEFAULT_BINDING = saml2.BINDING_HTTP_REDIRECT
@@ -32,7 +31,7 @@ class AttributeResolver(object):
if saml2client: if saml2client:
self.saml2client = saml2client self.saml2client = saml2client
else: 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, def extend(self, subject_id, issuer, vo_members, name_id_format=None,
sp_name_qualifier=None, log=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): def _use_on_or_after(condition, slack):
now = daylight_corrected_now() now = daylight_corrected_now()
#print "NOW: %d" % now #print "NOW: %d" % now
@@ -57,23 +62,17 @@ def _use_before(condition, slack):
return True return True
def for_me(condition, myself ): def for_me(condition, myself ):
# Am I among the intended audiences
for restriction in condition.audience_restriction: for restriction in condition.audience_restriction:
audience = restriction.audience for audience in restriction.audience:
if audience.text.strip() == myself: if audience.text.strip() == myself:
return True return True
else: else:
#print "Not for me: %s != %s" % (audience.text.strip(), myself) #print "Not for me: %s != %s" % (audience.text.strip(), myself)
pass pass
return False return False
# ---------------------------------------------------------------------------
class IncorrectlySigned(Exception):
pass
# ---------------------------------------------------------------------------
def authn_response(conf, requestor, outstanding_queries=None, log=None, def authn_response(conf, requestor, outstanding_queries=None, log=None,
timeslack=0, debug=0): timeslack=0, debug=0):
sec = security_context(conf) sec = security_context(conf)
@@ -128,7 +127,6 @@ class AuthnResponse(object):
self.response = self.sec.correctly_signed_response(decoded_xml) self.response = self.sec.correctly_signed_response(decoded_xml)
except Exception, excp: except Exception, excp:
self.log and self.log.info("EXCEPTION: %s", excp) self.log and self.log.info("EXCEPTION: %s", excp)
raise
if not self.response: if not self.response:
if self.log: if self.log:
@@ -180,7 +178,7 @@ class AuthnResponse(object):
self.not_on_or_after = _use_on_or_after(condition, self.timeslack) self.not_on_or_after = _use_on_or_after(condition, self.timeslack)
_use_before(condition, self.timeslack) _use_before(condition, self.timeslack)
except Exception, excp: 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: if not lax:
raise raise
else: else:
@@ -230,6 +228,7 @@ class AuthnResponse(object):
# The subject must contain a name_id # The subject must contain a name_id
assert subject.name_id assert subject.name_id
self.name_id = subject.name_id.text.strip() self.name_id = subject.name_id.text.strip()
return self.name_id
def _assertion(self, assertion): def _assertion(self, assertion):
self.assertion = assertion self.assertion = assertion
@@ -294,7 +293,7 @@ class AuthnResponse(object):
return True return True
def verify(self): 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.""" the signature is correct if present."""
self.status_ok() self.status_ok()

View File

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

View File

@@ -25,14 +25,16 @@ import saml2
import base64 import base64
from saml2.time_util import instant from saml2.time_util import instant
from saml2.utils import sid, deflate_and_base64_encode from saml2.s_utils import sid, deflate_and_base64_encode
from saml2.utils import do_attributes, args2dict from saml2.s_utils import do_attributes, factory
from saml2 import samlp, saml from saml2 import samlp, saml, class_name
from saml2 import VERSION, make_instance from saml2 import VERSION
from saml2.sigver import pre_signature_part from saml2.sigver import pre_signature_part
from saml2.sigver import security_context, signed_instance_factory from saml2.sigver import security_context, signed_instance_factory
from saml2.soap import SOAPClient from saml2.soap import SOAPClient
from saml2.population import Population
from saml2.virtual_org import VirtualOrg
from saml2.authnresponse import authn_response from saml2.authnresponse import authn_response
@@ -46,19 +48,32 @@ FORM_SPEC = """<form method="post" action="%s">
LAX = False LAX = False
class IdpUnspecified(Exception):
pass
class VerifyError(Exception):
pass
class Saml2Client(object): class Saml2Client(object):
""" The basic pySAML2 service provider class """ """ 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 environ:
:param config: A saml2.config.Config instance :param config: A saml2.config.Config instance
""" """
self.environ = environ self.environ = environ
self.vorg = None
self.users = Population(persistent_cache)
if config: if config:
self.config = config self.config = config
if "metadata" in config: if "metadata" in config:
self.metadata = config["metadata"] 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.sec = security_context(config)
self.debug = debug self.debug = debug
@@ -71,32 +86,23 @@ class Saml2Client(object):
return request return request
def idp_entry(self, name=None, location=None, provider_id=None): def idp_entry(self, name=None, location=None, provider_id=None):
res = {} res = samlp.IDPEntry()
if name: if name:
res["name"] = name res.name = name
if location: if location:
res["loc"] = location res.loc = location
if provider_id: if provider_id:
res["provider_id"] = provider_id res.provider_id = provider_id
if res:
return res
else:
return None
def scoping(self, idp_ents): return res
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) name = self.metadata.name(entityid)
return make_instance(samlp.Scoping, idp_ent = self.idp_entry(name, location)
self.scoping([self.idp_entry(name, location)])) return samlp.Scoping(idp_list=samlp.IDPList(idp_entry=[idp_ent]))
def response(self, post, requestor, outstanding, log=None): def response(self, post, requestor, outstanding, log=None):
""" Deal with the AuthnResponse """ Deal with an AuthnResponse
:param post: The reply as a dictionary :param post: The reply as a dictionary
:param requestor: The issuer of the AuthN request :param requestor: The issuer of the AuthN request
@@ -104,10 +110,8 @@ class Saml2Client(object):
the original web request from the user before redirection the original web request from the user before redirection
as values. as values.
:param log: where loggin should go. :param log: where loggin should go.
:return: A 2-tuple of identity information (in the form of a :return: An authnresponse.AuthnResponse instance which among other
dictionary) and where the user should really be sent. This things contains a verified saml2.AuthnResponse instance.
might differ from what the IdP thinks since I don't want
to reveal verything to it and it might not trust me.
""" """
# If the request contains a samlResponse, try to validate it # If the request contains a samlResponse, try to validate it
try: try:
@@ -115,15 +119,18 @@ class Saml2Client(object):
except KeyError: except KeyError:
return None return None
aresp = None
if saml_response: if saml_response:
aresp = authn_response(self.config, requestor, outstanding, log, aresp = authn_response(self.config, requestor, outstanding, log,
debug=self.debug) debug=self.debug)
aresp.loads(saml_response) aresp.loads(saml_response)
if self.debug: if self.debug:
log and log.info(aresp) 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, def authn_request(self, query_id, destination, service_url, spentityid,
my_name, vorg="", scoping=None, log=None, sign=False): 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 log: A service to which logs should be written
:param sign: Whether the request should be signed or not. :param sign: Whether the request should be signed or not.
""" """
prel = { request = samlp.AuthnRequest(
"id": query_id, id= query_id,
"version": VERSION, version= VERSION,
"issue_instant": instant(), issue_instant= instant(),
"destination": destination, destination= destination,
"assertion_consumer_service_url": service_url, assertion_consumer_service_url= service_url,
"protocol_binding": saml2.BINDING_HTTP_POST, protocol_binding= saml2.BINDING_HTTP_POST,
"provider_name": my_name, provider_name= my_name
} )
if scoping: if scoping:
prel["scoping"] = scoping request.scoping = scoping
name_id_policy = { # Profile stuff, should be configurable
"allow_create": "true" name_id_policy = samlp.NameIDPolicy(allow_create="true",
} format=saml.NAMEID_FORMAT_TRANSIENT)
name_id_policy["format"] = saml.NAMEID_FORMAT_TRANSIENT
if vorg: if vorg:
try: try:
name_id_policy["sp_name_qualifier"] = vorg name_id_policy.sp_name_qualifier = vorg
name_id_policy["format"] = saml.NAMEID_FORMAT_PERSISTENT name_id_policy.format = saml.NAMEID_FORMAT_PERSISTENT
except KeyError: except KeyError:
pass pass
if sign: if sign:
prel["signature"] = pre_signature_part(prel["id"], request.signature = pre_signature_part(request.id,
self.sec.my_cert, id=1) self.sec.my_cert, 1)
to_sign = [(class_name(request), request.id)]
else:
to_sign = []
prel["name_id_policy"] = name_id_policy request.name_id_policy = name_id_policy
prel["issuer"] = { "text": spentityid } request.issuer = factory(saml.Issuer, text=spentityid )
if log: if log:
log.info("DICT VERSION: %s" % prel) log.info("REQUEST: %s" % request)
return "%s" % signed_instance_factory(samlp.AuthnRequest, prel, return "%s" % signed_instance_factory(request, self.sec, to_sign)
self.sec)
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="", my_name="", relay_state="",
binding=saml2.BINDING_HTTP_REDIRECT, log=None, binding=saml2.BINDING_HTTP_REDIRECT, log=None,
vorg="", scoping=None): vorg="", scoping=None):
@@ -199,11 +239,17 @@ class Saml2Client(object):
:return: AuthnRequest response :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: if log:
log.info("spentityid: %s" % spentityid) log.info("spentityid: %s" % spentityid)
log.info("location: %s" % location) log.info("location: %s" % location)
log.info("service_url: %s" % service_url) log.info("service_url: %s" % service_url)
log.info("my_name: %s" % my_name) log.info("my_name: %s" % my_name)
session_id = sid() session_id = sid()
authen_req = self.authn_request(session_id, location, authen_req = self.authn_request(session_id, location,
service_url, spentityid, my_name, vorg, service_url, spentityid, my_name, vorg,
@@ -229,7 +275,8 @@ class Saml2Client(object):
lista = ["SAMLRequest=%s" % urllib.quote_plus( lista = ["SAMLRequest=%s" % urllib.quote_plus(
deflate_and_base64_encode( deflate_and_base64_encode(
authen_req)), authen_req)),
"spentityid=%s" % spentityid] #"spentityid=%s" % spentityid
]
if relay_state: if relay_state:
lista.append("RelayState=%s" % relay_state) lista.append("RelayState=%s" % relay_state)
login_url = "?".join([location, "&".join(lista)]) login_url = "?".join([location, "&".join(lista)])
@@ -263,35 +310,35 @@ class Saml2Client(object):
""" """
subject = args2dict( subject = saml.Subject(
name_id = args2dict(subject_id, format=nameid_format, name_id = saml.NameID(
text=subject_id,
format=nameid_format,
sp_name_qualifier=sp_name_qualifier, sp_name_qualifier=sp_name_qualifier,
name_qualifier=name_qualifier), name_qualifier=name_qualifier),
) )
prequery = { query = samlp.AttributeQuery(
"id": session_id, id=session_id,
"version": VERSION, version=VERSION,
"issue_instant": instant(), issue_instant=instant(),
"destination": destination, destination=destination,
"issuer": issuer, issuer=self.issuer(),
"subject":subject, subject=subject,
} )
if sign: if sign:
prequery["signature"] = pre_signature_part(prequery["id"], query.signature = pre_signature_part(query.id, self.sec.my_cert, 1)
self.sec.my_cert, 1)
if attribute: if attribute:
prequery["attribute"] = do_attributes(attribute) query.attribute = do_attributes(attribute)
request = make_instance(samlp.AttributeQuery, prequery)
if sign: if sign:
signed_req = self.sec.sign_assertion_using_xmlsec("%s" % request) signed_query = self.sec.sign_assertion_using_xmlsec("%s" % query)
return samlp.attribute_query_from_string(signed_req) return samlp.attribute_query_from_string(signed_query)
else: else:
return request return query
def attribute_query(self, subject_id, issuer, destination, def attribute_query(self, subject_id, issuer, destination,
@@ -334,14 +381,17 @@ class Saml2Client(object):
aresp = authn_response(self.config, issuer, {session_id:""}, log) aresp = authn_response(self.config, issuer, {session_id:""}, log)
session_info = aresp.loads(response).verify().session_info() 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) log and log.info("session: %s" % session_info)
return session_info return session_info
else: else:
log and log.info("No response") log and log.info("No response")
return None return None
def make_logout_request(self, session_id, destination, issuer, def make_logout_requests(self, subject_id, reason=None,
reason=None, not_on_or_after=None): not_on_or_after=None):
""" Constructs a LogoutRequest """ Constructs a LogoutRequest
:param subject_id: The identifier of the subject :param subject_id: The identifier of the subject
@@ -349,31 +399,67 @@ class Saml2Client(object):
form of a URI reference. form of a URI reference.
:param not_on_or_after: The time at which the request expires, :param not_on_or_after: The time at which the request expires,
after which the recipient may discard the message. after which the recipient may discard the message.
:return: An AttributeQuery instance :return: A LogoutRequest instance
""" """
prel = { result = []
"id": sid(),
"version": VERSION,
"issue_instant": instant(),
"destination": destination,
"issuer": issuer,
"session_index": session_id,
}
if reason: for entity_id in self.users.issuers_of_info(subject_id):
prel["reason"] = reason destination = self.config["service"]["sp"]["idp"][entity_id]
if not_on_or_after: # create NameID from subject_id
prel["not_on_or_after"] = not_on_or_after name_id = NameID(
text=self.client.users.get_entityid(subject_id,
entity_id)["name_id"])
return make_instance(samlp.LogoutRequest, prel) request = samlp.LogoutRequest(
id=sid(),
version=VERSION,
issue_instant=instant(),
destination=destination,
issuer=self.issuer(),
session_index=session_id,
name_id = name_id
)
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)
if reason:
request.reason = reason
if not_on_or_after:
request.not_on_or_after = not_on_or_after
result.append(request)
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 "idp" in config
assert len(config["idp"]) > 0 assert len(config["idp"]) > 0
assert "url" in config assert "endpoints" in config
assert "name" in config assert "name" in config
def _idp_aa_check(self, config): def _idp_aa_check(self, config):
assert "url" in config assert "endpoints" in config
if "assertions" in config: if "assertions" in config:
config["policy"] = Policy(config["assertions"]) config["policy"] = Policy(config["assertions"])
del config["assertions"] del config["assertions"]
@@ -95,6 +95,7 @@ class Config(dict):
config["metadata"] = self.load_metadata(config["metadata"], config["metadata"] = self.load_metadata(config["metadata"],
config["xmlsec_binary"], config["xmlsec_binary"],
config["attrconverters"]) config["attrconverters"])
self.metadata = config["metadata"]
if "sp" in config["service"]: if "sp" in config["service"]:
#print config["service"]["sp"] #print config["service"]["sp"]
@@ -130,11 +131,11 @@ class Config(dict):
except KeyError: except KeyError:
return Policy() return Policy()
def aa_url(self): def endpoint(self, typ, service):
return self["service"]["aa"]["url"] try:
return self["service"][typ]["endpoints"][service]
def idp_url(self): except KeyError:
return self["service"]["idp"]["url"] return None
def vo_conf(self, name): def vo_conf(self, name):
return self["virtual_organization"][name] return self["virtual_organization"][name]
@@ -142,3 +143,24 @@ class Config(dict):
def attribute_converters(self): def attribute_converters(self):
return self["attrconverters"] 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 :param entity_descriptor: A EntityDescriptor instance
""" """
try: try:
ssd = entity_descriptor.sp_sso_descriptor ssd = entity_descriptor.spsso_descriptor
except AttributeError: except AttributeError:
return return
@@ -141,7 +141,7 @@ class MetaData(object):
:param entity_descriptor: A EntityDescriptor instance :param entity_descriptor: A EntityDescriptor instance
""" """
try: try:
isd = entity_descriptor.idp_sso_descriptor isd = entity_descriptor.idpsso_descriptor
except AttributeError: except AttributeError:
return return
@@ -280,7 +280,7 @@ class MetaData(object):
except AttributeError: except AttributeError:
pass pass
try: try:
entity["contact"] = entity_descriptor.contact entity["contact_person"] = entity_descriptor.contact_person
except AttributeError: except AttributeError:
pass pass
@@ -394,22 +394,25 @@ class MetaData(object):
:param entityid: The Entity ID :param entityid: The Entity ID
:return: A name :return: A name
""" """
name = ""
try: try:
org = self.entity[entity_id]["organization"] for org in self.entity[entity_id]["organization"]:
try:
names = org.organization_display_name
except KeyError:
try: try:
names = org.organization_name name = org.organization_display_name[0]
except KeyError: except IndexError:
try: try:
names = org.organization_url name = org.organization_name[0]
except KeyError: except IndexError:
names = None try:
if names: name = org.organization_url[0]
name = names[0].text except IndexError:
pass
if name:
name = name.text
except KeyError: except KeyError:
name = "" pass
return name return name

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 import saml, samlp, VERSION, class_name
from saml2.utils import sid, decode_base64_and_inflate from saml2.s_utils import sid, decode_base64_and_inflate
from saml2.utils import response_factory from saml2.s_utils import response_factory
from saml2.utils import MissingValue, args2dict from saml2.s_utils import MissingValue, factory
from saml2.utils import success_status_factory from saml2.s_utils import success_status_factory
from saml2.utils import OtherError from saml2.s_utils import OtherError
from saml2.utils import VersionMismatch, UnknownPrincipal, UnsupportedBinding from saml2.s_utils import VersionMismatch, UnknownPrincipal, UnsupportedBinding
from saml2.utils import status_from_exception_factory from saml2.s_utils import status_from_exception_factory
from saml2.sigver import security_context, signed_instance_factory from saml2.sigver import security_context, signed_instance_factory
from saml2.sigver import pre_signature_part from saml2.sigver import pre_signature_part
@@ -105,8 +105,11 @@ class Identifier(object):
except KeyError: except KeyError:
nameid_format = saml.NAMEID_FORMAT_PERSISTENT nameid_format = saml.NAMEID_FORMAT_PERSISTENT
return args2dict(subj_id, format=nameid_format, return saml.NameID(format=nameid_format,
sp_name_qualifier=sp_name_qualifier) 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): def persistent_nameid(self, sp_name_qualifier, userid):
""" Get or create a persistent identifier for this object to be used """ Get or create a persistent identifier for this object to be used
@@ -117,8 +120,18 @@ class Identifier(object):
:return: A persistent random identifier. :return: A persistent random identifier.
""" """
subj_id = self.persistent(sp_name_qualifier, userid) subj_id = self.persistent(sp_name_qualifier, userid)
return args2dict(subj_id, format=saml.NAMEID_FORMAT_PERSISTENT, return saml.NameID(format=saml.NAMEID_FORMAT_PERSISTENT,
sp_name_qualifier=sp_name_qualifier) 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, def construct_nameid(self, local_policy, userid, sp_entity_id,
identity=None, name_id_policy=None): identity=None, name_id_policy=None):
@@ -143,9 +156,6 @@ class Identifier(object):
elif nameid_format == saml.NAMEID_FORMAT_TRANSIENT: elif nameid_format == saml.NAMEID_FORMAT_TRANSIENT:
return self.temporary_nameid() 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): class Server(object):
@@ -181,10 +191,9 @@ class Server(object):
def issuer(self): def issuer(self):
""" Return an Issuer precursor """ """ Return an Issuer precursor """
return args2dict( self.conf["entityid"], return saml.Issuer(text=self.conf["entityid"],
format=saml.NAMEID_FORMAT_ENTITY) format=saml.NAMEID_FORMAT_ENTITY)
def parse_authn_request(self, enc_request): def parse_authn_request(self, enc_request):
"""Parse a Authentication Request """Parse a Authentication Request
@@ -298,6 +307,8 @@ class Server(object):
:return: A Response instance :return: A Response instance
""" """
to_sign = []
if not status: if not status:
status = success_status_factory() status = success_status_factory()
@@ -323,19 +334,21 @@ class Server(object):
policy, issuer=_issuer) policy, issuer=_issuer)
if sign: if sign:
assertion["signature"] = pre_signature_part(assertion["id"], assertion.signature = pre_signature_part(assertion.id,
self.sec.my_cert, 1) 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 # Store which assertion that has been sent to which SP about which
# subject. # subject.
self.cache.set(assertion["subject"]["name_id"]["text"], self.cache.set(assertion.subject.name_id.text,
sp_entity_id, assertion, 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. 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 from saml2 import create_class_from_xml_string
import xmldsig as ds import xmldsig as ds
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
@@ -27,12 +27,11 @@ from subprocess import Popen, PIPE
import base64 import base64
import random import random
import os import os
import copy
def get_xmlsec_binary(): def get_xmlsec_binary():
for path in os.environ["PATH"].split(":"): for path in os.environ["PATH"].split(":"):
fil = os.path.join(path, "xmlsec1") fil = os.path.join(path, "xmlsec1")
if os.access(fil,os.X_OK): if os.access(fil, os.X_OK):
return fil return fil
raise Exception("Can't find xmlsec1") raise Exception("Can't find xmlsec1")
@@ -86,12 +85,12 @@ def _make_vals(val, klass, seccont, klass_inst=None, prop=None, part=False,
#print "make_vals(%s, %s)" % (val, klass) #print "make_vals(%s, %s)" % (val, klass)
if isinstance(val, dict): if isinstance(val, dict):
cinst = _instance(klass, val, seccont,base64encode=base64encode, cinst = _instance(klass, val, seccont, base64encode=base64encode,
elements_to_sign=elements_to_sign) elements_to_sign=elements_to_sign)
else: else:
try: try:
cinst = klass().set_text(val) cinst = klass().set_text(val)
except ValueError, excp: except ValueError:
if not part: if not part:
cis = [_make_vals(sval, klass, seccont, klass_inst, prop, cis = [_make_vals(sval, klass, seccont, klass_inst, prop,
True, base64encode, elements_to_sign) for sval in val] True, base64encode, elements_to_sign) for sval in val]
@@ -150,16 +149,12 @@ def _instance(klass, ava, seccont, base64encode=False, elements_to_sign=None):
return instance return instance
def signed_instance_factory(klass, ava, seccont, base64encode=False): def signed_instance_factory(instance, seccont, elements_to_sign=None):
elements_to_sign = []
instance = _instance(klass, ava, seccont, base64encode=False,
elements_to_sign=elements_to_sign)
if elements_to_sign: if elements_to_sign:
signed_xml = "%s" % instance signed_xml = "%s" % instance
for (node_name, nodeid) in elements_to_sign: for (node_name, nodeid) in elements_to_sign:
signed_xml = seccont.sign_statement_using_xmlsec(signed_xml, signed_xml = seccont.sign_statement_using_xmlsec(signed_xml,
class_name=node_name, nodeid=nodeid) klass_namn=node_name, nodeid=nodeid)
#print "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" #print "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
#print "%s" % signed_xml #print "%s" % signed_xml
@@ -274,7 +269,7 @@ def verify_signature(enctext, xmlsec_binary, cert_file=None, cert_type="pem",
com_list.append("--store-signatures") com_list.append("--store-signatures")
if node_id: if node_id:
com_list.extend(["--node-id",node_id]) com_list.extend(["--node-id", node_id])
com_list.append(fil) com_list.append(fil)
@@ -351,6 +346,7 @@ class SecurityContext(object):
# Your private key # Your private key
self.key_file = key_file self.key_file = key_file
self.key_type = key_type
# Your certificate # Your certificate
self.cert_file = cert_file self.cert_file = cert_file
@@ -379,7 +375,7 @@ class SecurityContext(object):
ntf = NamedTemporaryFile() ntf = NamedTemporaryFile()
com_list = [self.xmlsec, "--decrypt", com_list = [self.xmlsec, "--decrypt",
"--privkey-pem", key_file, "--privkey-pem", self.key_file,
"--output", ntf.name, "--output", ntf.name,
"--id-attr:%s" % ID_ATTR, "--id-attr:%s" % ID_ATTR,
ENC_NODE_NAME, fil] ENC_NODE_NAME, fil]
@@ -503,11 +499,11 @@ class SecurityContext(object):
return response return response
#---------------------------------------------------------------------------- #--------------------------------------------------------------------------
# SIGNATURE PART # 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): key_file=None, nodeid=None):
"""Sign a SAML statement using xmlsec. """Sign a SAML statement using xmlsec.
@@ -530,11 +526,11 @@ class SecurityContext(object):
com_list = [self.xmlsec, "--sign", com_list = [self.xmlsec, "--sign",
"--output", ntf.name, "--output", ntf.name,
"--privkey-pem", key_file, "--privkey-pem", key_file,
"--id-attr:%s" % ID_ATTR, class_name, "--id-attr:%s" % ID_ATTR, klass_namn,
#"--store-signatures" #"--store-signatures"
] ]
if nodeid: if nodeid:
com_list.extend(["--node-id",nodeid]) com_list.extend(["--node-id", nodeid])
com_list.append(fil) com_list.append(fil)
@@ -543,9 +539,9 @@ class SecurityContext(object):
# this doesn't work if --store-signatures are used # this doesn't work if --store-signatures are used
if out == "": if out == "":
#print " ".join(com_list) #print " ".join(com_list)
#print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
#print out #print out
#print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
ntf.seek(0) ntf.seek(0)
return ntf.read() return ntf.read()
else: else:
@@ -568,39 +564,65 @@ class SecurityContext(object):
# =========================================================================== # ===========================================================================
PRE_SIGNATURE = { # PRE_SIGNATURE = {
"signed_info": { # "signed_info": {
"signature_method": { # "signature_method": {
"algorithm": ds.SIG_RSA_SHA1 # "algorithm": ds.SIG_RSA_SHA1
}, # },
"canonicalization_method": { # "canonicalization_method": {
"algorithm": ds.ALG_EXC_C14N # "algorithm": ds.ALG_EXC_C14N
}, # },
"reference": { # "reference": {
# must be replace by a uriref based on the assertion ID # # must be replace by a uriref based on the assertion ID
"uri": None, # "uri": None,
"transforms": { # "transforms": {
"transform": [{ # "transform": [{
"algorithm": ds.TRANSFORM_ENVELOPED, # "algorithm": ds.TRANSFORM_ENVELOPED,
}, # },
{ # {
"algorithm": ds.ALG_EXC_C14N, # "algorithm": ds.ALG_EXC_C14N,
"inclusive_namespaces": { # "inclusive_namespaces": {
"prefix_list": "ds saml2 saml2p xenc", # "prefix_list": "ds saml2 saml2p xenc",
} # }
} # }
] # ]
}, # },
"digest_method":{ # "digest_method":{
"algorithm": ds.DIGEST_SHA1, # "algorithm": ds.DIGEST_SHA1,
}, # },
"digest_value": "", # "digest_value": "",
} # }
}, # },
"signature_value": None, # "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 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 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 :return: A preset signature part
""" """
presig = copy.deepcopy(PRE_SIGNATURE) signature_method = ds.SignatureMethod(algorithm = ds.SIG_RSA_SHA1)
presig["signed_info"]["reference"]["uri"] = "#%s" % ident canonicalization_method = ds.CanonicalizationMethod(
if id: algorithm = ds.ALG_EXC_C14N)
presig["id"] = "Signature%d" % id trans0 = ds.Transform(algorithm = ds.TRANSFORM_ENVELOPED)
if public_key: trans1 = ds.Transform(algorithm = ds.ALG_EXC_C14N)
presig["key_info"] = { transforms = ds.Transforms(transform = [trans0, trans1])
"x509_data": { digest_method = ds.DigestMethod(algorithm = ds.DIGEST_SHA1)
"x509_certificate": public_key,
} 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: else:
return "" 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 """ Returns a soap envelope containing a SAML request
as a text string. as a text string.
@@ -72,6 +72,13 @@ def make_soap_enveloped_saml_thingy(thingy):
envelope = ElementTree.Element('') envelope = ElementTree.Element('')
envelope.tag = '{%s}Envelope' % NAMESPACE 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 = ElementTree.Element('')
body.tag = '{%s}Body' % NAMESPACE body.tag = '{%s}Body' % NAMESPACE
envelope.append(body) envelope.append(body)

View File

@@ -189,6 +189,17 @@ def response_factory(signature=False, encrypt=False, **kwargs):
pass pass
return args2dict(**kwargs) 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): def _attrval(val):
if isinstance(val, list) or isinstance(val, set): if isinstance(val, list) or isinstance(val, set):
attrval = [args2dict(v) for v in val] 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"?> TEST_X509_ISSUER_SERIAL = """<?xml version="1.0" encoding="utf-8"?>
<X509IssuerSerial xmlns="http://www.w3.org/2000/09/xmldsig#"> <X509IssuerSerial xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509IssuerName>issuer name</X509IssuerName> <X509IssuerName>issuer name</X509IssuerName>
<X509IssuerNumber>1</X509IssuerNumber> <X509SerialNumber>1</X509SerialNumber>
</X509IssuerSerial> </X509IssuerSerial>
""" """

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,11 +3,14 @@
"service": { "service": {
"sp":{ "sp":{
"name" : "urn:mace:example.com:saml:roland: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"], "required_attributes": ["surName", "givenName", "mail"],
"optional_attributes": ["title"], "optional_attributes": ["title"],
"idp":{ "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", "subject_data": "subject_data.db",
"accept_time_diff": 60, "accept_time_diff": 60,
"attribute_map_dir" : "attributemaps", "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.saml import Attribute, NAME_FORMAT_URI, AttributeValue
from saml2.assertion import Policy, Assertion, filter_on_attributes from saml2.assertion import Policy, Assertion, filter_on_attributes
from saml2.assertion import filter_attribute_value_assertions 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 saml2 import attribute_converter
from py.test import raises from py.test import raises
@@ -152,21 +152,24 @@ def test_ava_filter_2():
} }
}} }}
r = Policy(conf) policy = Policy(conf)
ava = {"givenName":"Derek", ava = {"givenName":"Derek",
"surName": "Jeter", "surName": "Jeter",
"mail":"derek@example.com"} "mail":"derek@example.com"}
# I'm filtering away something the SP deems necessary # 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]) [mail], [gn, sn])
ava = {"givenName":"Derek", ava = {"givenName":"Derek",
"surName": "Jeter"} "surName": "Jeter"}
# it wasn't there to begin with # it wasn't there to begin with
raises(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]) [gn,sn,mail])
def test_filter_attribute_value_assertions_0(AVA): 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) statement = attribute_converter.from_local(self.acs, ava, BASIC_NF)
assert statement != None assert statement != None
assert len(statement["attribute"]) == 2 assert len(statement) == 2
a0 = statement["attribute"][0] a0 = statement[0]
a1 = statement["attribute"][1] a1 = statement[1]
if a0["friendly_name"] == 'sn': if a0.friendly_name == 'sn':
assert a0["name"] == 'urn:mace:dir:attribute-def:sn' assert a0.name == 'urn:mace:dir:attribute-def:sn'
assert a0["name_format"] == BASIC_NF assert a0.name_format == BASIC_NF
assert a1["friendly_name"] == "givenName" assert a1.friendly_name == "givenName"
assert a1["name"] == 'urn:mace:dir:attribute-def:givenName' assert a1.name == 'urn:mace:dir:attribute-def:givenName'
assert a1["name_format"] == BASIC_NF assert a1.name_format == BASIC_NF
elif a0["friendly_name"] == 'givenName': elif a0.friendly_name == 'givenName':
assert a0["name"] == 'urn:mace:dir:attribute-def:givenName' assert a0.name == 'urn:mace:dir:attribute-def:givenName'
assert a0["name_format"] == BASIC_NF assert a0.name_format == BASIC_NF
assert a1["friendly_name"] == "sn" assert a1.friendly_name == "sn"
assert a1["name"] == 'urn:mace:dir:attribute-def:sn' assert a1.name == 'urn:mace:dir:attribute-def:sn'
assert a1["name_format"] == BASIC_NF assert a1.name_format == BASIC_NF
else: else:
assert False assert False
@@ -80,21 +80,21 @@ class TestAC():
statement = attribute_converter.from_local(self.acs, ava, URI_NF) statement = attribute_converter.from_local(self.acs, ava, URI_NF)
assert len(statement["attribute"]) == 2 assert len(statement) == 2
a0 = statement["attribute"][0] a0 = statement[0]
a1 = statement["attribute"][1] a1 = statement[1]
if a0["friendly_name"] == 'surname': if a0.friendly_name == 'surname':
assert a0["name"] == 'urn:oid:2.5.4.4' assert a0.name == 'urn:oid:2.5.4.4'
assert a0["name_format"] == URI_NF assert a0.name_format == URI_NF
assert a1["friendly_name"] == "givenName" assert a1.friendly_name == "givenName"
assert a1["name"] == 'urn:oid:2.5.4.42' assert a1.name == 'urn:oid:2.5.4.42'
assert a1["name_format"] == URI_NF assert a1.name_format == URI_NF
elif a0["friendly_name"] == 'givenName': elif a0.friendly_name == 'givenName':
assert a0["name"] == 'urn:oid:2.5.4.42' assert a0.name == 'urn:oid:2.5.4.42'
assert a0["name_format"] == URI_NF assert a0.name_format == URI_NF
assert a1["friendly_name"] == "surname" assert a1.friendly_name == "surname"
assert a1["name"] == 'urn:oid:2.5.4.4' assert a1.name == 'urn:oid:2.5.4.4'
assert a1["name_format"] == URI_NF assert a1.name_format == URI_NF
else: else:
assert False assert False

View File

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

View File

@@ -9,7 +9,9 @@ sp1 = {
"entityid" : "urn:mace:umu.se:saml:roland:sp", "entityid" : "urn:mace:umu.se:saml:roland:sp",
"service": { "service": {
"sp": { "sp": {
"url" : "http://lingon.catalogix.se:8087/", "endpoints" : {
"assertion_consumer_service" : ["http://lingon.catalogix.se:8087/"],
},
"name": "test", "name": "test",
"idp" : { "idp" : {
"urn:mace:example.com:saml:roland:idp":None, "urn:mace:example.com:saml:roland:idp":None,
@@ -36,7 +38,9 @@ sp2 = {
"service": { "service": {
"sp":{ "sp":{
"name" : "Rolands SP", "name" : "Rolands SP",
"url" : "http://localhost:8087/", "endpoints" : {
"assertion_consumer_service" : ["http://lingon.catalogix.se:8087/"],
},
"required_attributes": ["surName", "givenName", "mail"], "required_attributes": ["surName", "givenName", "mail"],
"optional_attributes": ["title"], "optional_attributes": ["title"],
"idp": { "idp": {
@@ -52,7 +56,9 @@ IDP1 = {
"service": { "service": {
"idp":{ "idp":{
"name" : "Rolands IdP", "name" : "Rolands IdP",
"url" : "http://localhost:8088/", "endpoints": {
"single_sign_on_service" : ["http://localhost:8088/"],
},
"assertions":{ "assertions":{
"default": { "default": {
"attribute_restrictions": { "attribute_restrictions": {
@@ -79,7 +85,7 @@ def test_1():
service = c["service"] service = c["service"]
assert service.keys() == ["sp"] assert service.keys() == ["sp"]
sp = service["sp"] sp = service["sp"]
assert _eq(sp.keys(),["url","name","idp"]) assert _eq(sp.keys(),["endpoints","name","idp"])
md = c["metadata"] md = c["metadata"]
assert isinstance(md, MetaData) assert isinstance(md, MetaData)
@@ -94,7 +100,7 @@ def test_2():
service = c["service"] service = c["service"]
assert service.keys() == ["sp"] assert service.keys() == ["sp"]
sp = service["sp"] sp = service["sp"]
assert _eq(sp.keys(),['url', 'idp', 'optional_attributes', 'name', assert _eq(sp.keys(),['endpoints', 'idp', 'optional_attributes', 'name',
'required_attributes']) 'required_attributes'])
assert len(sp["idp"]) == 1 assert len(sp["idp"]) == 1
@@ -111,7 +117,9 @@ def test_missing_must():
no_entity_id = { no_entity_id = {
"service": { "service": {
"sp": { "sp": {
"url" : "http://lingon.catalogix.se:8087/", "endpoints" : {
"assertion_consumer_service" : ["http://lingon.catalogix.se:8087/"],
},
"name" : "test" "name" : "test"
} }
}, },
@@ -122,7 +130,9 @@ def test_missing_must():
"entityid" : "urn:mace:umu.se:saml:roland:sp", "entityid" : "urn:mace:umu.se:saml:roland:sp",
"service": { "service": {
"sp": { "sp": {
"url" : "http://lingon.catalogix.se:8087/", "endpoints" : {
"assertion_consumer_service" : ["http://lingon.catalogix.se:8087/"],
},
"name" : "test" "name" : "test"
} }
}, },
@@ -138,7 +148,9 @@ def test_minimum():
"entityid" : "urn:mace:example.com:saml:roland:sp", "entityid" : "urn:mace:example.com:saml:roland:sp",
"service": { "service": {
"sp": { "sp": {
"url" : "http://sp.example.org/", "endpoints" : {
"assertion_consumer_service" : ["http://sp.example.org/"],
},
"name" : "test", "name" : "test",
"idp": { "idp": {
"" : "https://example.com/idp/SSOService.php", "" : "https://example.com/idp/SSOService.php",
@@ -157,8 +169,15 @@ def test_idp():
print c print c
assert c.services() == ["idp"] 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("") attribute_restrictions = c.idp_policy().get_attribute_restriction("")
assert attribute_restrictions["eduPersonAffiliation"][0].match("staff") 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", "entityid" : "urn:mace:example.com:idp:2",
"service": { "service": {
"idp": { "idp": {
"url" : "http://idp.example.org/", "endpoints" : {
"single_sign_on_service" : ["http://idp.example.org/"],
},
"name" : "test", "name" : "test",
"assertions": { "assertions": {
"default": { "default": {
@@ -69,15 +71,17 @@ class TestIdentifier():
nameid = self.id.construct_nameid(policy, "foobar", nameid = self.id.construct_nameid(policy, "foobar",
"urn:mace:example.com:sp:1") "urn:mace:example.com:sp:1")
assert _eq(nameid.keys(), ['text', 'sp_name_qualifier', 'format']) assert _eq(nameid.keys(), ['text', 'sp_provided_id',
assert nameid["sp_name_qualifier"] == CONFIG["entityid"] 'sp_name_qualifier', 'name_qualifier', 'format'])
assert nameid["format"] == NAMEID_FORMAT_PERSISTENT 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", nameid_2 = self.id.construct_nameid(policy, "foobar",
"urn:mace:example.com:sp:1") "urn:mace:example.com:sp:1")
assert nameid == nameid_2 assert nameid != nameid_2
assert nameid["text"] == nameid_2["text"] assert nameid.text == nameid_2.text
def test_transient_1(self): def test_transient_1(self):
policy = Policy({ policy = Policy({
@@ -92,8 +96,8 @@ class TestIdentifier():
nameid = self.id.construct_nameid(policy, "foobar", nameid = self.id.construct_nameid(policy, "foobar",
"urn:mace:example.com:sp:1") "urn:mace:example.com:sp:1")
assert _eq(nameid.keys(), ['text', 'format']) assert _eq(nameid.keyswv(), ['text', 'format'])
assert nameid["format"] == NAMEID_FORMAT_TRANSIENT assert nameid.format == NAMEID_FORMAT_TRANSIENT
def test_vo_1(self): def test_vo_1(self):
policy = Policy({ policy = Policy({
@@ -112,11 +116,11 @@ class TestIdentifier():
{"uid": "foobar01"}, {"uid": "foobar01"},
name_id_policy) name_id_policy)
assert _eq(nameid.keys(), ['text', 'sp_name_qualifier', 'format']) assert _eq(nameid.keyswv(), ['text', 'sp_name_qualifier', 'format'])
assert nameid["sp_name_qualifier"] == 'http://vo.example.org/biomed' assert nameid.sp_name_qualifier == 'http://vo.example.org/biomed'
assert nameid["format"] == \ assert nameid.format == \
CONFIG.vo_conf('http://vo.example.org/biomed')["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): def test_vo_2(self):
policy = Policy({ policy = Policy({
@@ -136,8 +140,8 @@ class TestIdentifier():
{"uid": "foobar01"}, {"uid": "foobar01"},
name_id_policy) name_id_policy)
assert _eq(nameid.keys(), ['text', 'sp_name_qualifier', 'format']) assert _eq(nameid.keyswv(), ['text', 'sp_name_qualifier', 'format'])
assert nameid["sp_name_qualifier"] == 'http://vo.example.org/design' assert nameid.sp_name_qualifier == 'http://vo.example.org/design'
assert nameid["format"] == NAMEID_FORMAT_PERSISTENT assert nameid.format == NAMEID_FORMAT_PERSISTENT
assert nameid["text"] != "foobar01" assert nameid.text != "foobar01"

View File

@@ -4,9 +4,10 @@ import os
import base64 import base64
from saml2 import sigver, make_instance 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 time_util
from saml2 import saml, samlp from saml2 import saml, samlp
from saml2.s_utils import factory, do_attribute_statement
import xmldsig as ds import xmldsig as ds
from py.test import raises from py.test import raises
@@ -21,11 +22,11 @@ PRIV_KEY = "test.key"
def _eq(l1,l2): def _eq(l1,l2):
return set(l1) == set(l2) return set(l1) == set(l2)
SIGNED_VALUE= """AS1kHHtA4eTOU2XLTWhLMSJQ6V+TSDymRoTF78CqjrYURNLk9wjdPjAReNn9eykv SIGNED_VALUE= """kMuyOK17nyp4CbA1v7KE32rX4+NQQ8EvdglTK61uIMEo3ax0PgFU7bgZGey+Aj8H
ryFiHNk0p9wMBknha5pH8aeCI/LmcVhLa5xteGZrtE/Udh5vv8z4kRQX51Uz/5x8 hTPVyAzWmBDxHpSCFe050PTtNoKHx7nXprLfhuQXsPq8s0KBoZR+2qYfVCkWYVX7
ToiobGw83MEW6A0dRUn0O20NBMMTaFZZPXye7RvVlHY=""" T3zG/Tn+fesBA1zLo4lYdAovol7C35KAsAWoknmZdOE="""
DIGEST_VALUE = "WFRXmImfoO3M6JOLE6BGGpU9Ud0=" DIGEST_VALUE = "SXw3kqTf+PtTiUnI8nQ6xmrM3qw="
def get_xmlsec(): def get_xmlsec():
for path in os.environ["PATH"].split(":"): for path in os.environ["PATH"].split(":"):
@@ -94,24 +95,16 @@ class TestSecurity():
self.sec = sigver.SecurityContext(get_xmlsec(), PRIV_KEY, "pem", self.sec = sigver.SecurityContext(get_xmlsec(), PRIV_KEY, "pem",
PUB_KEY, "pem", debug=1) PUB_KEY, "pem", debug=1)
self._assertion = { self._assertion = factory( saml.Assertion,
"version": "2.0", version="2.0",
"id": "11111", id="11111",
"issue_instant": "2009-10-30T13:20:28Z", issue_instant="2009-10-30T13:20:28Z",
"signature": sigver.pre_signature_part("11111", self.sec.my_cert, signature=sigver.pre_signature_part("11111", self.sec.my_cert, 1),
1), attribute_statement=do_attribute_statement({
"attribute_statement": { ("","","surName"): ("Foo",""),
"attribute": [{ ("","","givenName") :("Bar",""),
"friendly_name": "surName", })
"attribute_value": "Foo", )
},
{
"friendly_name": "givenName",
"attribute_value": "Bar",
}
]
}
}
def test_verify_1(self): def test_verify_1(self):
xml_response = open(SIGNED).read() xml_response = open(SIGNED).read()
@@ -130,10 +123,10 @@ class TestSecurity():
xml_response) xml_response)
def test_sign_assertion(self): 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) sign_ass = self.sec.sign_assertion_using_xmlsec("%s" % ass, nodeid=ass.id)
print sign_ass
sass = saml.assertion_from_string(sign_ass) sass = saml.assertion_from_string(sign_ass)
print sass print sass
assert _eq(sass.keyswv(), ['attribute_statement', 'issue_instant', assert _eq(sass.keyswv(), ['attribute_statement', 'issue_instant',
@@ -144,15 +137,18 @@ class TestSecurity():
sig = sass.signature sig = sass.signature
assert sig.signature_value.text == SIGNED_VALUE assert sig.signature_value.text == SIGNED_VALUE
assert len(sig.signed_info.reference) == 1 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
assert sig.signed_info.reference[0].digest_value[0].text == DIGEST_VALUE assert sig.signed_info.reference[0].digest_value.text == DIGEST_VALUE
def test_sign_response(self): def test_sign_response(self):
s_response = sigver.signed_instance_factory(samlp.Response, { response = factory(samlp.Response,
"assertion" : self._assertion, assertion=self._assertion,
"id": "22222", id="22222",
"signature": sigver.pre_signature_part("22222"), signature=sigver.pre_signature_part("22222", self.sec.my_cert))
}, self.sec)
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 assert s_response != None
print s_response print s_response
@@ -166,37 +162,33 @@ class TestSecurity():
assert sass.id == "11111" assert sass.id == "11111"
assert time_util.str_to_time(sass.issue_instant) assert time_util.str_to_time(sass.issue_instant)
sig = sass.signature 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) == 1
assert len(sig.signed_info.reference[0].digest_value) == 1 assert sig.signed_info.reference[0].digest_value
digest = sig.signed_info.reference[0].digest_value[0].text digest = sig.signed_info.reference[0].digest_value.text
assert digest == """z6O3mlLmX1a6Wk1F4cgMsAXdA6Q=""" assert digest == """uX92C/YDroqITDfDY1IeekGtZac="""
def test_sign_response_2(self): def test_sign_response_2(self):
assertion2 = { assertion2 = factory( saml.Assertion,
"version": "2.0", version= "2.0",
"id": "11122", id= "11122",
"issue_instant": "2009-10-30T13:20:28Z", issue_instant= "2009-10-30T13:20:28Z",
"signature": sigver.pre_signature_part("11122"), signature= sigver.pre_signature_part("11122", self.sec.my_cert),
"attribute_statement": { attribute_statement=do_attribute_statement({
"attribute": [{ ("","","surName"): ("Fox",""),
"friendly_name": "surName", ("","","givenName") :("Bear",""),
"attribute_value": "Fox", })
}, )
{ response = factory(samlp.Response,
"friendly_name": "givenName", assertion=assertion2,
"attribute_value": "Bear", id="22233",
} signature=sigver.pre_signature_part("22233"))
]
}
}
s_response = sigver.signed_instance_factory(samlp.Response, { to_sign = [(class_name(assertion2), assertion2.id),
"assertion" : [self._assertion,assertion2], (class_name(response), response.id)]
"id": "22233",
"signature": sigver.pre_signature_part("22233"), s_response = sigver.signed_instance_factory( response, self.sec, to_sign)
}, self.sec)
assert s_response != None assert s_response != None
print s_response print s_response
@@ -207,23 +199,26 @@ class TestSecurity():
assert _eq(sass.keyswv(), ['attribute_statement', 'issue_instant', assert _eq(sass.keyswv(), ['attribute_statement', 'issue_instant',
'version', 'signature', 'id']) 'version', 'signature', 'id'])
assert sass.version == "2.0" assert sass.version == "2.0"
assert sass.id == "11111" assert sass.id == "11122"
assert time_util.str_to_time(sass.issue_instant) assert time_util.str_to_time(sass.issue_instant)
sig = sass.signature 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) == 1
assert len(sig.signed_info.reference[0].digest_value) == 1 assert sig.signed_info.reference[0].digest_value
digest = sig.signed_info.reference[0].digest_value[0].text digest = sig.signed_info.reference[0].digest_value.text
assert digest == """z6O3mlLmX1a6Wk1F4cgMsAXdA6Q=""" assert digest == """l36wHa6Lyed9ZeAZ3jFL77wPVQ4="""
def test_sign_verify(self): def test_sign_verify(self):
s_response = sigver.signed_instance_factory(samlp.Response, { response = factory(samlp.Response,
"assertion" : self._assertion, assertion=self._assertion,
"id": "22222", id="22233",
"signature": sigver.pre_signature_part("22222", signature=sigver.pre_signature_part("22233", self.sec.my_cert))
self.sec.my_cert),
}, self.sec) 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 print s_response
res = self.sec.verify_signature("%s" % s_response, res = self.sec.verify_signature("%s" % s_response,
@@ -233,16 +228,25 @@ class TestSecurity():
assert res assert res
def test_sign_verify_with_cert_from_instance(self): def test_sign_verify_with_cert_from_instance(self):
s_response = sigver.signed_instance_factory(samlp.Response, { response = factory(samlp.Response,
"assertion" : self._assertion, assertion=self._assertion,
"id": "22222", id="22222",
"signature": sigver.pre_signature_part("22222", signature=sigver.pre_signature_part("22222", self.sec.my_cert))
self.sec.my_cert),
}, self.sec)
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()) ci = "".join(sigver.cert_from_instance(s_response)[0].split())
print ci
print self.sec.my_cert
assert ci == self.sec.my_cert assert ci == self.sec.my_cert
res = self.sec.verify_signature("%s" % s_response, res = self.sec.verify_signature("%s" % s_response,
@@ -254,26 +258,19 @@ class TestSecurity():
assert res == s_response assert res == s_response
def test_sign_verify_assertion_with_cert_from_instance(self): def test_sign_verify_assertion_with_cert_from_instance(self):
assertion = { assertion = factory( saml.Assertion,
"version": "2.0", version= "2.0",
"id": "11111", id= "11100",
"issue_instant": "2009-10-30T13:20:28Z", issue_instant= "2009-10-30T13:20:28Z",
"signature": sigver.pre_signature_part("11111", self.sec.my_cert), signature= sigver.pre_signature_part("11100", self.sec.my_cert),
"attribute_statement": { attribute_statement=do_attribute_statement({
"attribute": [{ ("","","surName"): ("Fox",""),
"friendly_name": "surName", ("","","givenName") :("Bear",""),
"attribute_value": "Foo", })
}, )
{
"friendly_name": "givenName",
"attribute_value": "Bar",
}
]
}
}
s_assertion = sigver.signed_instance_factory(saml.Assertion, to_sign = [(class_name(assertion), assertion.id)]
assertion, self.sec) s_assertion = sigver.signed_instance_factory(assertion, self.sec, to_sign)
print s_assertion print s_assertion
ci = "".join(sigver.cert_from_instance(s_assertion)[0].split()) ci = "".join(sigver.cert_from_instance(s_assertion)[0].split())
@@ -289,30 +286,25 @@ class TestSecurity():
assert res assert res
def test_exception_sign_verify_with_cert_from_instance(self): def test_exception_sign_verify_with_cert_from_instance(self):
assertion = { assertion = factory( saml.Assertion,
"version": "2.0", version= "2.0",
"id": "11111", id= "11100",
"issue_instant": "2009-10-30T13:20:28Z", issue_instant= "2009-10-30T13:20:28Z",
#"signature": sigver.pre_signature_part("11111"), #signature= sigver.pre_signature_part("11100", self.sec.my_cert),
"attribute_statement": { attribute_statement=do_attribute_statement({
"attribute": [{ ("","","surName"): ("Foo",""),
"friendly_name": "surName", ("","","givenName") :("Bar",""),
"attribute_value": "Foo", })
}, )
{
"friendly_name": "givenName",
"attribute_value": "Bar",
}
]
}
}
s_response = sigver.signed_instance_factory(samlp.Response, { response = factory(samlp.Response,
"assertion" : assertion, assertion=assertion,
"id": "22222", id="22222",
"signature": sigver.pre_signature_part("22222", signature=sigver.pre_signature_part("22222", self.sec.my_cert))
self.sec.my_cert),
}, self.sec) 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 # Change something that should make everything fail
@@ -320,16 +312,3 @@ class TestSecurity():
raises(sigver.SignatureError, self.sec._check_signature, raises(sigver.SignatureError, self.sec._check_signature,
"%s" % s_response, s_response, class_name(s_response)) "%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 -*- # -*- coding: utf-8 -*-
from saml2 import samlp, BINDING_HTTP_POST 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.server import Server
from saml2.authnresponse import authn_response from saml2.authnresponse import authn_response
@@ -55,6 +55,7 @@ class TestAuthnResponse:
assert self.ar.came_from == 'http://localhost:8088/sso' assert self.ar.came_from == 'http://localhost:8088/sso'
assert self.ar.session_id() == "12" assert self.ar.session_id() == "12"
assert self.ar.ava == {'eduPersonEntitlement': ['Jeter'] } assert self.ar.ava == {'eduPersonEntitlement': ['Jeter'] }
assert self.ar.name_id
assert self.ar.issuer() == 'urn:mace:example.com:saml:roland:idp' assert self.ar.issuer() == 'urn:mace:example.com:saml:roland:idp'
def test_verify_signed_1(self): def test_verify_signed_1(self):
@@ -72,18 +73,20 @@ class TestAuthnResponse:
assert self.ar.session_id() == "12" assert self.ar.session_id() == "12"
assert self.ar.ava == {'eduPersonEntitlement': ['Jeter'] } assert self.ar.ava == {'eduPersonEntitlement': ['Jeter'] }
assert self.ar.issuer() == 'urn:mace:example.com:saml:roland:idp' assert self.ar.issuer() == 'urn:mace:example.com:saml:roland:idp'
assert self.ar.name_id
def test_parse_2(self): def test_parse_2(self):
xml_response = open(XML_RESPONSE_FILE).read() xml_response = open(XML_RESPONSE_FILE).read()
ID = "bahigehogffohiphlfmplepdpcohkhhmheppcdie" ID = "bahigehogffohiphlfmplepdpcohkhhmheppcdie"
self.ar.outstanding_queries = {ID: "http://localhost:8088/foo"} self.ar.outstanding_queries = {ID: "http://localhost:8088/foo"}
self.ar.requestor = "xenosmilus.umdc.umu.se" self.ar.requestor = "xenosmilus.umdc.umu.se"
self.ar.timeslack = 20000000 # roughly a year, should create the response on the fly
print self.ar.__dict__ self.ar.timeslack = 31536000
self.ar.loads(xml_response, decode=False) self.ar.loads(xml_response, decode=False)
self.ar.verify() self.ar.verify()
print self.ar print self.ar.__dict__
assert self.ar.came_from == 'http://localhost:8088/foo' assert self.ar.came_from == 'http://localhost:8088/foo'
assert self.ar.session_id() == ID 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.server import Server, Identifier
from saml2 import server, make_instance from saml2 import server, make_instance
from saml2 import samlp, saml, client, utils, config from saml2 import samlp, saml, client, config
from saml2.utils import OtherError from saml2 import s_utils
from saml2.utils import do_attribute_statement from saml2.s_utils import OtherError
from saml2.s_utils import do_attribute_statement, factory
from py.test import raises from py.test import raises
import shelve import shelve
import re import re
@@ -25,7 +26,7 @@ class TestServer1():
self.client = client.Saml2Client({},conf) self.client = client.Saml2Client({},conf)
def test_issuer(self): def test_issuer(self):
issuer = make_instance( saml.Issuer, self.server.issuer()) issuer = self.server.issuer()
assert isinstance(issuer, saml.Issuer) assert isinstance(issuer, saml.Issuer)
assert _eq(issuer.keyswv(), ["text","format"]) assert _eq(issuer.keyswv(), ["text","format"])
assert issuer.format == saml.NAMEID_FORMAT_ENTITY assert issuer.format == saml.NAMEID_FORMAT_ENTITY
@@ -33,27 +34,24 @@ class TestServer1():
def test_assertion(self): def test_assertion(self):
tmp = utils.assertion_factory( assertion = s_utils.assertion_factory(
subject= utils.args2dict("_aaa", subject= factory(saml.Subject, text="_aaa",
name_id=saml.NAMEID_FORMAT_TRANSIENT), name_id=factory(saml.NameID,
attribute_statement = utils.args2dict( format=saml.NAMEID_FORMAT_TRANSIENT)),
attribute=[ attribute_statement = do_attribute_statement({
utils.args2dict(attribute_value="Derek", ("","","surName"): ("Jeter",""),
friendly_name="givenName"), ("","","givenName") :("Derek",""),
utils.args2dict(attribute_value="Jeter", }),
friendly_name="surName"),
]),
issuer=self.server.issuer(), issuer=self.server.issuer(),
) )
assertion = make_instance(saml.Assertion, tmp)
assert _eq(assertion.keyswv(),['attribute_statement', 'issuer', 'id', assert _eq(assertion.keyswv(),['attribute_statement', 'issuer', 'id',
'subject', 'issue_instant', 'version']) 'subject', 'issue_instant', 'version'])
assert assertion.version == "2.0" assert assertion.version == "2.0"
assert assertion.issuer.text == "urn:mace:example.com:saml:roland:idp" assert assertion.issuer.text == "urn:mace:example.com:saml:roland:idp"
# #
assert len(assertion.attribute_statement) == 1 assert assertion.attribute_statement
attribute_statement = assertion.attribute_statement[0] attribute_statement = assertion.attribute_statement
assert len(attribute_statement.attribute) == 2 assert len(attribute_statement.attribute) == 2
attr0 = attribute_statement.attribute[0] attr0 = attribute_statement.attribute[0]
attr1 = attribute_statement.attribute[1] attr1 = attribute_statement.attribute[1]
@@ -70,28 +68,25 @@ class TestServer1():
subject = assertion.subject subject = assertion.subject
assert _eq(subject.keyswv(),["text", "name_id"]) assert _eq(subject.keyswv(),["text", "name_id"])
assert subject.text == "_aaa" 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): def test_response(self):
tmp = utils.response_factory( response = s_utils.response_factory(
in_response_to="_012345", in_response_to="_012345",
destination="https:#www.example.com", destination="https:#www.example.com",
status=utils.success_status_factory(), status=s_utils.success_status_factory(),
assertion=utils.assertion_factory( assertion=s_utils.assertion_factory(
subject = utils.args2dict("_aaa", subject = factory( saml.Subject, text="_aaa",
name_id=saml.NAMEID_FORMAT_TRANSIENT), name_id=saml.NAMEID_FORMAT_TRANSIENT),
attribute_statement = [ attribute_statement = do_attribute_statement({
utils.args2dict(attribute_value="Derek", ("","","surName"): ("Jeter",""),
friendly_name="givenName"), ("","","givenName") :("Derek",""),
utils.args2dict(attribute_value="Jeter", }),
friendly_name="surName"),
],
issuer=self.server.issuer(), issuer=self.server.issuer(),
), ),
issuer=self.server.issuer(), issuer=self.server.issuer(),
) )
response = make_instance(samlp.Response, tmp)
print response.keyswv() print response.keyswv()
assert _eq(response.keyswv(),['destination', 'assertion','status', assert _eq(response.keyswv(),['destination', 'assertion','status',
'in_response_to', 'issue_instant', 'in_response_to', 'issue_instant',
@@ -114,9 +109,9 @@ class TestServer1():
my_name = "My real name", 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 # should raise an error because faulty spentityid
raises(OtherError,self.server.parse_authn_request,intermed) raises(OtherError, self.server.parse_authn_request, intermed)
def test_parse_faulty_request_to_err_status(self): def test_parse_faulty_request_to_err_status(self):
authn_request = self.client.authn_request( authn_request = self.client.authn_request(
@@ -127,14 +122,13 @@ class TestServer1():
my_name = "My real name", my_name = "My real name",
) )
intermed = utils.deflate_and_base64_encode(authn_request) intermed = s_utils.deflate_and_base64_encode(authn_request)
try: try:
self.server.parse_authn_request(intermed) self.server.parse_authn_request(intermed)
status = None status = None
except OtherError, oe: except OtherError, oe:
print oe.args print oe.args
status = make_instance(samlp.Status, status = s_utils.status_from_exception_factory(oe)
utils.status_from_exception_factory(oe))
assert status assert status
print status print status
@@ -156,8 +150,9 @@ class TestServer1():
) )
print authn_request 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) response = self.server.parse_authn_request(intermed)
# returns a dictionary
print response print response
assert response["consumer_url"] == "http://localhost:8087/" assert response["consumer_url"] == "http://localhost:8087/"
assert response["id"] == "1" assert response["id"] == "1"
@@ -185,12 +180,13 @@ class TestServer1():
assert resp.status assert resp.status
assert resp.status.status_code.value == samlp.STATUS_SUCCESS assert resp.status.status_code.value == samlp.STATUS_SUCCESS
assert resp.assertion assert resp.assertion
assert len(resp.assertion) == 1 assert resp.assertion
assertion = resp.assertion[0] assertion = resp.assertion
assert len(assertion.authn_statement) == 1 print assertion
assert assertion.authn_statement
assert assertion.conditions assert assertion.conditions
assert len(assertion.attribute_statement) == 1 assert assertion.attribute_statement
attribute_statement = assertion.attribute_statement[0] attribute_statement = assertion.attribute_statement
print attribute_statement print attribute_statement
assert len(attribute_statement.attribute) == 1 assert len(attribute_statement.attribute) == 1
attribute = attribute_statement.attribute[0] 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" assert attribute.name_format == "urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
value = attribute.attribute_value[0] value = attribute.attribute_value[0]
assert value.text.strip() == "Short stop" assert value.text.strip() == "Short stop"
assert value.type == "xs:string" assert value.get_type() == "xs:string"
assert assertion.subject assert assertion.subject
assert assertion.subject.name_id assert assertion.subject.name_id
assert len(assertion.subject.subject_confirmation) == 1 assert assertion.subject.subject_confirmation
confirmation = assertion.subject.subject_confirmation[0] confirmation = assertion.subject.subject_confirmation
print confirmation.keyswv() print confirmation.keyswv()
print confirmation.subject_confirmation_data print confirmation.subject_confirmation_data
assert confirmation.subject_confirmation_data.in_response_to == "12" assert confirmation.subject_confirmation_data.in_response_to == "12"
@@ -227,7 +223,7 @@ class TestServer1():
assert not resp.assertion assert not resp.assertion
def test_sso_failure_response(self): 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", resp = self.server.error_response( "http://localhost:8087/", "12",
"urn:mace:example.com:saml:roland:sp", exc ) "urn:mace:example.com:saml:roland:sp", exc )
@@ -253,10 +249,8 @@ class TestServer1():
resp_str = self.server.authn_response(ava, resp_str = self.server.authn_response(ava,
"1", "http://local:8087/", "1", "http://local:8087/",
"urn:mace:example.com:saml:roland:sp", "urn:mace:example.com:saml:roland:sp",
make_instance(samlp.NameIDPolicy, samlp.NameIDPolicy(format=saml.NAMEID_FORMAT_TRANSIENT,
utils.args2dict( allow_create="true"),
format=saml.NAMEID_FORMAT_TRANSIENT,
allow_create="true")),
"foba0001@example.com") "foba0001@example.com")
response = samlp.response_from_string("\n".join(resp_str)) response = samlp.response_from_string("\n".join(resp_str))
@@ -324,12 +318,12 @@ class TestServer2():
assert response.version == "2.0" assert response.version == "2.0"
assert response.issuer.text == "urn:mace:example.com:saml:roland:idpr" assert response.issuer.text == "urn:mace:example.com:saml:roland:idpr"
assert response.status.status_code.value == samlp.STATUS_SUCCESS assert response.status.status_code.value == samlp.STATUS_SUCCESS
assert len(response.assertion) == 1 assert response.assertion
assertion = response.assertion[0] assertion = response.assertion
assert assertion.version == "2.0" assert assertion.version == "2.0"
subject = assertion.subject subject = assertion.subject
assert subject.name_id.format == saml.NAMEID_FORMAT_TRANSIENT assert subject.name_id.format == saml.NAMEID_FORMAT_TRANSIENT
assert len(subject.subject_confirmation) == 1 assert subject.subject_confirmation
subject_confirmation = subject.subject_confirmation[0] subject_confirmation = subject.subject_confirmation
assert subject_confirmation.subject_confirmation_data.in_response_to == "aaa" assert subject_confirmation.subject_confirmation_data.in_response_to == "aaa"

View File

@@ -2,12 +2,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import base64 import base64
from urlparse import urlparse, parse_qs
from saml2.client import Saml2Client from saml2.client import Saml2Client
from saml2 import samlp, client, BINDING_HTTP_POST 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.sigver import correctly_signed_authn_request, verify_signature
from saml2.server import Server from saml2.server import Server
from saml2.s_utils import decode_base64_and_inflate
import os import os
@@ -27,6 +29,8 @@ def ava(attribute_statement):
result[name].append(value.text.strip()) result[name].append(value.text.strip())
return result return result
def _leq(l1, l2):
return set(l1) == set(l2)
# def test_parse_3(): # def test_parse_3():
# xml_response = open(XML_RESPONSE_FILE3).read() # xml_response = open(XML_RESPONSE_FILE3).read()
@@ -41,7 +45,7 @@ def ava(attribute_statement):
# assert False # assert False
REQ1 = """<?xml version='1.0' encoding='UTF-8'?> 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: class TestClient:
@@ -63,6 +67,7 @@ class TestClient:
nameid_format=saml.NAMEID_FORMAT_PERSISTENT) nameid_format=saml.NAMEID_FORMAT_PERSISTENT)
str = "%s" % req.to_string() str = "%s" % req.to_string()
print str print str
print REQ1 % req.issue_instant
assert str == REQ1 % req.issue_instant assert str == REQ1 % req.issue_instant
assert req.destination == "https://idp.example.com/idp/" assert req.destination == "https://idp.example.com/idp/"
assert req.id == "1" assert req.id == "1"
@@ -72,7 +77,7 @@ class TestClient:
assert name_id.format == saml.NAMEID_FORMAT_PERSISTENT assert name_id.format == saml.NAMEID_FORMAT_PERSISTENT
assert name_id.text == "E8042FB4-4D5B-48C3-8E14-8EDD852790DD" assert name_id.text == "E8042FB4-4D5B-48C3-8E14-8EDD852790DD"
issuer = req.issuer 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): def test_create_attribute_query2(self):
req = self.client.create_attribute_query("1", req = self.client.create_attribute_query("1",
@@ -130,7 +135,7 @@ class TestClient:
assert req.id == "1" assert req.id == "1"
assert req.version == "2.0" assert req.version == "2.0"
assert req.issue_instant 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 nameid = req.subject.name_id
assert nameid.format == saml.NAMEID_FORMAT_TRANSIENT assert nameid.format == saml.NAMEID_FORMAT_TRANSIENT
assert nameid.text == "_e7b68a04488f715cda642fbdd90099f5" assert nameid.text == "_e7b68a04488f715cda642fbdd90099f5"
@@ -146,23 +151,22 @@ class TestClient:
assert req == None assert req == None
def test_idp_entry(self): def test_idp_entry(self):
idp_entry = make_instance( samlp.IDPEntry, idp_entry = self.client.idp_entry(name="Umeå Universitet",
self.client.idp_entry(name="Umeå Universitet", location="https://idp.umu.se/")
location="https://idp.umu.se/"))
assert idp_entry.name == "Umeå Universitet" assert idp_entry.name == "Umeå Universitet"
assert idp_entry.loc == "https://idp.umu.se/" assert idp_entry.loc == "https://idp.umu.se/"
def test_scope(self): def test_scope(self):
scope = make_instance(samlp.Scoping, self.client.scoping( entity_id = "urn:mace:example.com:saml:roland:idp"
[self.client.idp_entry(name="Umeå Universitet", locs = self.client.metadata.single_sign_on_services(entity_id)
location="https://idp.umu.se/")])) scope = self.client.scoping_from_metadata(entity_id, locs)
assert scope.idp_list assert scope.idp_list
assert len(scope.idp_list.idp_entry) == 1 assert len(scope.idp_list.idp_entry) == 1
idp_entry = scope.idp_list.idp_entry[0] idp_entry = scope.idp_list.idp_entry[0]
assert idp_entry.name == "Umeå Universitet" assert idp_entry.name == 'Example Co'
assert idp_entry.loc == "https://idp.umu.se/" assert idp_entry.loc == ['http://localhost:8088/sso/']
def test_create_auth_request_0(self): def test_create_auth_request_0(self):
ar_str = self.client.authn_request("1", ar_str = self.client.authn_request("1",
@@ -186,7 +190,7 @@ class TestClient:
assert self.client.config["virtual_organization"].keys() == [ assert self.client.config["virtual_organization"].keys() == [
"urn:mace:example.com:it:tek"] "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.com/sso",
"http://www.example.org/service", "http://www.example.org/service",
"urn:mace:example.org:saml:sp", "urn:mace:example.org:saml:sp",
@@ -195,6 +199,7 @@ class TestClient:
ar = samlp.authn_request_from_string(ar_str) ar = samlp.authn_request_from_string(ar_str)
print ar print ar
assert ar.id == "666"
assert ar.assertion_consumer_service_url == "http://www.example.org/service" assert ar.assertion_consumer_service_url == "http://www.example.org/service"
assert ar.destination == "http://www.example.com/sso" assert ar.destination == "http://www.example.com/sso"
assert ar.protocol_binding == BINDING_HTTP_POST 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)) self.client.sec.verify_signature(ar_str, node_name=class_name(ar))
def test_response(self): def test_response(self):
IDP = "urn:mace:example.com:saml:roland:idp"
ava = { "givenName": ["Derek"], "surname": ["Jeter"], ava = { "givenName": ["Derek"], "surname": ["Jeter"],
"mail": ["derek@nyy.mlb.com"]} "mail": ["derek@nyy.mlb.com"]}
resp_str = "\n".join(self.server.authn_response(ava, resp_str = "\n".join(self.server.authn_response(
"1", "http://local:8087/", identity=ava,
"urn:mace:example.com:saml:roland:sp", in_response_to="1",
make_instance(samlp.NameIDPolicy, destination="http://local:8087/",
utils.args2dict( sp_entity_id="urn:mace:example.com:saml:roland:sp",
format=saml.NAMEID_FORMAT_TRANSIENT, name_id_policy=samlp.NameIDPolicy(
allow_create="true")), format=saml.NAMEID_FORMAT_PERSISTENT),
"foba0001@example.com")) userid="foba0001@example.com"))
resp_str = base64.encodestring(resp_str) resp_str = base64.encodestring(resp_str)
@@ -253,7 +260,106 @@ class TestClient:
{"1":"http://foo.example.com/service"}) {"1":"http://foo.example.com/service"})
assert authn_response != None assert authn_response != None
assert authn_response.issuer() == IDP
assert authn_response.response.assertion[0].issuer.text == IDP
session_info = authn_response.session_info() 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) response = samlp.response_from_string(authn_response.xmlstr)
assert response.destination == "http://local:8087/" 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 #!/usr/bin/env python
import os import os
import getopt import getopt
import xmldsig as ds
from saml2 import utils, md, samlp, BINDING_HTTP_POST, BINDING_HTTP_REDIRECT from saml2 import utils, md, samlp, BINDING_HTTP_POST, BINDING_HTTP_REDIRECT
from saml2 import BINDING_SOAP, class_name, make_instance from saml2 import BINDING_SOAP, class_name, make_instance
from saml2.time_util import in_a_while 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.saml import NAME_FORMAT_URI
from saml2.sigver import pre_signature_part, SecurityContext from saml2.sigver import pre_signature_part, SecurityContext
from saml2.attribute_converter import from_local_name, ac_factory from saml2.attribute_converter import from_local_name, ac_factory
@@ -30,155 +32,248 @@ class Usage(Exception):
DEFAULTS = { DEFAULTS = {
"want_assertions_signed": "true", "want_assertions_signed": "true",
"authn_requests_signed": "false", "authn_requests_signed": "false",
"want_authn_requests_signed": "true",
} }
ORG_ATTR_TRANSL = { ORG_ATTR_TRANSL = {
"organization_name": "name", "organization_name": ("name", md.OrganizationName),
"organization_display_name": "display_name", "organization_display_name": ("display_name", md.OrganizationDisplayName),
"organization_url": "url", "organization_url": ("url", md.OrganizationURL)
} }
PERSON_ATTR_TRANSL = { def _localized_name(val, klass):
"company": "company", try:
"given_name": "givenname", (text,lang) = val
"sur_name": "surname", return klass(text=text,lang=lang)
"email_address": "mail", except ValueError:
"telephone_number": "phone", return klass(text=val)
"type": "type",
}
def _localized_name(tup): def do_organization_info(conf):
if tup[1]: """ decription of an organization in the configuration is
return args2dict(tup[0],lang=tup[1]) a dictionary of keys and values, where the values might be tuples.
else:
return tup[0]
def do_organization_info(conf, desc): "organization": {
""" """ "name": ("AB Exempel", "se"),
"display_name": ("AB Exempel", "se"),
"url": "http://www.example.org"
}
"""
try: try:
corg = conf["organization"] corg = conf["organization"]
dorg = desc["organization"] = {} org = md.Organization()
for dkey, (ckey, klass) in ORG_ATTR_TRANSL.items():
for (dkey, ckey) in ORG_ATTR_TRANSL.items():
if ckey not in corg: if ckey not in corg:
continue continue
if isinstance(corg[ckey], basestring): if isinstance(corg[ckey], basestring):
dorg[dkey] = [corg[ckey]] setattr(org, dkey, [_localized_name(corg[ckey], klass)])
elif isinstance(corg[ckey], tuple): elif isinstance(corg[ckey], list):
dorg[dkey] = [_localized_name(corg[ckey])] setattr(org, dkey, [_localized_name(n, klass) for n in corg[ckey]])
else: else:
dorg[dkey] = [] setattr(org, dkey, [_localized_name(corg[ckey], klass)])
for val in corg[ckey]: return org
if isinstance(val,tuple): except KeyError:
dorg[dkey].append(_localized_name(val)) 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:
for val in value:
data.append(classpec[0](text=val))
else: else:
dorg[dkey].append(val) data = classpec(text=value)
setattr(cp, key, data)
except KeyError:
pass
for (prop, classpec, req) in contact_person.c_attributes.values():
try:
# should do a check for valid value
setattr(cp, prop, corg[prop])
except KeyError:
pass
cps.append(cp)
except KeyError: except KeyError:
pass pass
return cps
def do_contact_person_info(conf, desc): def do_key_descriptor(cert):
if "contact_person" in conf: return md.KeyDescriptor(
desc["contact_person"] = [] key_info=ds.KeyInfo(
for corg in conf["contact_person"]: x509_data=ds.X509Data(
dorg = {} x509_certificate=ds.X509Certificate(text=cert)
for (dkey, ckey) in PERSON_ATTR_TRANSL.items(): )
try: )
dorg[dkey] = corg[ckey] )
except:
pass
desc["contact_person"].append(dorg)
def do_sp_sso_descriptor(sp, cert, acs): def do_requested_attribute(attributes, acs, is_required="false"):
desc = { lista = []
"protocol_support_enumeration": samlp.NAMESPACE, for attr in attributes:
"assertion_consumer_service": { attr = from_local_name(acs, attr, NAME_FORMAT_URI)
"binding": BINDING_HTTP_POST , args = {}
"location": sp["url"], for key in attr.keyswv():
"index": 0, args[key] = getattr(attr,key)
}, args["is_required"] = is_required
"key_descriptor":{ lista.append(md.RequestedAttribute(**args))
"key_info": { return lista
"x509_data": {
"x509_certificate": cert 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),
},
"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"]: for key in ["want_assertions_signed", "authn_requests_signed"]:
try: try:
desc[key] = "%s" % sp[key] setattr(spsso, key, "%s" % sp[key])
except KeyError: except KeyError:
desc[key] = DEFAULTS[key] setattr(spsso, key, DEFAULTS[key])
requested_attribute = [] requested_attributes = []
if "required_attributes" in sp: if "required_attributes" in sp:
for attr in sp["required_attributes"]: requested_attributes.extend(do_requested_attribute(
reqa = from_local_name(acs, attr, NAME_FORMAT_URI) sp["required_attributes"],
reqa["is_required"] = "true" acs,
requested_attribute.append(reqa) is_required="true"))
if "optional_attributes" in sp: if "optional_attributes" in sp:
for attr in sp["optional_attributes"]: requested_attributes.extend(do_requested_attribute(
reqa = from_local_name(acs, attr, NAME_FORMAT_URI) sp["optional_attributes"],
requested_attribute.append(reqa) acs,
is_required="false"))
if requested_attribute: if requested_attributes:
desc["attribute_consuming_service"] = { spsso.attribute_consuming_service = [md.AttributeConsumingService(
"requested_attribute": requested_attribute, requested_attribute=requested_attributes,
"service_name": { service_name= [md.ServiceName(lang="en",text=sp["name"])]
"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: # if "discovery_service" in sp:
desc["extensions"] = {"extension_elements":[ # spsso.extensions= {"extension_elements":[
{ # {
"tag":"DiscoveryResponse", # "tag":"DiscoveryResponse",
"namespace":md.IDPDISC, # "namespace":md.IDPDISC,
"attributes": { # "attributes": {
"index":"1", # "index":"1",
"binding": md.IDPDISC, # "binding": md.IDPDISC,
"location":sp["url"] # "location":sp["url"]
} # }
} # }
]} # ]}
return desc return spsso
def do_idp_sso_descriptor(idp, cert): def do_idp_sso_descriptor(idp, cert=None):
return { idpsso = md.IDPSSODescriptor()
"protocol_support_enumeration": samlp.NAMESPACE, idpsso.protocol_support_enumeration=samlp.NAMESPACE
"want_authn_requests_signed": True,
"single_sign_on_service": { if idp["endpoints"]:
"binding": BINDING_HTTP_REDIRECT , for (endpoint, instlist) in do_endpoints(idp["endpoints"],
"location": idp["url"], ENDPOINTS["idp"]).items():
}, setattr(idpsso, endpoint, instlist)
"key_descriptor":{
"key_info": { if cert:
"x509_data": { idpsso.key_descriptor=do_key_descriptor(cert)
"x509_certificate": 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): def do_aa_descriptor(aa, cert):
return { aa = md.AttributeAuthorityDescriptor()
"protocol_support_enumeration": samlp.NAMESPACE, aa.protocol_support_enumeration=samlp.NAMESPACE
"attribute_service": {
"binding": BINDING_SOAP , if idp["endpoints"]:
"location": aa["url"], for (endpoint, instlist) in do_endpoints(aa["endpoints"],
}, ENDPOINTS["aa"]).items():
"key_descriptor":{ setattr(aasso, endpoint, instlist)
"key_info": {
"x509_data": { if cert:
"x509_certificate": cert aa.key_descriptor=do_key_descriptor(cert)
}
} return aa
},
}
def entity_descriptor(confd, valid_for): def entity_descriptor(confd, valid_for):
mycert = "".join(open(confd["cert_file"]).readlines()[1:-1]) mycert = "".join(open(confd["cert_file"]).readlines()[1:-1])
@@ -193,45 +288,43 @@ def entity_descriptor(confd, valid_for):
#else: #else:
# backward = {} # backward = {}
ed = { ed = md.EntityDescriptor(entity_id=confd["entityid"])
"entity_id": confd["entityid"],
}
if valid_for:
ed["valid_until"] = in_a_while(hours=valid_for)
do_organization_info(confd, ed) if valid_for:
do_contact_person_info(confd, ed) 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"]: if "sp" in confd["service"]:
# The SP # The SP
ed["sp_sso_descriptor"] = do_sp_sso_descriptor(confd["service"]["sp"], ed.sp_sso_descriptor = do_sp_sso_descriptor(confd["service"]["sp"],
mycert, attrconverters) attrconverters, mycert)
if "idp" in confd["service"]: 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) confd["service"]["idp"], mycert)
if "aa" in confd["service"]: if "aa" in confd["service"]:
ed["attribute_authority_descriptor"] = do_aa_descriptor( ed.attribute_authority_descriptor = do_aa_descriptor(
confd["service"]["aa"], mycert) confd["service"]["aa"], mycert)
return ed return ed
def entities_descriptor(eds, valid_for, name, id, sign, sc): def entities_descriptor(eds, valid_for, name, id, sign, sc):
d = {"entity_descriptor": eds} entities = md.EntitiesDescriptor(entity_descriptor= eds)
if valid_for: if valid_for:
d["valid_until"] = in_a_while(hours=valid_for) entities.valid_until = in_a_while(hours=valid_for)
if name: if name:
d["name"] = name entities.name = name
if id: if id:
d["id"] = id entities.id = id
if sign: if sign:
d["signature"] = pre_signature_part(d["id"]) entities.signature = pre_signature_part(id)
statement = make_instance(md.EntitiesDescriptor, d)
if sign: if sign:
statement = sc.sign_statement_using_xmlsec("%s" % statement, entities = sc.sign_statement_using_xmlsec("%s" % entities,
class_name(statement)) class_name(entities))
return statement return entities
def main(args): def main(args):