This commit is contained in:
Roland Hedberg 2014-10-02 16:04:41 +02:00
parent 095f8dbe1d
commit 13fdda52ab
43 changed files with 456 additions and 449 deletions

View File

@ -1,2 +1,2 @@
# -*- coding: utf-8 -*-
# Created by Roland Hedberg
# Created by Roland Hedberg

View File

@ -6,7 +6,7 @@ from paste.httpheaders import REQUEST_METHOD
from paste.httpheaders import CONTENT_TYPE
from paste.httpheaders import USER_AGENT
import re
import re
_DAV_METHODS = (
'OPTIONS',
@ -74,9 +74,9 @@ class MyChallengeDecider:
environ['samlsp.logout'] = True
return True
# If the user is already authent, whatever happens(except logout),
# If the user is already authent, whatever happens(except logout),
# don't make a challenge
if environ.has_key('repoze.who.identity'):
if environ.has_key('repoze.who.identity'):
return False
# require a challenge for login

View File

@ -7,18 +7,18 @@ from zope.interface import implements
from repoze.who.interfaces import IMetadataProvider
class EntitlementMetadataProvider(object):
implements(IMetadataProvider)
def __init__(self, filename, key_attribute):
# Means I have to do explicit syncs on writes, but also
# that it's faster on reads since it will cache data
self._store = shelve.open(filename, writeback=True)
self.key_attribute = key_attribute
def keys(self):
return self._store.keys()
def get(self, user, attribute):
return self._store[user][attribute]
@ -28,19 +28,19 @@ class EntitlementMetadataProvider(object):
self._store[user][attribute] = value
self._store.sync()
def part_of(self, user, virtualorg):
if virtualorg in self._store[user]["entitlement"]:
return True
else:
return False
def get_entitlement(self, user, virtualorg):
try:
return self._store[user]["entitlement"][virtualorg]
except KeyError:
return []
def store_entitlement(self, user, virtualorg, entitlement=None):
if user not in self._store:
self._store[user] = {"entitlement":{}}
@ -51,14 +51,14 @@ class EntitlementMetadataProvider(object):
entitlement = []
self._store[user]["entitlement"][virtualorg] = entitlement
self._store.sync()
def add_metadata(self, environ, identity):
#logger = environ.get('repoze.who.logger','')
try:
user = self._store[identity.get('repoze.who.userid')]
except KeyError:
return
try:
vorg = environ["myapp.vo"]
try:
@ -72,6 +72,6 @@ class EntitlementMetadataProvider(object):
for vorg, ents in user["entitlement"].items():
res.extend(["%s:%s" % (vorg, e) for e in ents])
identity["user"] = res
def make_plugin(filename, key_attribute=""):
return EntitlementMetadataProvider(filename, key_attribute)

View File

@ -40,7 +40,7 @@ HIDDEN_PRE_LINE = """<input type=hidden name="%s" value="%s">"""
class FormHiddenPlugin(FormPlugin):
implements(IChallenger, IIdentifier)
# IIdentifier
def identify(self, environ):
logger = environ.get('repoze.who.logger','')
@ -49,7 +49,7 @@ class FormHiddenPlugin(FormPlugin):
query = parse_dict_querystring(environ)
# If the extractor finds a special query string on any request,
# it will attempt to find the values in the input body.
if query.get(self.login_form_qs):
if query.get(self.login_form_qs):
form = parse_formvars(environ)
from StringIO import StringIO
# we need to replace wsgi.input because we've read it
@ -89,7 +89,7 @@ class FormHiddenPlugin(FormPlugin):
if location:
headers = list(app_headers) + list(forget_headers)
return HTTPFound(headers = headers)
query = parse_dict_querystring(environ)
hidden = []
for key, val in query.items():
@ -98,7 +98,7 @@ class FormHiddenPlugin(FormPlugin):
logger.info("hidden: %s" % (hidden,))
form = self.formbody or _DEFAULT_FORM
form = form % "\n".join(hidden)
if self.formcallable is not None:
form = self.formcallable(environ)
def auth_form(environ, start_response):

View File

@ -6,15 +6,15 @@ from zope.interface import implements
from repoze.who.interfaces import IMetadataProvider
class INIMetadataProvider(object):
implements(IMetadataProvider)
def __init__(self, ini_file, key_attribute):
self.users = ConfigParser.ConfigParser()
self.users.readfp(open(ini_file))
self.key_attribute = key_attribute
def add_metadata(self, _environ, identity):
#logger = environ.get('repoze.who.logger','')
@ -30,6 +30,6 @@ class INIMetadataProvider(object):
identity["user"] = dict(self.users.items(key))
except ValueError:
pass
def make_plugin(ini_file, key_attribute=""):
return INIMetadataProvider(ini_file, key_attribute)

View File

@ -40,7 +40,7 @@ from saml2.s_utils import sid
from saml2.config import config_factory
from saml2.profile import paos
#from saml2.population import Population
# from saml2.population import Population
#from saml2.attribute_resolver import AttributeResolver
logger = logging.getLogger(__name__)
@ -58,6 +58,7 @@ def construct_came_from(environ):
came_from += '?' + qstr
return came_from
def exception_trace(tag, exc, log):
message = traceback.format_exception(*sys.exc_info())
log.error("[%s] ExcList: %s" % (tag, "".join(message),))
@ -79,12 +80,11 @@ class ECP_response(object):
class SAML2Plugin(object):
implements(IChallenger, IIdentifier, IAuthenticator, IMetadataProvider)
def __init__(self, rememberer_name, config, saml_client, wayf, cache,
sid_store=None, discovery="", idp_query_param="",
sid_store_cert=None,):
sid_store_cert=None, ):
self.rememberer_name = rememberer_name
self.wayf = wayf
self.saml_client = saml_client
@ -130,17 +130,20 @@ class SAML2Plugin(object):
:param environ: A dictionary with environment variables
"""
body= ''
body = ''
try:
length= int(environ.get('CONTENT_LENGTH', '0'))
length = int(environ.get('CONTENT_LENGTH', '0'))
except ValueError:
length= 0
if length!=0:
length = 0
if length != 0:
body = environ['wsgi.input'].read(length) # get the POST variables
environ['s2repoze.body'] = body # store the request body for later use by pysaml2
environ['wsgi.input'] = StringIO(body) # restore the request body as a stream so that everything seems untouched
environ[
's2repoze.body'] = body # store the request body for later
# use by pysaml2
environ['wsgi.input'] = StringIO(body) # restore the request body
# as a stream so that everything seems untouched
post = parse_qs(body) # parse the POST fields into a dict
post = parse_qs(body) # parse the POST fields into a dict
logger.debug('identify post: %s' % (post,))
@ -161,10 +164,11 @@ class SAML2Plugin(object):
"""
# check headers to see if it's an ECP request
# headers = {
# 'Accept' : 'text/html; application/vnd.paos+xml',
# 'PAOS' : 'ver="%s";"%s"' % (paos.NAMESPACE, SERVICE)
# }
# headers = {
# 'Accept' : 'text/html; application/vnd.paos+xml',
# 'PAOS' : 'ver="%s";"%s"' % (paos.NAMESPACE,
# SERVICE)
# }
_cli = self.saml_client
@ -262,7 +266,6 @@ class SAML2Plugin(object):
_cli = self.saml_client
if 'REMOTE_USER' in environ:
name_id = decode(environ["REMOTE_USER"])
@ -360,7 +363,7 @@ class SAML2Plugin(object):
try:
ret = _cli.config.getattr(
"endpoints","sp")["discovery_response"][0][0]
"endpoints", "sp")["discovery_response"][0][0]
if (environ["PATH_INFO"]) in ret and ret.split(
environ["PATH_INFO"])[1] == "":
query = parse_qs(environ["QUERY_STRING"])
@ -439,8 +442,10 @@ class SAML2Plugin(object):
#logger = environ.get('repoze.who.logger', '')
query = parse_dict_querystring(environ)
if ("CONTENT_LENGTH" not in environ or not environ["CONTENT_LENGTH"]) and \
"SAMLResponse" not in query and "SAMLRequest" not in query:
if ("CONTENT_LENGTH" not in environ or not environ[
"CONTENT_LENGTH"]) and \
"SAMLResponse" not in query and "SAMLRequest" not in \
query:
logger.debug('[identify] get or empty post')
return None
@ -483,6 +488,7 @@ class SAML2Plugin(object):
return {}
except:
import traceback
traceback.print_exc()
elif "SAMLResponse" not in post:
logger.info("[sp.identify] --- NOT SAMLResponse ---")
@ -498,7 +504,8 @@ class SAML2Plugin(object):
#if self.debug:
try:
if logout:
response = self.saml_client.parse_logout_request_response(
response = \
self.saml_client.parse_logout_request_response(
post["SAMLResponse"][0], binding)
if response:
action = self.saml_client.handle_logout_response(
@ -548,7 +555,8 @@ class SAML2Plugin(object):
name_id = identity['repoze.who.userid']
if isinstance(name_id, basestring):
try:
# Make sure that userids authenticated by another plugin don't cause problems here.
# Make sure that userids authenticated by another plugin
# don't cause problems here.
name_id = decode(name_id)
except:
pass
@ -602,7 +610,9 @@ class SAML2Plugin(object):
#noinspection PyUnusedLocal
def authenticate(self, environ, identity=None):
if identity:
if identity.get('user') and environ.get('s2repoze.sessioninfo') and identity.get('user') == environ.get('s2repoze.sessioninfo').get('ava'):
if identity.get('user') and environ.get(
's2repoze.sessioninfo') and identity.get(
'user') == environ.get('s2repoze.sessioninfo').get('ava'):
return identity.get('login')
tktuser = identity.get('repoze.who.plugins.auth_tkt.userid', None)
if tktuser and self.saml_client.is_logged_in(decode(tktuser)):
@ -634,8 +644,7 @@ def make_plugin(remember_name=None, # plugin for remember
identity_cache="",
discovery="",
idp_query_param=""
):
):
if saml_conf is "":
raise ValueError(
'must include saml_conf in configuration')

View File

@ -13,7 +13,7 @@
classes to interact with.
Conversions to and from XML should only be necessary when the SAML classes
"touch the wire" and are sent over HTTP. For this reason this module
"touch the wire" and are sent over HTTP. For this reason this module
provides methods and functions to convert SAML classes to and from strings.
"""
@ -70,7 +70,7 @@ def class_name(instance):
def create_class_from_xml_string(target_class, xml_string):
"""Creates an instance of the target class from a string.
:param target_class: The class which will be instantiated and populated
with the contents of the XML. This class must have a c_tag and a
c_namespace class variable.
@ -79,7 +79,7 @@ def create_class_from_xml_string(target_class, xml_string):
class.
:return: An instance of the target class with members assigned according to
the contents of the XML - or None if the root XML tag and namespace did
the contents of the XML - or None if the root XML tag and namespace did
not match those of the target class.
"""
tree = ElementTree.fromstring(xml_string)
@ -98,10 +98,10 @@ def create_class_from_element_tree(target_class, tree, namespace=None,
:param tree: An element tree whose contents will be converted into
members of the new target_class instance.
:param namespace: The namespace which the XML tree's root node must
match. If omitted, the namespace defaults to the c_namespace of the
match. If omitted, the namespace defaults to the c_namespace of the
target class.
:param tag: The tag which the XML tree's root node must match. If
omitted, the tag defaults to the c_tag class member of the target
omitted, the tag defaults to the c_tag class member of the target
class.
:return: An instance of the target class - or None if the tag and namespace
@ -136,16 +136,16 @@ class ExtensionElement(object):
capture the information in the XML. Child nodes in an XML
extension are turned into ExtensionElements as well.
"""
def __init__(self, tag, namespace=None, attributes=None,
children=None, text=None):
"""Constructor for ExtensionElement
:param namespace: The XML namespace for this element.
:param tag: The tag (without the namespace qualifier) for
this element. To reconstruct the full qualified name of the
this element. To reconstruct the full qualified name of the
element, combine this tag with the namespace.
:param attributes: The attribute value string pairs for the XML
:param attributes: The attribute value string pairs for the XML
attributes of this element.
:param children: list (optional) A list of ExtensionElements which
represent the XML child nodes of this element.
@ -156,41 +156,41 @@ class ExtensionElement(object):
self.attributes = attributes or {}
self.children = children or []
self.text = text
def to_string(self):
""" Serialize the object into a XML string """
element_tree = self.transfer_to_element_tree()
return ElementTree.tostring(element_tree, encoding="UTF-8")
def transfer_to_element_tree(self):
if self.tag is None:
return None
element_tree = ElementTree.Element('')
if self.namespace is not None:
element_tree.tag = '{%s}%s' % (self.namespace, self.tag)
else:
element_tree.tag = self.tag
for key, value in self.attributes.iteritems():
element_tree.attrib[key] = value
for child in self.children:
child.become_child_element_of(element_tree)
element_tree.text = self.text
return element_tree
def become_child_element_of(self, element_tree):
"""Converts this object into an etree element and adds it as a child
"""Converts this object into an etree element and adds it as a child
node in an etree element.
Adds self to the ElementTree. This method is required to avoid verbose
Adds self to the ElementTree. This method is required to avoid verbose
XML which constantly redefines the namespace.
:param element_tree: ElementTree._Element The element to which this
:param element_tree: ElementTree._Element The element to which this
object's XML will be added.
"""
new_element = self.transfer_to_element_tree()
@ -231,37 +231,37 @@ class ExtensionElement(object):
results.append(element)
return results
def loadd(self, ava):
""" expects a special set of keys """
if "attributes" in ava:
for key, val in ava["attributes"].items():
self.attributes[key] = val
try:
self.tag = ava["tag"]
except KeyError:
if not self.tag:
raise KeyError("ExtensionElement must have a tag")
try:
self.namespace = ava["namespace"]
except KeyError:
if not self.namespace:
raise KeyError("ExtensionElement must belong to a namespace")
try:
self.text = ava["text"]
except KeyError:
pass
if "children" in ava:
for item in ava["children"]:
self.children.append(ExtensionElement(item["tag"]).loadd(item))
return self
def extension_element_from_string(xml_string):
element_tree = ElementTree.fromstring(xml_string)
@ -273,7 +273,7 @@ def _extension_element_from_element_tree(element_tree):
if '}' in elementc_tag:
namespace = elementc_tag[1:elementc_tag.index('}')]
tag = elementc_tag[elementc_tag.index('}') + 1:]
else:
else:
namespace = None
tag = elementc_tag
extension = ExtensionElement(namespace=namespace, tag=tag)
@ -286,17 +286,17 @@ def _extension_element_from_element_tree(element_tree):
class ExtensionContainer(object):
c_tag = ""
c_namespace = ""
def __init__(self, text=None, extension_elements=None,
extension_attributes=None):
self.text = text
self.extension_elements = extension_elements or []
self.extension_attributes = extension_attributes or {}
# Three methods to create an object from an ElementTree
def harvest_element_tree(self, tree):
# Fill in the instance members from the contents of the XML tree.
@ -305,7 +305,7 @@ class ExtensionContainer(object):
for attribute, value in tree.attrib.iteritems():
self._convert_element_attribute_to_member(attribute, value)
self.text = tree.text
def _convert_element_tree_to_member(self, child_tree):
self.extension_elements.append(_extension_element_from_element_tree(
child_tree))
@ -333,7 +333,7 @@ class ExtensionContainer(object):
:param tag: str (optional) The desired tag
:param namespace: str (optional) The desired namespace
:Return: A list of elements whose tag and/or namespace match the
:Return: A list of elements whose tag and/or namespace match the
parameters values
"""
@ -381,16 +381,16 @@ class ExtensionContainer(object):
def add_extension_attribute(self, name, value):
self.extension_attributes[name] = value
def make_vals(val, klass, klass_inst=None, prop=None, part=False,
base64encode=False):
"""
Creates a class instance with a specified value, the specified
class instance may be a value on a property in a defined class instance.
:param val: The value
:param klass: The value class
:param klass_inst: The class instance which has a property on which
:param klass_inst: The class instance which has a property on which
what this function returns is a value.
:param prop: The property which the value should be assigned to.
:param part: If the value is one of a possible list of values it should be
@ -400,7 +400,7 @@ def make_vals(val, klass, klass_inst=None, prop=None, part=False,
cinst = None
#print "make_vals(%s, %s)" % (val, klass)
if isinstance(val, dict):
cinst = klass().loadd(val, base64encode=base64encode)
else:
@ -413,19 +413,19 @@ def make_vals(val, klass, klass_inst=None, prop=None, part=False,
setattr(klass_inst, prop, cis)
else:
raise
if part:
return cinst
else:
if cinst:
else:
if cinst:
cis = [cinst]
setattr(klass_inst, prop, cis)
def make_instance(klass, spec, base64encode=False):
"""
Constructs a class instance containing the specified information
:param klass: The class
:param spec: Information to be placed in the instance (a dictionary)
:return: The instance
@ -435,12 +435,12 @@ def make_instance(klass, spec, base64encode=False):
class SamlBase(ExtensionContainer):
"""A foundation class on which SAML classes are built. It
"""A foundation class on which SAML classes are built. It
handles the parsing of attributes and children which are common to all
SAML classes. By default, the SamlBase class translates all XML child
SAML classes. By default, the SamlBase class translates all XML child
nodes into ExtensionElements.
"""
c_children = {}
c_attributes = {}
c_attribute_type = {}
@ -450,7 +450,7 @@ class SamlBase(ExtensionContainer):
c_any_attribute = None
c_value_type = None
c_ns_prefix = None
def _get_all_c_children_with_order(self):
if len(self.c_child_order) > 0:
for child in self.c_child_order:
@ -458,7 +458,7 @@ class SamlBase(ExtensionContainer):
else:
for _, values in self.__class__.c_children.iteritems():
yield values[0]
def _convert_element_tree_to_member(self, child_tree):
# Find the element's tag in this class's list of child members
if child_tree.tag in self.__class__.c_children:
@ -480,10 +480,10 @@ class SamlBase(ExtensionContainer):
ExtensionContainer._convert_element_tree_to_member(self, child_tree)
def _convert_element_attribute_to_member(self, attribute, value):
# Find the attribute in this class's list of attributes.
# Find the attribute in this class's list of attributes.
if attribute in self.__class__.c_attributes:
# Find the member of this class which corresponds to the XML
# attribute(lookup in current_class.c_attributes) and set this
# Find the member of this class which corresponds to the XML
# attribute(lookup in current_class.c_attributes) and set this
# member to the desired value (using self.__dict__).
setattr(self, self.__class__.c_attributes[attribute][0], value)
else:
@ -493,7 +493,7 @@ class SamlBase(ExtensionContainer):
# Three methods to create an ElementTree from an object
def _add_members_to_element_tree(self, tree):
# Convert the members of this class which are XML child nodes.
# Convert the members of this class which are XML child nodes.
# This uses the class's c_children dictionary to find the members which
# should become XML child nodes.
for member_name in self._get_all_c_children_with_order():
@ -519,10 +519,10 @@ class SamlBase(ExtensionContainer):
def become_child_element_of(self, node):
"""
Note: Only for use with classes that have a c_tag and c_namespace class
Note: Only for use with classes that have a c_tag and c_namespace class
member. It is in SamlBase so that it can be inherited but it should
not be called on instances of SamlBase.
:param node: The node to which this instance should be a child
"""
new_child = self._to_element_tree()
@ -531,8 +531,8 @@ class SamlBase(ExtensionContainer):
def _to_element_tree(self):
"""
Note, this method is designed to be used only with classes that have a
c_tag and c_namespace. It is placed in SamlBase for inheritance but
Note, this method is designed to be used only with classes that have a
c_tag and c_namespace. It is placed in SamlBase for inheritance but
should not be called on in this class.
"""
@ -560,7 +560,7 @@ class SamlBase(ExtensionContainer):
ElementTree._namespace_map[uri] = prefix
except ValueError:
pass
return ElementTree.tostring(self._to_element_tree(), encoding="UTF-8")
def __str__(self):
@ -568,25 +568,25 @@ class SamlBase(ExtensionContainer):
def keyswv(self):
""" Return the keys of attributes or children that has values
:return: list of keys
"""
return [key for key, val in self.__dict__.items() if val]
def keys(self):
""" Return all the keys that represent possible attributes and
""" Return all the keys that represent possible attributes and
children.
:return: list of keys
"""
keys = ['text']
keys.extend([n for (n, t, r) in self.c_attributes.values()])
keys.extend([v[0] for v in self.c_children.values()])
return keys
def children_with_values(self):
""" Returns all children that has values
:return: Possibly empty list of children.
"""
childs = []
@ -604,12 +604,12 @@ class SamlBase(ExtensionContainer):
#noinspection PyUnusedLocal
def set_text(self, val, base64encode=False):
""" Sets the text property of this instance.
:param val: The value of the text property
:param base64encode: Whether the value should be base64encoded
:return: The instance
"""
#print "set_text: %s" % (val,)
if isinstance(val, bool):
if val:
@ -624,23 +624,23 @@ class SamlBase(ExtensionContainer):
pass
else:
raise ValueError("Type shouldn't be '%s'" % (val,))
return self
def loadd(self, ava, base64encode=False):
"""
Sets attributes, children, extension elements and extension
attributes of this element instance depending on what is in
"""
Sets attributes, children, extension elements and extension
attributes of this element instance depending on what is in
the given dictionary. If there are already values on properties
those will be overwritten. If the keys in the dictionary does
not correspond to known attributes/children/.. they are ignored.
:param ava: The dictionary
:param base64encode: Whether the values on attributes or texts on
children shoule be base64encoded.
:return: The instance
"""
for prop, _typ, _req in self.c_attributes.values():
#print "# %s" % (prop)
if prop in ava:
@ -653,13 +653,13 @@ class SamlBase(ExtensionContainer):
if "text" in ava:
self.set_text(ava["text"], base64encode)
for prop, klassdef in self.c_children.values():
#print "## %s, %s" % (prop, klassdef)
if prop in ava:
#print "### %s" % ava[prop]
# means there can be a list of values
if isinstance(klassdef, list):
if isinstance(klassdef, list):
make_vals(ava[prop], klassdef[0], self, prop,
base64encode=base64encode)
else:
@ -671,13 +671,13 @@ class SamlBase(ExtensionContainer):
for item in ava["extension_elements"]:
self.extension_elements.append(ExtensionElement(
item["tag"]).loadd(item))
if "extension_attributes" in ava:
for key, val in ava["extension_attributes"].items():
self.extension_attributes[key] = val
return self
def clear_text(self):
if self.text:
_text = self.text.strip()
@ -781,42 +781,42 @@ class SamlBase(ExtensionContainer):
def element_to_extension_element(element):
"""
Convert an element into a extension element
:param element: The element instance
:return: An extension element instance
"""
exel = ExtensionElement(element.c_tag, element.c_namespace,
exel = ExtensionElement(element.c_tag, element.c_namespace,
text=element.text)
exel.attributes.update(element.extension_attributes)
exel.children.extend(element.extension_elements)
for xml_attribute, (member_name, typ, req) in \
element.c_attributes.iteritems():
member_value = getattr(element, member_name)
if member_value is not None:
exel.attributes[xml_attribute] = member_value
exel.children.extend([element_to_extension_element(c) for c in
element.children_with_values()])
return exel
def extension_element_to_element(extension_element, translation_functions,
namespace=None):
""" Convert an extension element to a normal element.
In order to do this you need to have an idea of what type of
In order to do this you need to have an idea of what type of
element it is. Or rather which module it belongs to.
:param extension_element: The extension element
:param translation_functions: A dictionary with class identifiers
as keys and string-to-element translations functions as values
:param namespace: The namespace of the translation functions.
:return: An element instance or None
"""
try:
element_namespace = extension_element.namespace
except AttributeError:
@ -830,9 +830,9 @@ def extension_element_to_element(extension_element, translation_functions,
return ets(extension_element.to_string())
except KeyError:
pass
return None
def extension_elements_to_elements(extension_elements, schemas):
""" Create a list of elements each one matching one of the

View File

@ -21,25 +21,25 @@ logger = logging.getLogger(__name__)
def _filter_values(vals, vlist=None, must=False):
""" Removes values from *vals* that does not appear in vlist
:param vals: The values that are to be filtered
:param vlist: required or optional value
:param must: Whether the allowed values must appear
:return: The set of values after filtering
"""
if not vlist: # No value specified equals any value
return vals
if isinstance(vlist, basestring):
vlist = [vlist]
res = []
for val in vlist:
if val in vals:
res.append(val)
if must:
if res:
return res
@ -67,9 +67,9 @@ def _match(attr, ava):
def filter_on_attributes(ava, required=None, optional=None, acs=None,
fail_on_unfulfilled_requirements=True):
""" Filter
:param ava: An attribute value assertion as a dictionary
:param required: list of RequestedAttribute instances defined to be
:param required: list of RequestedAttribute instances defined to be
required
:param optional: list of RequestedAttribute instances defined to be
optional
@ -78,7 +78,7 @@ def filter_on_attributes(ava, required=None, optional=None, acs=None,
:return: The modified attribute value assertion
"""
res = {}
if required is None:
required = []
@ -126,20 +126,20 @@ def filter_on_attributes(ava, required=None, optional=None, acs=None,
res[_fn].extend(_filter_values(ava[_fn], values))
except KeyError:
res[_fn] = _filter_values(ava[_fn], values)
return res
def filter_on_demands(ava, required=None, optional=None):
""" Never return more than is needed. Filters out everything
the server is prepared to return but the receiver doesn't ask for
:param ava: Attribute value assertion as a dictionary
:param required: Required attributes
:param optional: Optional attributes
:return: The possibly reduced assertion
"""
# Is all what's required there:
if required is None:
required = {}
@ -169,7 +169,7 @@ def filter_on_demands(ava, required=None, optional=None):
for attr in lava.keys():
if attr not in oka:
del ava[lava[attr]]
return ava
@ -219,7 +219,7 @@ def filter_attribute_value_assertions(ava, attribute_restrictions=None):
rules defined in the attribute restrictions. If filtering results in
an attribute without values, then the attribute is removed from the
assertion.
:param ava: The incoming attribute value assertion (dictionary)
:param attribute_restrictions: The rules that govern which attributes
and values that are allowed. (dictionary)
@ -227,7 +227,7 @@ def filter_attribute_value_assertions(ava, attribute_restrictions=None):
"""
if not attribute_restrictions:
return ava
for attr, vals in ava.items():
_attr = attr.lower()
try:
@ -300,7 +300,7 @@ def post_entity_categories(maps, **kwargs):
class Policy(object):
""" handles restrictions on assertions """
def __init__(self, restrictions=None):
if restrictions:
self.compile(restrictions)
@ -314,14 +314,14 @@ class Policy(object):
In the configuration file, restrictions on which values that
can be returned are specified with the help of regular expressions.
This function goes through and pre-compiles the regular expressions.
:param restrictions:
:return: The assertion with the string specification replaced with
a compiled regular expression.
"""
self._restrictions = restrictions.copy()
for who, spec in self._restrictions.items():
if spec is None:
continue
@ -391,7 +391,7 @@ class Policy(object):
return val
def get_nameid_format(self, sp_entity_id):
""" Get the NameIDFormat to used for the entity id
""" Get the NameIDFormat to used for the entity id
:param: The SP entity ID
:retur: The format
"""
@ -399,7 +399,7 @@ class Policy(object):
saml.NAMEID_FORMAT_TRANSIENT)
def get_name_form(self, sp_entity_id):
""" Get the NameFormat to used for the entity id
""" Get the NameFormat to used for the entity id
:param: The SP entity ID
:retur: The format
"""
@ -407,16 +407,16 @@ class Policy(object):
return self.get("name_format", sp_entity_id, NAME_FORMAT_URI)
def get_lifetime(self, sp_entity_id):
""" The lifetime of the assertion
""" The lifetime of the assertion
:param sp_entity_id: The SP entity ID
:param: lifetime as a dictionary
:param: lifetime as a dictionary
"""
# default is a hour
return self.get("lifetime", sp_entity_id, {"hours": 1})
def get_attribute_restrictions(self, sp_entity_id):
""" Return the attribute restriction for SP that want the information
:param sp_entity_id: The SP entity ID
:return: The restrictions
"""
@ -461,20 +461,20 @@ class Policy(object):
def not_on_or_after(self, sp_entity_id):
""" When the assertion stops being valid, should not be
used after this time.
:param sp_entity_id: The SP entity ID
:return: String representation of the time
"""
return in_a_while(**self.get_lifetime(sp_entity_id))
def filter(self, ava, sp_entity_id, mdstore, required=None, optional=None):
""" What attribute and attribute values returns depends on what
the SP has said it wants in the request or in the metadata file and
what the IdP/AA wants to release. An assumption is that what the SP
asks for overrides whatever is in the metadata. But of course the
IdP never releases anything it doesn't want to.
:param ava: The information about the subject as a dictionary
:param sp_entity_id: The entity ID of the SP
:param mdstore: A Metadata store
@ -510,11 +510,11 @@ class Policy(object):
return {}
else:
return _ava
def restrict(self, ava, sp_entity_id, metadata=None):
""" Identity attribute names are expected to be expressed in
the local lingo (== friendlyName)
:return: A filtered ava according to the IdPs/AAs rules and
the list of required/optional attributes according to the SP.
If the requirements can't be met an exception is raised.
@ -529,7 +529,7 @@ class Policy(object):
def conditions(self, sp_entity_id):
""" Return a saml.Condition instance
:param sp_entity_id: The SP entity ID
:return: A saml.Condition instance
"""
@ -657,7 +657,7 @@ def authn_statement(authn_class=None, authn_auth=None,
class Assertion(dict):
""" Handles assertions about subjects """
def __init__(self, dic=None):
dict.__init__(self, dic)
self.acs = []
@ -667,10 +667,10 @@ class Assertion(dict):
authn_auth=None, authn_decl=None, encrypt=None,
sec_context=None, authn_decl_ref=None, authn_instant="",
subject_locality=""):
""" Construct the Assertion
""" Construct the Assertion
:param sp_entity_id: The entityid of the SP
:param in_response_to: An identifier of the message, this message is
:param in_response_to: An identifier of the message, this message is
a response to
:param consumer_url: The intended consumer of the assertion
:param name_id: An NameID instance
@ -744,10 +744,10 @@ class Assertion(dict):
_ass.attribute_statement=[attr_statement]
return _ass
def apply_policy(self, sp_entity_id, policy, metadata=None):
""" Apply policy to the assertion I'm representing
""" Apply policy to the assertion I'm representing
:param sp_entity_id: The SP entity ID
:param policy: The policy
:param metadata: Metadata to use

View File

@ -434,7 +434,7 @@ class AttributeConverter(object):
def from_format(self, attr):
""" Find out the local name of an attribute
:param attr: An saml.Attribute instance
:return: The local attribute name or "" if no mapping could be made
"""

View File

@ -23,7 +23,7 @@ class AttributeResolver(object):
self.metadata = saml2client.config.metadata
def extend(self, name_id, issuer, vo_members):
"""
"""
:param name_id: The identifier by which the subject is know
among all the participents of the VO
:param issuer: Who am I the poses the query
@ -33,7 +33,7 @@ class AttributeResolver(object):
subject
"""
result = []
for member in vo_members:
for member in vo_members:
for ass in self.metadata.attribute_consuming_service(member):
for attr_serv in ass.attribute_service:
logger.info(

View File

@ -7,7 +7,7 @@ import logging
logger = logging.getLogger(__name__)
# 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
# timeout time.
@ -28,7 +28,7 @@ class Cache(object):
else:
self._db = {}
self._sync = False
def delete(self, name_id):
"""
@ -41,17 +41,17 @@ class Cache(object):
self._db.sync()
except AttributeError:
pass
def get_identity(self, name_id, entities=None,
check_not_on_or_after=True):
""" 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.
:param name_id: The subject identifier, a NameID instance
:param entities: The identifiers of the entities whoes assertions are
interesting. If the list is empty all entities are interesting.
:return: A 2-tuple consisting of the identity information (a
dictionary of attributes and values) and the list of entities
dictionary of attributes and values) and the list of entities
whoes information has timed out.
"""
if not entities:
@ -60,7 +60,7 @@ class Cache(object):
entities = self._db[cni].keys()
except KeyError:
return {}, []
res = {}
oldees = []
for entity_id in entities:
@ -73,19 +73,19 @@ class Cache(object):
if not info:
oldees.append(entity_id)
continue
for key, vals in info["ava"].items():
for key, vals in info["ava"].items():
try:
tmp = set(res[key]).union(set(vals))
res[key] = list(tmp)
except KeyError:
res[key] = vals
return res, oldees
def get(self, name_id, entity_id, check_not_on_or_after=True):
""" Get session information about a subject gotten from a
specified IdP/AA.
:param name_id: The subject identifier, a NameID instance
:param entity_id: The identifier of the entity_id
:param check_not_on_or_after: if True it will check if this
@ -99,13 +99,13 @@ class Cache(object):
raise ToOld("past %s" % timestamp)
return info or None
def set(self, name_id, entity_id, info, not_on_or_after=0):
""" Stores session information in the cache. Assumes that the name_id
is unique within the context of the Service Provider.
:param name_id: The subject identifier, a NameID instance
:param entity_id: The identifier of the entity_id/receiver of an
:param entity_id: The identifier of the entity_id/receiver of an
assertion
:param info: The session info, the assertion is part of this
:param not_on_or_after: A time after which the assertion is not valid.
@ -120,35 +120,35 @@ class Cache(object):
self._db.sync()
except AttributeError:
pass
def reset(self, name_id, entity_id):
""" Scrap the assertions received from a IdP or an AA about a special
subject.
:param name_id: The subject identifier, a NameID instance
:param entity_id: The identifier of the entity_id of the assertion
:return:
"""
self.set(name_id, entity_id, {}, 0)
def entities(self, name_id):
""" Returns all the entities of assertions for a subject, disregarding
whether the assertion still is valid or not.
:param name_id: The subject identifier, a NameID instance
:return: A possibly empty list of entity identifiers
"""
cni = code(name_id)
return self._db[cni].keys()
def receivers(self, name_id):
""" Another name for entities() just to make it more logic in the IdP
""" Another name for entities() just to make it more logic in the IdP
scenario """
return self.entities(name_id)
def active(self, name_id, entity_id):
""" Returns the status of assertions from a specific entity_id.
:param name_id: The ID of the subject
:param entity_id: The entity ID of the entity_id of the assertion
:return: True or False depending on if the assertion is still
@ -164,10 +164,10 @@ class Cache(object):
return False
else:
return time_util.not_on_or_after(timestamp)
def subjects(self):
""" Return identifiers for all the subjects that are in the cache.
:return: list of subject identifiers
"""
return [decode(c) for c in self._db.keys()]

View File

@ -84,7 +84,7 @@ class Saml2Client(Base):
""" More or less a layer of indirection :-/
Bootstrapping the whole thing by finding all the IdPs that should
be notified.
:param name_id: The identifier of the subject that wants to be
logged out.
:param reason: Why the subject wants to log out
@ -95,7 +95,7 @@ class Saml2Client(Base):
:return: Depends on which binding is used:
If the HTTP redirect binding then a HTTP redirect,
if SOAP binding has been used the just the result of that
conversation.
conversation.
"""
if isinstance(name_id, basestring):
@ -205,8 +205,8 @@ class Saml2Client(Base):
return responses
def local_logout(self, name_id):
""" Remove the user from the cache, equals local logout
""" Remove the user from the cache, equals local logout
:param name_id: The identifier of the subject
"""
self.users.remove_person(name_id)
@ -214,15 +214,15 @@ class Saml2Client(Base):
def is_logged_in(self, name_id):
""" Check if user is in the cache
:param name_id: The identifier of the subject
"""
identity = self.users.get_identity(name_id)[0]
return bool(identity)
def handle_logout_response(self, response):
""" handles a Logout response
""" handles a Logout response
:param response: A response.Response instance
:return: 4-tuple of (session_id of the last sent logout request,
response message, response headers and message)

View File

@ -198,7 +198,7 @@ class Base(Entity):
consent=None, extensions=None, sign=None,
allow_create=False, sign_prepare=False, **kwargs):
""" Creates an authentication request.
:param destination: Where the request should be sent.
:param vorg: The virtual organization the service belongs to.
:param scoping: The scope of the request
@ -312,7 +312,7 @@ class Base(Entity):
extensions=None, sign=False, sign_prepare=False,
**kwargs):
""" Constructs an AttributeQuery
:param destination: To whom the query should be sent
:param name_id: The identifier of the subject
:param attribute: A dictionary of attributes and values that is

View File

@ -465,7 +465,7 @@ class Config(object):
handler.setFormatter(formatter)
return handler
def setup_logger(self):
if root_logger.level != logging.NOTSET: # Someone got there before me
return root_logger
@ -528,7 +528,7 @@ class SPConfig(Config):
class IdPConfig(Config):
def_context = "idp"
def __init__(self):
Config.__init__(self)

View File

@ -69,7 +69,7 @@ class DiscoveryServer(Entity):
entity_id=None, **kwargs):
if return_url is None:
return_url = kwargs["return"]
if entity_id:
qp = urlencode({returnIDParam: entity_id})

View File

@ -100,7 +100,7 @@ def ecp_auth_request(cls, entityid=None, relay_state="", sign=False):
# ----------------------------------------
logger.info("entityid: %s, binding: %s" % (entityid, BINDING_SOAP))
location = cls._sso_location(entityid, binding=BINDING_SOAP)
req_id, authn_req = cls.create_authn_request(
location, binding=BINDING_PAOS, service_url_binding=BINDING_PAOS)
@ -134,7 +134,7 @@ def handle_ecp_authn_response(cls, soap_message, outstanding=None):
cls.users.add_information_about_person(response.session_info())
return response, _relay_state
def ecp_response(target_url, response):
@ -168,7 +168,7 @@ class ECPServer(Server):
def parse_ecp_authn_query(self):
pass
def ecp_response(self):
# ----------------------------------------

View File

@ -147,7 +147,7 @@ class Client(Entity):
_ = self.send(rc_url, "POST", data=soap.soap_fault(error))
# Raise an exception so the user knows something went wrong
raise SAMLError(error)
return idp_response
@staticmethod
@ -221,7 +221,7 @@ class Client(Entity):
self.done_ecp = True
logger.debug("Done ECP")
return None
def add_paos_headers(self, headers=None):

View File

@ -673,7 +673,7 @@ class Entity(HTTPBase):
def create_logout_request(self, destination, issuer_entity_id,
subject_id=None, name_id=None,
reason=None, expire=None, message_id=0,
reason=None, expire=None, message_id=0,
consent=None, extensions=None, sign=False):
""" Constructs a LogoutRequest
@ -771,7 +771,7 @@ class Entity(HTTPBase):
return response
def create_manage_name_id_request(self, destination, message_id=0,
def create_manage_name_id_request(self, destination, message_id=0,
consent=None, extensions=None, sign=False,
name_id=None, new_id=None,
encrypted_id=None, new_encrypted_id=None,
@ -839,7 +839,7 @@ class Entity(HTTPBase):
return response
def parse_manage_name_id_request_response(self, string,
def parse_manage_name_id_request_response(self, string,
binding=BINDING_SOAP):
return self._parse_response(string, saml_response.ManageNameIDResponse,
"manage_name_id_service", binding,

View File

@ -1,7 +1,7 @@
# An eduPersonTargetedID comprises
# the entity name of the identity provider, the entity name of the service
# the entity name of the identity provider, the entity name of the service
# provider, and a opaque string value.
# These strings are separated by "!" symbols. This form is advocated by
# These strings are separated by "!" symbols. This form is advocated by
# Internet2 and may overtake the other form in due course.
import hashlib
@ -15,8 +15,8 @@ logger = logging.getLogger(__name__)
class Eptid(object):
def __init__(self, secret):
self._db = {}
self.secret = secret
self.secret = secret
def make(self, idp, sp, args):
md5 = hashlib.md5()
for arg in args:

View File

@ -33,7 +33,7 @@ class EntityAttributesType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,

View File

@ -106,11 +106,11 @@ class HTTPBase(object):
self.request_args["verify"] = ca_bundle
if key_file:
self.request_args["cert"] = (cert_file, key_file)
self.sec = None
self.user = None
self.passwd = None
def cookies(self, url):
"""
Return cookies that are matching the path and are still valid

View File

@ -5,7 +5,7 @@ import memcache
from saml2 import time_util
from saml2.cache import ToOld, CacheError
# 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
# timeout time.
@ -13,18 +13,18 @@ logger = logging.getLogger(__name__)
def _key(prefix, name):
return "%s_%s" % (prefix, name)
class Cache(object):
def __init__(self, servers, debug=0):
self._cache = memcache.Client(servers, debug)
def delete(self, subject_id):
entities = self.entities(subject_id)
if entities:
for entity_id in entities:
if not self._cache.delete(_key(subject_id, entity_id)):
raise CacheError("Delete failed")
if not self._cache.delete(subject_id):
raise CacheError("Delete failed")
@ -33,33 +33,33 @@ class Cache(object):
subjects.remove(subject_id)
if not self._cache.set("subjects", subjects):
raise CacheError("Set operation failed")
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.
:param subject_id: The identifier of the subject
:param entities: The identifiers of the entities whoes assertions are
interesting. If the list is empty all entities are interesting.
:return: A 2-tuple consisting of the identity information (a
dictionary of attributes and values) and the list of entities
dictionary of attributes and values) and the list of entities
whoes information has timed out.
"""
if not entities:
entities = self.entities(subject_id)
if not entities:
return {}, []
res = {}
oldees = []
for (entity_id, item) in self._cache.get_multi(entities,
for (entity_id, item) in self._cache.get_multi(entities,
subject_id+'_').items():
try:
info = self.get_info(item)
except ToOld:
oldees.append(entity_id)
continue
for key, vals in info["ava"].items():
for key, vals in info["ava"].items():
try:
tmp = set(res[key]).union(set(vals))
res[key] = list(tmp)
@ -78,7 +78,7 @@ class Cache(object):
(timestamp, info) = item
except ValueError:
raise ToOld()
if check_not_on_or_after and not time_util.not_on_or_after(timestamp):
raise ToOld()
@ -90,13 +90,13 @@ class Cache(object):
return {}
else:
return self.get_info(res)
def set(self, subject_id, entity_id, info, timestamp=0):
""" Stores session information in the cache. Assumes that the subject_id
is unique within the context of the Service Provider.
:param subject_id: The subject 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
assertion
:param info: The session info, the assertion is part of this
:param timestamp: A time after which the assertion is not valid.
@ -111,31 +111,31 @@ class Cache(object):
subjects.append(subject_id)
if not self._cache.set("subjects", subjects):
raise CacheError("set failed")
if entity_id not in entities:
entities.append(entity_id)
if not self._cache.set(subject_id, entities):
raise CacheError("set failed")
# Should use memcache's expire
if not self._cache.set(_key(subject_id, entity_id), (timestamp, info)):
raise CacheError("set failed")
def reset(self, subject_id, entity_id):
""" Scrap the assertions received from a IdP or an AA about a special
subject.
:param subject_id: The subjects identifier
:param entity_id: The identifier of the entity_id of the assertion
:return:
"""
if not self._cache.set(_key(subject_id, entity_id), {}, 0):
raise CacheError("reset failed")
def entities(self, subject_id):
""" Returns all the entities of assertions for a subject, disregarding
whether the assertion still is valid or not.
:param subject_id: The identifier of the subject
:return: A possibly empty list of entity identifiers
"""
@ -144,15 +144,15 @@ class Cache(object):
raise KeyError("No such subject")
else:
return res
def receivers(self, subject_id):
""" Another name for entities() just to make it more logic in the IdP
""" Another name for entities() just to make it more logic in the IdP
scenario """
return self.entities(subject_id)
def active(self, subject_id, entity_id):
""" Returns the status of assertions from a specific entity_id.
:param subject_id: The ID of the subject
:param entity_id: The entity ID of the entity_id of the assertion
:return: True or False depending on if the assertion is still
@ -164,18 +164,18 @@ class Cache(object):
return False
except TypeError:
return False
# if not info:
# return False
try:
return time_util.not_on_or_after(timestamp)
except ToOld:
return False
def subjects(self):
""" Return identifiers for all the subjects that are in the cache.
:return: list of subject identifiers
"""
return self._cache.get("subjects")
@ -189,7 +189,7 @@ class Cache(object):
if info:
info.update(ava)
self.set(subject_id, entity_id, info, res[0])
def valid_to(self, subject_id, entity_id, newtime):
try:
(timestamp, info) = self._cache.get(_key(subject_id, entity_id))
@ -197,6 +197,6 @@ class Cache(object):
return False
except TypeError:
info = {}
if not self._cache.set(_key(subject_id, entity_id), (newtime, info)):
raise CacheError("valid_to failed")

View File

@ -78,7 +78,7 @@ class Cache(object):
res[key] = vals
return res, oldees
def _get_info(self, item, check_not_on_or_after=True):
""" Get session information about a subject gotten from a
specified IdP/AA.

View File

@ -121,7 +121,7 @@ class MetaData(object):
self.entities_descr = None
self.entity_descr = None
self.check_validity = check_validity
def items(self):
return self.entity.items()

View File

@ -2,11 +2,11 @@
# -*- coding: utf-8 -*-
#
"""Contains classes and functions that are necessary to implement
"""Contains classes and functions that are necessary to implement
different bindings.
Bindings normally consists of three parts:
- rules about what to send
- rules about what to send
- how to package the information
- which protocol to use
"""
@ -46,10 +46,10 @@ FORM_SPEC = """<form method="post" action="%s">
def http_form_post_message(message, location, relay_state="",
typ="SAMLRequest"):
"""The HTTP POST binding defines a mechanism by which SAML protocol
"""The HTTP POST binding defines a mechanism by which SAML protocol
messages may be transmitted within the base64-encoded content of a
HTML form control.
:param message: The message
:param location: Where the form should be posted to
:param relay_state: for preserving and conveying state information
@ -66,25 +66,25 @@ def http_form_post_message(message, location, relay_state="",
_msg = message
response.append(FORM_SPEC % (location, typ, _msg, relay_state))
response.append("""<script type="text/javascript">""")
response.append(" window.onload = function ()")
response.append(" { document.forms[0].submit(); }")
response.append("""</script>""")
response.append("</body>")
return {"headers": [("Content-type", "text/html")], "data": response}
def http_redirect_message(message, location, relay_state="", typ="SAMLRequest",
sigalg=None, key=None):
"""The HTTP Redirect binding defines a mechanism by which SAML protocol
"""The HTTP Redirect binding defines a mechanism by which SAML protocol
messages can be transmitted within URL parameters.
Messages are encoded for use with this binding using a URL encoding
technique, and transmitted using the HTTP GET method.
Messages are encoded for use with this binding using a URL encoding
technique, and transmitted using the HTTP GET method.
The DEFLATE Encoding is used in this function.
:param message: The message
:param location: Where the message should be posted to
:param relay_state: for preserving and conveying state information
@ -93,7 +93,7 @@ def http_redirect_message(message, location, relay_state="", typ="SAMLRequest",
:param key: Key to use for signing
:return: A tuple containing header information and a HTML message.
"""
if not isinstance(message, basestring):
message = "%s" % (message,)
@ -134,7 +134,7 @@ def http_redirect_message(message, location, relay_state="", typ="SAMLRequest",
login_url = glue_char.join([location, string])
headers = [('Location', str(login_url))]
body = []
return {"headers": headers, "data": body}
@ -193,17 +193,17 @@ def make_soap_enveloped_saml_thingy(thingy, header_parts=None):
def http_soap_message(message):
return {"headers": [("Content-type", "application/soap+xml")],
"data": make_soap_enveloped_saml_thingy(message)}
def http_paos(message, extra=None):
return {"headers": [("Content-type", "application/soap+xml")],
"data": make_soap_enveloped_saml_thingy(message, extra)}
def parse_soap_enveloped_saml(text, body_class, header_class=None):
"""Parses a SOAP enveloped SAML thing and returns header parts and body
:param text: The SOAP object as XML
:param text: The SOAP object as XML
:return: header parts and body as saml.samlbase instances
"""
envelope = ElementTree.fromstring(text)
@ -233,7 +233,7 @@ def parse_soap_enveloped_saml(text, body_class, header_class=None):
header[sub.tag] = \
saml2.create_class_from_element_tree(klass, sub)
break
return body, header
# -----------------------------------------------------------------------------
@ -242,7 +242,7 @@ PACKING = {
saml2.BINDING_HTTP_REDIRECT: http_redirect_message,
saml2.BINDING_HTTP_POST: http_form_post_message,
}
def packager(identifier):
try:

View File

@ -15,20 +15,20 @@ class Population(object):
self.cache = Cache()
def add_information_about_person(self, session_info):
"""If there already are information from this source in the cache
"""If there already are information from this source in the cache
this function will overwrite that information"""
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 stale_sources_for_person(self, name_id, sources=None):
"""
:param name_id: Identifier of the subject, a NameID instance
:param name_id: Identifier of the subject, a NameID instance
:param sources: Sources for information about the subject
:return:
"""
@ -36,8 +36,8 @@ class Population(object):
# once before, hence they are represented in the cache
sources = self.cache.entities(name_id)
sources = [m for m in sources if not self.cache.active(name_id, m)]
return sources
return sources
def issuers_of_info(self, name_id):
return self.cache.entities(name_id)
@ -46,20 +46,20 @@ class Population(object):
def get_info_from(self, name_id, entity_id):
return self.cache.get(name_id, entity_id)
def subjects(self):
"""Returns the name id's for all the persons in the cache"""
return self.cache.subjects()
def remove_person(self, name_id):
self.cache.delete(name_id)
def get_entityid(self, name_id, source_id, check_not_on_or_after=True):
try:
return self.cache.get(name_id, source_id, check_not_on_or_after)[
"name_id"]
except (KeyError, ValueError):
return ""
def sources(self, name_id):
return self.cache.entities(name_id)

View File

@ -1,3 +1,2 @@
#profile schema descriptions
__author__ = 'rolandh'

View File

@ -42,7 +42,7 @@ class RequestType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -79,7 +79,7 @@ class ResponseType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -112,7 +112,7 @@ class RelayStateType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,

View File

@ -36,7 +36,7 @@ class RequestType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -72,7 +72,7 @@ class ResponseType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,

View File

@ -13,7 +13,7 @@ logger = logging.getLogger(__name__)
def _dummy(_arg):
return None
class Request(object):
def __init__(self, sec_context, receiver_addrs, attribute_converters=None,
@ -29,7 +29,7 @@ class Request(object):
self.binding = None
self.relay_state = ""
self.signature_check = _dummy # has to be set !!!
def _clear(self):
self.xmlstr = ""
self.name_id = ""
@ -46,7 +46,7 @@ class Request(object):
raise
except Exception, excp:
logger.info("EXCEPTION: %s", excp)
if not self.message:
logger.error("Response was not correctly signed")
logger.info(xmldata)
@ -59,9 +59,9 @@ class Request(object):
except NotValid, exc:
logger.error("Not valid request: %s" % exc.args[0])
raise
return self
def issue_instant_ok(self):
""" Check that the request was issued at a reasonable time """
upper = time_util.shift_time(time_util.time_in_a_while(days=1),
@ -73,14 +73,14 @@ class Request(object):
issued_at = time_util.str_to_time(self.message.issue_instant)
return issued_at > lower and issued_at < upper
def _verify(self):
def _verify(self):
assert self.message.version == "2.0"
if self.message.destination and self.receiver_addrs and \
self.message.destination not in self.receiver_addrs:
logger.error("%s not in %s" % (self.message.destination,
self.receiver_addrs))
raise OtherError("Not destined for me!")
assert self.issue_instant_ok()
return self
@ -92,9 +92,9 @@ class Request(object):
return self._verify()
except AssertionError:
return None
def subject_id(self):
""" The name of the subject can be in either of
""" The name of the subject can be in either of
BaseID, NameID or EncryptedID
:return: The identifier if there is one
@ -113,10 +113,10 @@ class Request(object):
return self.message.name_id
else: # EncryptedID
pass
def sender(self):
return self.message.issuer.text
class LogoutRequest(Request):
msgtype = "logout_request"
@ -126,8 +126,8 @@ class LogoutRequest(Request):
Request.__init__(self, sec_context, receiver_addrs,
attribute_converters, timeslack)
self.signature_check = self.sec.correctly_signed_logout_request
class AttributeQuery(Request):
msgtype = "attribute_query"
@ -136,7 +136,7 @@ class AttributeQuery(Request):
Request.__init__(self, sec_context, receiver_addrs,
attribute_converters, timeslack)
self.signature_check = self.sec.correctly_signed_attribute_query
def attribute(self):
""" Which attributes that are sought for """
return []

View File

@ -891,7 +891,7 @@ class AuthnResponse(StatusResponse):
return res
def session_info(self):
""" Returns a predefined set of information gleened from the
""" Returns a predefined set of information gleened from the
response.
:returns: Dictionary with information
"""

View File

@ -99,8 +99,8 @@ EXCEPTION2STATUS = {
Exception: samlp.STATUS_AUTHN_FAILED,
}
GENERIC_DOMAINS = ["aero", "asia", "biz", "cat", "com", "coop", "edu",
"gov", "info", "int", "jobs", "mil", "mobi", "museum",
GENERIC_DOMAINS = ["aero", "asia", "biz", "cat", "com", "coop", "edu",
"gov", "info", "int", "jobs", "mil", "mobi", "museum",
"name", "net", "org", "pro", "tel", "travel"]
@ -132,11 +132,11 @@ def valid_email(emailaddress, domains=GENERIC_DOMAINS):
return True # Email address is fine.
else:
return False # Email address has funny characters.
def decode_base64_and_inflate(string):
""" base64 decodes and then inflates according to RFC1951
""" base64 decodes and then inflates according to RFC1951
:param string: a deflated and encoded string
:return: the string after decoding and inflating
"""
@ -147,7 +147,7 @@ def decode_base64_and_inflate(string):
def deflate_and_base64_encode(string_val):
"""
Deflates and the base64 encodes a string
:param string_val: The string to deflate and encode
:return: The deflated and encoded string
"""
@ -171,7 +171,7 @@ def sid(seed=""):
128-160 bits
:param seed: A seed string
:return: The hex version of the digest, prefixed by 'id-' to make it
:return: The hex version of the digest, prefixed by 'id-' to make it
compliant with the NCName specification
"""
ident = md5()
@ -186,9 +186,9 @@ def parse_attribute_map(filenames):
Expects a file with each line being composed of the oid for the attribute
exactly one space, a user friendly name of the attribute and then
the type specification of the name.
:param filenames: List of filenames on mapfiles.
:return: A 2-tuple, one dictionary with the oid as keys and the friendly
:return: A 2-tuple, one dictionary with the oid as keys and the friendly
names as values, the other one the other way around.
"""
forward = {}
@ -198,9 +198,9 @@ def parse_attribute_map(filenames):
(name, friendly_name, name_format) = line.strip().split()
forward[(name, name_format)] = friendly_name
backward[friendly_name] = (name, name_format)
return forward, backward
def identity_attribute(form, attribute, forward_map=None):
if form == "friendly":
@ -212,10 +212,10 @@ def identity_attribute(form, attribute, forward_map=None):
except KeyError:
return attribute.name
# default is name
return attribute.name
return attribute.name
#----------------------------------------------------------------------------
def error_status_factory(info):
if isinstance(info, Exception):
@ -240,21 +240,21 @@ def error_status_factory(info):
status_code=samlp.StatusCode(
value=samlp.STATUS_RESPONDER,
status_code=samlp.StatusCode(value=errcode)))
return status
def success_status_factory():
return samlp.Status(status_code=samlp.StatusCode(
value=samlp.STATUS_SUCCESS))
def status_message_factory(message, code, fro=samlp.STATUS_RESPONDER):
return samlp.Status(
status_message=samlp.StatusMessage(text=message),
status_code=samlp.StatusCode(value=fro,
status_code=samlp.StatusCode(value=code)))
def assertion_factory(**kwargs):
assertion = saml.Assertion(version=VERSION, id=sid(),
@ -275,7 +275,7 @@ def _attrval(val, typ=""):
if typ:
for ava in attrval:
ava.set_type(typ)
return attrval
# --- attribute profiles -----
@ -293,7 +293,7 @@ def do_ava(val, typ=""):
attrval = [do_ava(v)[0] for v in val]
elif val or val is False:
ava = saml.AttributeValue()
ava.set_text(val)
ava.set_text(val)
attrval = [ava]
elif val is None:
attrval = None
@ -305,7 +305,7 @@ def do_ava(val, typ=""):
ava.set_type(typ)
return attrval
def do_attribute(val, typ, key):
attr = saml.Attribute()
@ -328,7 +328,7 @@ def do_attribute(val, typ, key):
if friendly:
attr.friendly_name = friendly
return attr
def do_attributes(identity):
attrs = []
@ -340,14 +340,14 @@ def do_attributes(identity):
except ValueError:
val = spec
typ = ""
except TypeError:
except TypeError:
val = ""
typ = ""
attr = do_attribute(val, typ, key)
attrs.append(attr)
return attrs
def do_attribute_statement(identity):
"""

View File

@ -1,2 +1 @@
__author__ = 'rolandh'

View File

@ -60,7 +60,7 @@ class TOperation_(wsdl.TExtensibilityElement_):
extension_elements=None,
extension_attributes=None,
):
wsdl.TExtensibilityElement_.__init__(self,
wsdl.TExtensibilityElement_.__init__(self,
required=required,
text=text,
extension_elements=extension_elements,
@ -113,7 +113,7 @@ class TFaultRes_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -147,7 +147,7 @@ class TFault_(TFaultRes_):
extension_elements=None,
extension_attributes=None,
):
TFaultRes_.__init__(self,
TFaultRes_.__init__(self,
required=required,
parts=parts,
encoding_style=encoding_style,
@ -188,7 +188,7 @@ class THeaderFault_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -221,7 +221,7 @@ class TAddress_(wsdl.TExtensibilityElement_):
extension_elements=None,
extension_attributes=None,
):
wsdl.TExtensibilityElement_.__init__(self,
wsdl.TExtensibilityElement_.__init__(self,
required=required,
text=text,
extension_elements=extension_elements,
@ -253,7 +253,7 @@ class TBinding_(wsdl.TExtensibilityElement_):
extension_elements=None,
extension_attributes=None,
):
wsdl.TExtensibilityElement_.__init__(self,
wsdl.TExtensibilityElement_.__init__(self,
required=required,
text=text,
extension_elements=extension_elements,
@ -304,7 +304,7 @@ class TBody_(wsdl.TExtensibilityElement_):
extension_elements=None,
extension_attributes=None,
):
wsdl.TExtensibilityElement_.__init__(self,
wsdl.TExtensibilityElement_.__init__(self,
required=required,
text=text,
extension_elements=extension_elements,
@ -419,7 +419,7 @@ class THeader_(wsdl.TExtensibilityElement_):
extension_elements=None,
extension_attributes=None,
):
wsdl.TExtensibilityElement_.__init__(self,
wsdl.TExtensibilityElement_.__init__(self,
required=required,
text=text,
extension_elements=extension_elements,

View File

@ -128,7 +128,7 @@ class Envelope_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -207,7 +207,7 @@ class Fault_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,

View File

@ -58,7 +58,7 @@ class TDocumented_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -111,7 +111,7 @@ class TImport_(TExtensibleAttributesDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleAttributesDocumented_.__init__(self,
TExtensibleAttributesDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -160,7 +160,7 @@ class TPart_(TExtensibleAttributesDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleAttributesDocumented_.__init__(self,
TExtensibleAttributesDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -194,7 +194,7 @@ class TOperation_(TExtensibleDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleDocumented_.__init__(self,
TExtensibleDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -227,7 +227,7 @@ class TParam_(TExtensibleAttributesDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleAttributesDocumented_.__init__(self,
TExtensibleAttributesDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -260,7 +260,7 @@ class TFault_(TExtensibleAttributesDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleAttributesDocumented_.__init__(self,
TExtensibleAttributesDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -291,7 +291,7 @@ class TBindingOperationMessage_(TExtensibleDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleDocumented_.__init__(self,
TExtensibleDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -321,7 +321,7 @@ class TBindingOperationFault_(TExtensibleDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleDocumented_.__init__(self,
TExtensibleDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -400,7 +400,7 @@ class TBindingOperation_(TExtensibleDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleDocumented_.__init__(self,
TExtensibleDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -435,7 +435,7 @@ class TPort_(TExtensibleDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleDocumented_.__init__(self,
TExtensibleDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -465,7 +465,7 @@ class TExtensibilityElement_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -536,7 +536,7 @@ class TMessage_(TExtensibleDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleDocumented_.__init__(self,
TExtensibleDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -584,7 +584,7 @@ class TPortType_(TExtensibleAttributesDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleAttributesDocumented_.__init__(self,
TExtensibleAttributesDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -634,7 +634,7 @@ class TBinding_(TExtensibleDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleDocumented_.__init__(self,
TExtensibleDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -683,7 +683,7 @@ class TService_(TExtensibleDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleDocumented_.__init__(self,
TExtensibleDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,
@ -791,7 +791,7 @@ class TDefinitions_(TExtensibleDocumented_):
extension_elements=None,
extension_attributes=None,
):
TExtensibleDocumented_.__init__(self,
TExtensibleDocumented_.__init__(self,
documentation=documentation,
text=text,
extension_elements=extension_elements,

View File

@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
"""Contains classes and functions that a SAML2.0 Identity provider (IdP)
"""Contains classes and functions that a SAML2.0 Identity provider (IdP)
or attribute authority (AA) may use to conclude its tasks.
"""
import logging
@ -100,8 +100,8 @@ class Server(Entity):
raise NotImplementedError("No such storage type implemented")
def init_config(self, stype="idp"):
""" Remaining init of the server configuration
""" Remaining init of the server configuration
:param stype: The type of Server ("idp"/"aa")
"""
if stype == "aa":
@ -201,7 +201,7 @@ class Server(Entity):
# -------------------------------------------------------------------------
def parse_authn_request(self, enc_request, binding=BINDING_HTTP_REDIRECT):
"""Parse a Authentication Request
:param enc_request: The request in its transport format
:param binding: Which binding that was used to transport the message
to this entity.
@ -217,7 +217,7 @@ class Server(Entity):
def parse_attribute_query(self, xml_string, binding):
""" Parse an attribute query
:param xml_string: The Attribute Query as an XML string
:param binding: Which binding that was used for the request
:return: A query instance
@ -280,7 +280,7 @@ class Server(Entity):
sign_assertion=False, sign_response=False,
best_effort=False, encrypt_assertion=False, encrypt_cert=None):
""" Create a response. A layer of indirection.
:param in_response_to: The session identifier of the request
:param consumer_url: The URL which should receive the response
:param sp_entity_id: The entity identifier of the SP
@ -361,7 +361,7 @@ class Server(Entity):
sign_assertion=False, sign_response=False,
attributes=None, **kwargs):
""" Create an attribute assertion response.
:param identity: A dictionary with attributes and values that are
expected to be the bases for the assertion in the response.
:param in_response_to: The session identifier of the request

View File

@ -33,7 +33,7 @@ class WrongMessageType(Exception):
def parse_soap_enveloped_saml_response(text):
tags = ['{%s}Response' % SAMLP_NAMESPACE,
tags = ['{%s}Response' % SAMLP_NAMESPACE,
'{%s}LogoutResponse' % SAMLP_NAMESPACE]
return parse_soap_enveloped_saml_thingy(text, tags)
@ -128,7 +128,7 @@ def parse_soap_enveloped_saml_authn_response(text):
def parse_soap_enveloped_saml_thingy(text, expected_tags):
"""Parses a SOAP enveloped SAML thing and returns the thing as
a string.
:param text: The SOAP object as XML string
:param expected_tags: What the tag of the SAML thingy is expected to be.
:return: SAML thingy as a string
@ -137,7 +137,7 @@ def parse_soap_enveloped_saml_thingy(text, expected_tags):
# Make sure it's a SOAP message
assert envelope.tag == '{%s}Envelope' % soapenv.NAMESPACE
assert len(envelope) >= 1
body = None
for part in envelope:
@ -148,7 +148,7 @@ def parse_soap_enveloped_saml_thingy(text, expected_tags):
if body is None:
return ""
saml_part = body[0]
if saml_part.tag in expected_tags:
return ElementTree.tostring(saml_part, encoding="UTF-8")
@ -190,7 +190,7 @@ def class_instances_from_soap_enveloped_saml_thingies(text, modules):
assert envelope.tag == '{%s}Envelope' % soapenv.NAMESPACE
assert len(envelope) >= 1
env = {"header": [], "body": None}
for part in envelope:
if part.tag == '{%s}Body' % soapenv.NAMESPACE:
assert len(part) == 1
@ -232,7 +232,7 @@ def open_soap_envelope(text):
def make_soap_enveloped_saml_thingy(thingy, headers=None):
""" Returns a soap envelope containing a SAML request
as a text string.
:param thingy: The SAML thingy
:return: The SOAP envelope as a string
"""

View File

@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
"""
Implements some usefull functions when dealing with validity of
Implements some usefull functions when dealing with validity of
different types of information.
"""
@ -21,7 +21,7 @@ TIME_FORMAT_WITH_FRAGMENT = re.compile(
# ---------------------------------------------------------------------------
# I'm sure this is implemented somewhere else can't find it now though, so I
# made an attempt.
#Implemented according to
#Implemented according to
#http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/
#adding-durations-to-dateTimes
@ -67,7 +67,7 @@ def parse_duration(duration):
sign = '+'
assert duration[index] == "P"
index += 1
dic = dict([(typ, 0) for (code, typ) in D_FORMAT if typ])
dlen = len(duration)
@ -113,14 +113,14 @@ def parse_duration(duration):
if index == dlen:
break
return sign, dic
def add_duration(tid, duration):
(sign, dur) = parse_duration(duration)
if sign == '+':
#Months
temp = tid.tm_mon + dur["tm_mon"]
@ -159,7 +159,7 @@ def add_duration(tid, duration):
temp = month + carry
month = modulo(temp, 1, 13)
year += f_quotient(temp, 1, 13)
return time.localtime(time.mktime((year, month, days, hour, minutes,
secs, 0, 0, -1)))
else:
@ -202,7 +202,7 @@ def in_a_while(days=0, seconds=0, microseconds=0, milliseconds=0,
"""
if format is None:
format = TIME_FORMAT
return time_in_a_while(days, seconds, microseconds, milliseconds,
minutes, hours, weeks).strftime(format)

View File

@ -71,7 +71,7 @@ def valid_url(url):
_ = urlparse.urlparse(url)
except Exception:
raise NotValid("URL")
# if part[1] == "localhost" or part[1] == "127.0.0.1":
# raise NotValid("URL")
return True
@ -103,7 +103,7 @@ def valid_address(address):
if not (valid_ipv4(address) or valid_ipv6(address)):
raise NotValid("address")
return True
def valid_ipv4(address):
parts = address.split(".")
@ -116,8 +116,8 @@ def valid_ipv4(address):
except ValueError:
return False
return True
#
#
IPV6_PATTERN = re.compile(r"""
^
\s* # Leading whitespace
@ -135,7 +135,7 @@ IPV6_PATTERN = re.compile(r"""
| (?<!:) #
| (?<=:) (?<!::) : #
) # OR
| # A v4 address with NO leading zeros
| # A v4 address with NO leading zeros
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]?\d)
(?: \.
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]?\d)
@ -144,7 +144,7 @@ IPV6_PATTERN = re.compile(r"""
\s* # Trailing whitespace
$
""", re.VERBOSE | re.IGNORECASE | re.DOTALL)
def valid_ipv6(address):
"""Validates IPv6 addresses. """
@ -157,7 +157,7 @@ def valid_boolean(val):
return True
else:
raise NotValid("boolean")
def valid_duration(val):
try:
@ -168,8 +168,8 @@ def valid_duration(val):
def valid_string(val):
""" Expects unicode
Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] |
""" Expects unicode
Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] |
[#x10000-#x10FFFF]
"""
for char in val:
@ -188,7 +188,7 @@ def valid_string(val):
else:
raise NotValid("string")
return True
def valid_unsigned_short(val):
try:
@ -197,9 +197,9 @@ def valid_unsigned_short(val):
raise NotValid("unsigned short")
except ValueError:
raise NotValid("unsigned short")
return True
def valid_positive_integer(val):
try:
@ -218,7 +218,7 @@ def valid_non_negative_integer(val):
integer = int(val)
except ValueError:
raise NotValid("non negative integer")
if integer < 0:
raise NotValid("non negative integer")
return True
@ -230,7 +230,7 @@ def valid_integer(val):
except ValueError:
raise NotValid("integer")
return True
def valid_base64(val):
try:
@ -241,11 +241,11 @@ def valid_base64(val):
def valid_qname(val):
""" A qname is either
NCName or
""" A qname is either
NCName or
NCName ':' NCName
"""
try:
(prefix, localpart) = val.split(":")
return valid_ncname(prefix) and valid_ncname(localpart)
@ -254,8 +254,8 @@ def valid_qname(val):
def valid_anytype(val):
""" Goes through all known type validators
""" Goes through all known type validators
:param val: The value to validate
:return: True is value is valid otherwise an exception is raised
"""
@ -267,12 +267,12 @@ def valid_anytype(val):
return True
except NotValid:
pass
if isinstance(val, type):
return True
raise NotValid("AnyType")
# -----------------------------------------------------------------------------
VALIDATOR = {
@ -306,7 +306,7 @@ def validate_value_type(value, spec):
"""
if "maxlen" in spec:
return len(value) <= spec["maxlen"]
if spec["base"] == "string":
if "enumeration" in spec:
if value not in spec["enumeration"]:
@ -318,7 +318,7 @@ def validate_value_type(value, spec):
valid(spec["member"], val)
else:
return valid(spec["base"], value)
return True
@ -370,7 +370,7 @@ def valid_instance(instance):
if required and not value:
txt = "Required value on property '%s' missing" % name
raise MustValueError("Class '%s' instance: %s" % (class_name, txt))
if value:
try:
if isinstance(typ, type):
@ -378,14 +378,14 @@ def valid_instance(instance):
spec = typ.c_value_type
else:
spec = {"base": "string"} # do I need a default
validate_value_type(value, spec)
else:
valid(typ, value)
except (NotValid, ValueError), exc:
txt = ERROR_TEXT % (value, name, exc.args[0])
raise NotValid("Class '%s' instance: %s" % (class_name, txt))
for (name, _spec) in instclass.c_children.values():
value = getattr(instance, name, '')
@ -422,7 +422,7 @@ def valid_instance(instance):
"Class '%s' instance cardinality error: %s" % (
class_name, "more then max (%s>%s)" % (vlen,
_cmax)))
if _list:
for val in value:
# That it is the right class is handled elsewhere

View File

@ -21,17 +21,17 @@ class VirtualOrg(object):
def _cache_session(self, session_info):
return True
def _affiliation_members(self):
"""
Get the member of the Virtual Organization from the metadata,
Get the member of the Virtual Organization from the metadata,
more specifically from AffiliationDescriptor.
"""
return self.sp.config.metadata.vo_members(self._name)
def members_to_ask(self, name_id):
"""Find the member of the Virtual Organization that I haven't already
spoken too
"""Find the member of the Virtual Organization that I haven't already
spoken too
"""
vo_members = self._affiliation_members()
@ -44,37 +44,37 @@ class VirtualOrg(object):
name_id, m)]
logger.info("VO members (not cached): %s" % vo_members)
return vo_members
def get_common_identifier(self, name_id):
(ava, _) = self.sp.users.get_identity(name_id)
if ava == {}:
return None
ident = self.common_identifier
try:
return ava[ident][0]
except KeyError:
return None
def do_aggregation(self, name_id):
logger.info("** Do VO aggregation **\nSubjectID: %s, VO:%s" % (
name_id, self._name))
to_ask = self.members_to_ask(name_id)
if to_ask:
com_identifier = self.get_common_identifier(name_id)
resolver = AttributeResolver(self.sp)
# extends returns a list of session_infos
# extends returns a list of session_infos
for session_info in resolver.extend(
com_identifier, self.sp.config.entityid, to_ask):
_ = self._cache_session(session_info)
logger.info(">Issuers: %s" % self.sp.users.issuers_of_info(name_id))
logger.info("AVA: %s" % (self.sp.users.get_identity(name_id),))
return True
else:
return False

View File

@ -96,7 +96,7 @@ class SignatureValueType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -124,7 +124,7 @@ class CanonicalizationMethodType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -172,7 +172,7 @@ class TransformType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -201,7 +201,7 @@ class DigestMethodType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -305,7 +305,7 @@ class X509IssuerSerialType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -366,7 +366,7 @@ class PGPDataType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -412,7 +412,7 @@ class SPKIDataType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -444,7 +444,7 @@ class ObjectType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -476,7 +476,7 @@ class SignaturePropertyType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -631,7 +631,7 @@ class DSAKeyValueType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -696,7 +696,7 @@ class RSAKeyValueType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -771,7 +771,7 @@ class SignatureMethodType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -931,7 +931,7 @@ class X509DataType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -1064,7 +1064,7 @@ class TransformsType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -1099,7 +1099,7 @@ class KeyValueType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -1146,7 +1146,7 @@ class SignaturePropertiesType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -1210,7 +1210,7 @@ class RetrievalMethodType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -1271,7 +1271,7 @@ class ReferenceType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -1413,7 +1413,7 @@ class ManifestType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -1453,7 +1453,7 @@ class SignedInfoType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -1541,7 +1541,7 @@ class SignatureType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,

View File

@ -59,7 +59,7 @@ class TransformsType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -137,7 +137,7 @@ class AgreementMethodType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -168,7 +168,7 @@ class ReferenceType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -198,7 +198,7 @@ class EncryptionPropertyType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -261,7 +261,7 @@ class EncryptionMethodType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -308,7 +308,7 @@ class CipherReferenceType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -396,7 +396,7 @@ class ReferenceList(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -457,7 +457,7 @@ class EncryptionPropertiesType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -491,7 +491,7 @@ class CipherDataType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -566,7 +566,7 @@ class EncryptedType_(SamlBase):
extension_elements=None,
extension_attributes=None,
):
SamlBase.__init__(self,
SamlBase.__init__(self,
text=text,
extension_elements=extension_elements,
extension_attributes=extension_attributes,
@ -641,7 +641,7 @@ class EncryptedKeyType_(EncryptedType_):
extension_elements=None,
extension_attributes=None,
):
EncryptedType_.__init__(self,
EncryptedType_.__init__(self,
encryption_method=encryption_method,
key_info=key_info,
cipher_data=cipher_data,