PEP-8
This commit is contained in:
parent
095f8dbe1d
commit
13fdda52ab
@ -1,2 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Created by Roland Hedberg
|
||||
# Created by Roland Hedberg
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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(
|
||||
|
@ -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()]
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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})
|
||||
|
||||
|
@ -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):
|
||||
|
||||
# ----------------------------------------
|
||||
|
@ -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):
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -1,3 +1,2 @@
|
||||
#profile schema descriptions
|
||||
__author__ = 'rolandh'
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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 []
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -1,2 +1 @@
|
||||
__author__ = 'rolandh'
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user