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:
@@ -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,19 +97,8 @@ 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):
|
||||||
"""
|
"""
|
||||||
If more than one idp and if none is selected, I have to do wayf or
|
If more than one idp and if none is selected, I have to do wayf or
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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):
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
return res
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def scoping(self, idp_ents):
|
def scoping_from_metadata(self, entityid, location=None):
|
||||||
return {
|
|
||||||
"idp_list": {
|
|
||||||
"idp_entry": idp_ents
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def scoping_from_metadata(self, entityid, location):
|
|
||||||
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:
|
||||||
return None
|
self.users.add_information_about_person(aresp.session_info())
|
||||||
|
|
||||||
|
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,
|
||||||
@@ -333,6 +380,9 @@ 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
|
||||||
@@ -340,8 +390,8 @@ class Saml2Client(object):
|
|||||||
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,32 +399,68 @@ 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
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for entity_id in self.users.issuers_of_info(subject_id):
|
||||||
|
destination = self.config["service"]["sp"]["idp"][entity_id]
|
||||||
|
|
||||||
|
# create NameID from subject_id
|
||||||
|
name_id = NameID(
|
||||||
|
text=self.client.users.get_entityid(subject_id,
|
||||||
|
entity_id)["name_id"])
|
||||||
|
|
||||||
|
request = samlp.LogoutRequest(
|
||||||
|
id=sid(),
|
||||||
|
version=VERSION,
|
||||||
|
issue_instant=instant(),
|
||||||
|
destination=destination,
|
||||||
|
issuer=self.issuer(),
|
||||||
|
session_index=session_id,
|
||||||
|
name_id = name_id
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
prel = {
|
if reason:
|
||||||
"id": sid(),
|
request.reason = reason
|
||||||
"version": VERSION,
|
|
||||||
"issue_instant": instant(),
|
|
||||||
"destination": destination,
|
|
||||||
"issuer": issuer,
|
|
||||||
"session_index": session_id,
|
|
||||||
}
|
|
||||||
|
|
||||||
if reason:
|
if not_on_or_after:
|
||||||
prel["reason"] = reason
|
request.not_on_or_after = not_on_or_after
|
||||||
|
|
||||||
if not_on_or_after:
|
result.append(request)
|
||||||
prel["not_on_or_after"] = not_on_or_after
|
|
||||||
|
return result
|
||||||
return make_instance(samlp.LogoutRequest, prel)
|
|
||||||
|
|
||||||
def logout(self, session_id, destination,
|
def global_logout(self, subject_id, reason="", not_on_or_after=None):
|
||||||
issuer, reason="", not_on_or_after=None):
|
requests = self.make_logout_requests(subject_id, reason,
|
||||||
return self.make_logout_request(session_id, destination,
|
not_on_or_after)
|
||||||
issuer, 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
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
ROW = """<tr><td>%s</td><td>%s</td></tr>"""
|
ROW = """<tr><td>%s</td><td>%s</td></tr>"""
|
||||||
|
|||||||
@@ -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,7 +95,8 @@ 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"]
|
||||||
if "metadata" in config:
|
if "metadata" in config:
|
||||||
@@ -130,15 +131,36 @@ 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]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
def idp_url(self):
|
|
||||||
return self["service"]["idp"]["url"]
|
|
||||||
|
|
||||||
def vo_conf(self, name):
|
def vo_conf(self, name):
|
||||||
return self["virtual_organization"][name]
|
return self["virtual_organization"][name]
|
||||||
|
|
||||||
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
|
||||||
2840
src/saml2/md.py
2840
src/saml2/md.py
File diff suppressed because it is too large
Load Diff
@@ -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,23 +394,26 @@ 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
|
||||||
|
|
||||||
@keep_updated
|
@keep_updated
|
||||||
|
|||||||
2117
src/saml2/saml.py
2117
src/saml2/saml.py
File diff suppressed because it is too large
Load Diff
2506
src/saml2/samlp.py
2506
src/saml2/samlp.py
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||||
@@ -104,9 +104,12 @@ class Identifier(object):
|
|||||||
nameid_format = vo_conf["nameid_format"]
|
nameid_format = vo_conf["nameid_format"]
|
||||||
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,9 +191,8 @@ 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)
|
||||||
|
|
||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -611,16 +633,34 @@ def pre_signature_part(ident, public_key=None, id=None):
|
|||||||
:param public_key: The base64 part of a PEM file
|
:param public_key: The base64 part of a PEM file
|
||||||
:return: A preset signature part
|
:return: A preset signature part
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
signature_method = ds.SignatureMethod(algorithm = ds.SIG_RSA_SHA1)
|
||||||
|
canonicalization_method = ds.CanonicalizationMethod(
|
||||||
|
algorithm = ds.ALG_EXC_C14N)
|
||||||
|
trans0 = ds.Transform(algorithm = ds.TRANSFORM_ENVELOPED)
|
||||||
|
trans1 = ds.Transform(algorithm = ds.ALG_EXC_C14N)
|
||||||
|
transforms = ds.Transforms(transform = [trans0, trans1])
|
||||||
|
digest_method = ds.DigestMethod(algorithm = ds.DIGEST_SHA1)
|
||||||
|
|
||||||
presig = copy.deepcopy(PRE_SIGNATURE)
|
reference = ds.Reference(uri = "#%s" % ident,
|
||||||
presig["signed_info"]["reference"]["uri"] = "#%s" % ident
|
digest_value = ds.DigestValue(),
|
||||||
if id:
|
transforms = transforms,
|
||||||
presig["id"] = "Signature%d" % id
|
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:
|
if public_key:
|
||||||
presig["key_info"] = {
|
x509_data = ds.X509Data(x509_certificate=[ds.X509Certificate(text=public_key)])
|
||||||
"x509_data": {
|
key_info = ds.KeyInfo(x509_data=x509_data)
|
||||||
"x509_certificate": public_key,
|
signature.key_info = key_info
|
||||||
}
|
|
||||||
}
|
return signature
|
||||||
|
|
||||||
return presig
|
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
@@ -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>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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},
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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"
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -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"
|
|
||||||
@@ -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
|
|
||||||
1166
tests/test_02_md.py
1166
tests/test_02_md.py
File diff suppressed because it is too large
Load Diff
@@ -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)
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
)
|
|
||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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')]
|
||||||
|
|
||||||
|
|
||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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,38 +162,34 @@ 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"))
|
||||||
]
|
|
||||||
}
|
to_sign = [(class_name(assertion2), assertion2.id),
|
||||||
}
|
(class_name(response), response.id)]
|
||||||
|
|
||||||
|
s_response = sigver.signed_instance_factory( response, self.sec, to_sign)
|
||||||
|
|
||||||
s_response = sigver.signed_instance_factory(samlp.Response, {
|
|
||||||
"assertion" : [self._assertion,assertion2],
|
|
||||||
"id": "22233",
|
|
||||||
"signature": sigver.pre_signature_part("22233"),
|
|
||||||
}, self.sec)
|
|
||||||
|
|
||||||
assert s_response != None
|
assert s_response != None
|
||||||
print s_response
|
print s_response
|
||||||
print
|
print
|
||||||
@@ -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
|
|
||||||
|
|||||||
@@ -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()
|
|
||||||
@@ -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"]"""
|
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|
||||||
@@ -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,156 +32,249 @@ 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",
|
|
||||||
"given_name": "givenname",
|
|
||||||
"sur_name": "surname",
|
|
||||||
"email_address": "mail",
|
|
||||||
"telephone_number": "phone",
|
|
||||||
"type": "type",
|
|
||||||
}
|
|
||||||
|
|
||||||
def _localized_name(tup):
|
|
||||||
if tup[1]:
|
|
||||||
return args2dict(tup[0],lang=tup[1])
|
|
||||||
else:
|
|
||||||
return tup[0]
|
|
||||||
|
|
||||||
def do_organization_info(conf, desc):
|
|
||||||
""" """
|
|
||||||
try:
|
try:
|
||||||
corg = conf["organization"]
|
(text,lang) = val
|
||||||
dorg = desc["organization"] = {}
|
return klass(text=text,lang=lang)
|
||||||
|
except ValueError:
|
||||||
for (dkey, ckey) in ORG_ATTR_TRANSL.items():
|
return klass(text=val)
|
||||||
|
|
||||||
|
def do_organization_info(conf):
|
||||||
|
""" decription of an organization in the configuration is
|
||||||
|
a dictionary of keys and values, where the values might be tuples.
|
||||||
|
|
||||||
|
"organization": {
|
||||||
|
"name": ("AB Exempel", "se"),
|
||||||
|
"display_name": ("AB Exempel", "se"),
|
||||||
|
"url": "http://www.example.org"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
corg = conf["organization"]
|
||||||
|
org = md.Organization()
|
||||||
|
for dkey, (ckey, klass) 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
|
def do_requested_attribute(attributes, acs, is_required="false"):
|
||||||
desc["contact_person"].append(dorg)
|
lista = []
|
||||||
|
for attr in attributes:
|
||||||
|
attr = from_local_name(acs, attr, NAME_FORMAT_URI)
|
||||||
|
args = {}
|
||||||
|
for key in attr.keyswv():
|
||||||
|
args[key] = getattr(attr,key)
|
||||||
|
args["is_required"] = is_required
|
||||||
|
lista.append(md.RequestedAttribute(**args))
|
||||||
|
return lista
|
||||||
|
|
||||||
|
ENDPOINTS = {
|
||||||
|
"sp": {
|
||||||
|
"artifact_resolution_service": (md.ArtifactResolutionService, True),
|
||||||
|
"single_logout_service": (md.SingleLogoutService, False),
|
||||||
|
"manage_name_id_service": (md.ManageNameIDService, False),
|
||||||
|
"assertion_consumer_service": (md.AssertionConsumerService, True),
|
||||||
|
},
|
||||||
|
"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),
|
||||||
|
|
||||||
def do_sp_sso_descriptor(sp, cert, acs):
|
"assertion_id_request_service": (md.AssertionIDRequestService, False),
|
||||||
desc = {
|
},
|
||||||
"protocol_support_enumeration": samlp.NAMESPACE,
|
"aa":{
|
||||||
"assertion_consumer_service": {
|
"artifact_resolution_service": (md.ArtifactResolutionService, True),
|
||||||
"binding": BINDING_HTTP_POST ,
|
"single_logout_service": (md.SingleLogoutService, False),
|
||||||
"location": sp["url"],
|
"manage_name_id_service": (md.ManageNameIDService, False),
|
||||||
"index": 0,
|
|
||||||
},
|
"assertion_id_request_service": (md.AssertionIDRequestService, False),
|
||||||
"key_descriptor":{
|
|
||||||
"key_info": {
|
"attribute_service": (md.AttributeService, False)
|
||||||
"x509_data": {
|
},
|
||||||
"x509_certificate": cert
|
}
|
||||||
}
|
|
||||||
}
|
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": {
|
|
||||||
"x509_data": {
|
|
||||||
"x509_certificate": cert
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if cert:
|
||||||
|
idpsso.key_descriptor=do_key_descriptor(cert)
|
||||||
|
|
||||||
|
for key in ["want_authn_requests_signed"]:
|
||||||
|
try:
|
||||||
|
setattr(idpsso, key, "%s" % idp[key])
|
||||||
|
except KeyError:
|
||||||
|
setattr(idpsso, key, DEFAULTS[key])
|
||||||
|
|
||||||
|
return idpsso
|
||||||
|
|
||||||
def do_aa_descriptor(aa, cert):
|
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 ,
|
|
||||||
"location": aa["url"],
|
|
||||||
},
|
|
||||||
"key_descriptor":{
|
|
||||||
"key_info": {
|
|
||||||
"x509_data": {
|
|
||||||
"x509_certificate": cert
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if idp["endpoints"]:
|
||||||
|
for (endpoint, instlist) in do_endpoints(aa["endpoints"],
|
||||||
|
ENDPOINTS["aa"]).items():
|
||||||
|
setattr(aasso, endpoint, instlist)
|
||||||
|
|
||||||
|
if cert:
|
||||||
|
aa.key_descriptor=do_key_descriptor(cert)
|
||||||
|
|
||||||
|
return aa
|
||||||
|
|
||||||
def entity_descriptor(confd, valid_for):
|
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:
|
if valid_for:
|
||||||
ed["valid_until"] = in_a_while(hours=valid_for)
|
ed.valid_until = in_a_while(hours=valid_for)
|
||||||
|
|
||||||
do_organization_info(confd, ed)
|
ed.organization = do_organization_info(confd)
|
||||||
do_contact_person_info(confd, ed)
|
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):
|
||||||
|
|||||||
Reference in New Issue
Block a user