src/saml2/response.py
This commit is contained in:
@@ -75,7 +75,7 @@ class MyChallengeDecider:
|
||||
|
||||
# require a challenge for login
|
||||
for regex in self.path_login:
|
||||
if regex.match(uri) != None:
|
||||
if regex.match(uri) is not None:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@@ -47,7 +47,7 @@ class EntitlementMetadataProvider(object):
|
||||
elif "entitlement" not in self._store[user]:
|
||||
self._store[user]["entitlement"] = {}
|
||||
|
||||
if entitlement == None:
|
||||
if entitlement is None:
|
||||
entitlement = []
|
||||
self._store[user]["entitlement"][virtualorg] = entitlement
|
||||
self._store.sync()
|
||||
|
||||
@@ -36,10 +36,12 @@ from repoze.who.plugins.form import FormPluginBase
|
||||
|
||||
from saml2 import BINDING_HTTP_REDIRECT
|
||||
from saml2.client import Saml2Client
|
||||
#from saml2.attribute_resolver import AttributeResolver
|
||||
from saml2.config import SPConfig
|
||||
from saml2.s_utils import sid
|
||||
from saml2.virtual_org import VirtualOrg
|
||||
|
||||
#from saml2.population import Population
|
||||
#from saml2.attribute_resolver import AttributeResolver
|
||||
|
||||
def construct_came_from(environ):
|
||||
""" The URL that the user used when the process where interupted
|
||||
@@ -71,7 +73,7 @@ class SAML2Plugin(FormPluginBase):
|
||||
implements(IChallenger, IIdentifier, IAuthenticator, IMetadataProvider)
|
||||
|
||||
def __init__(self, rememberer_name, config, saml_client,
|
||||
virtual_organization, wayf, _cache, debug, sid_store=None):
|
||||
wayf, _cache, debug, sid_store=None):
|
||||
FormPluginBase.__init__(self)
|
||||
|
||||
self.rememberer_name = rememberer_name
|
||||
@@ -82,18 +84,7 @@ class SAML2Plugin(FormPluginBase):
|
||||
self.conf = config
|
||||
self.srv = self.conf["service"]["sp"]
|
||||
self.log = None
|
||||
|
||||
if virtual_organization:
|
||||
self.vorg = virtual_organization
|
||||
self.vorg_conf = None
|
||||
# try:
|
||||
# self.vorg_conf = self.conf[
|
||||
# "virtual_organization"][virtual_organization]
|
||||
# except KeyError:
|
||||
# self.vorg = None
|
||||
else:
|
||||
self.vorg = None
|
||||
|
||||
|
||||
try:
|
||||
self.metadata = self.conf["metadata"]
|
||||
except KeyError:
|
||||
@@ -116,8 +107,8 @@ class SAML2Plugin(FormPluginBase):
|
||||
|
||||
if len( idps ) == 1:
|
||||
idp_url = idps[0]["single_sign_on_service"][BINDING_HTTP_REDIRECT]
|
||||
elif len( idps ) == 0:
|
||||
return (1, HTTPInternalServerError(detail='Misconfiguration'))
|
||||
elif not len(idps):
|
||||
return 1, HTTPInternalServerError(detail='Misconfiguration')
|
||||
else:
|
||||
if self.wayf:
|
||||
wayf_selected = environ.get('s2repose.wayf_selected','')
|
||||
@@ -140,9 +131,9 @@ class SAML2Plugin(FormPluginBase):
|
||||
detail="Do not know how to talk to '%s'!" & (
|
||||
wayf_selected,)))
|
||||
else:
|
||||
return (1, HTTPNotImplemented(detail='No WAYF present!'))
|
||||
return 1, HTTPNotImplemented(detail='No WAYF present!')
|
||||
|
||||
return (0, idp_url)
|
||||
return 0, idp_url
|
||||
|
||||
#### IChallenger ####
|
||||
def challenge(self, environ, _status, _app_headers, _forget_headers):
|
||||
@@ -165,7 +156,8 @@ class SAML2Plugin(FormPluginBase):
|
||||
try:
|
||||
vorg = environ["myapp.vo"]
|
||||
except KeyError:
|
||||
vorg = self.vorg
|
||||
vorg = self.saml_client.vorg
|
||||
|
||||
self.log and self.log.info("[sp.challenge] VO: %s" % vorg)
|
||||
|
||||
# If more than one idp and if none is selected, I have to do wayf
|
||||
@@ -176,8 +168,9 @@ class SAML2Plugin(FormPluginBase):
|
||||
idp_url = response
|
||||
# Do the AuthnRequest
|
||||
(sid_, result) = self.saml_client.authenticate(location=idp_url,
|
||||
relay_state=came_from,
|
||||
vorg=vorg)
|
||||
relay_state=came_from,
|
||||
log=self.log,
|
||||
vorg=vorg)
|
||||
|
||||
# remember the request
|
||||
self.outstanding_queries[sid_] = came_from
|
||||
@@ -230,11 +223,12 @@ class SAML2Plugin(FormPluginBase):
|
||||
return post
|
||||
|
||||
def _construct_identity(self, session_info):
|
||||
identity = {}
|
||||
identity["login"] = session_info["name_id"]
|
||||
identity["password"] = ""
|
||||
identity['repoze.who.userid'] = session_info["name_id"]
|
||||
identity["user"] = session_info["ava"]
|
||||
identity = {
|
||||
"login": session_info["name_id"],
|
||||
"password": "",
|
||||
'repoze.who.userid': session_info["name_id"],
|
||||
"user": session_info["ava"],
|
||||
}
|
||||
if self.debug and self.log:
|
||||
self.log.info("Identity: %s" % identity)
|
||||
|
||||
@@ -329,12 +323,12 @@ class SAML2Plugin(FormPluginBase):
|
||||
environ["s2repoze.sessioninfo"] = session_info
|
||||
name_id = session_info["name_id"]
|
||||
# contruct and return the identity
|
||||
identity = {}
|
||||
identity["login"] = name_id
|
||||
identity["password"] = ""
|
||||
identity['repoze.who.userid'] = name_id
|
||||
identity["user"] = self.saml_client.users.get_identity(name_id)[0]
|
||||
|
||||
identity = {
|
||||
"login": name_id,
|
||||
"password": "",
|
||||
'repoze.who.userid': name_id,
|
||||
"user": self.saml_client.users.get_identity(name_id)[0],
|
||||
}
|
||||
self.log.info("[sp.identify] IDENTITY: %s" % (identity,))
|
||||
return identity
|
||||
else:
|
||||
@@ -371,23 +365,29 @@ class SAML2Plugin(FormPluginBase):
|
||||
|
||||
if "pysaml2_vo_expanded" not in identity:
|
||||
# is this a Virtual Organization situation
|
||||
if self.vorg:
|
||||
if self.vorg.do_vo_aggregation(subject_id):
|
||||
# Get the extended identity
|
||||
identity["user"] = self.saml_client.users.get_identity(
|
||||
if self.saml_client.vorg:
|
||||
try:
|
||||
if self.saml_client.vorg.do_aggregation(subject_id,
|
||||
log=self.log):
|
||||
# Get the extended identity
|
||||
identity["user"] = self.saml_client.users.get_identity(
|
||||
subject_id)[0]
|
||||
# Only do this once, mark that the identity has been
|
||||
# expanded
|
||||
identity["pysaml2_vo_expanded"] = 1
|
||||
|
||||
# Only do this once, mark that the identity has been
|
||||
# expanded
|
||||
identity["pysaml2_vo_expanded"] = 1
|
||||
except KeyError:
|
||||
self.log and self.log.error(
|
||||
"Failed to do attribute aggregation, "
|
||||
"missing common attribute")
|
||||
if self.debug:
|
||||
self.log and self.log.info("[add_metadata] returns: %s" % (dict(identity),))
|
||||
self.log and self.log.info("[add_metadata] returns: %s" % (
|
||||
dict(identity),))
|
||||
|
||||
|
||||
# @return
|
||||
# used 2 times : one to get the ticket, the other to validate it
|
||||
def _service_url(self, environ, qstr=None):
|
||||
if qstr != None:
|
||||
if qstr is not None:
|
||||
url = construct_url(environ, querystring = qstr)
|
||||
else:
|
||||
url = construct_url(environ)
|
||||
@@ -422,11 +422,12 @@ def make_plugin(rememberer_name=None, # plugin for remember
|
||||
|
||||
config = SPConfig()
|
||||
config.load_file(saml_conf)
|
||||
|
||||
scl = Saml2Client(config, identity_cache=identity_cache,
|
||||
virtual_organization=virtual_organization)
|
||||
|
||||
scl = Saml2Client(config, identity_cache=identity_cache)
|
||||
|
||||
plugin = SAML2Plugin(rememberer_name, config, scl,
|
||||
virtual_organization, wayf, cache, debug, sid_store)
|
||||
plugin = SAML2Plugin(rememberer_name, config, scl, wayf, cache, debug,
|
||||
sid_store)
|
||||
return plugin
|
||||
|
||||
# came_from = re.sub(r'ticket=[^&]*&?', '', came_from)
|
||||
|
||||
@@ -593,7 +593,7 @@ class SamlBase(ExtensionContainer):
|
||||
setattr(self, "text", "%d" % val)
|
||||
elif isinstance(val, basestring):
|
||||
setattr(self, "text", val)
|
||||
elif val == None:
|
||||
elif val is None:
|
||||
pass
|
||||
else:
|
||||
raise ValueError( "Type shouldn't be '%s'" % (val,))
|
||||
@@ -660,7 +660,7 @@ class SamlBase(ExtensionContainer):
|
||||
try:
|
||||
restriction = self.c_cardinality[prop]
|
||||
val = getattr(self, prop)
|
||||
if val == None:
|
||||
if val is None:
|
||||
num = 0
|
||||
elif isinstance(val, list):
|
||||
num = len(val)
|
||||
|
||||
@@ -70,7 +70,7 @@ def filter_on_attributes(ava, required=None, optional=None):
|
||||
"""
|
||||
res = {}
|
||||
|
||||
if required == None:
|
||||
if required is None:
|
||||
required = []
|
||||
|
||||
for attr in required:
|
||||
@@ -84,7 +84,7 @@ def filter_on_attributes(ava, required=None, optional=None):
|
||||
print >> sys.stderr, ava.keys()
|
||||
raise MissingValue("Required attribute missing: '%s'" % (attr.friendly_name,))
|
||||
|
||||
if optional == None:
|
||||
if optional is None:
|
||||
optional = []
|
||||
|
||||
for attr in optional:
|
||||
@@ -189,7 +189,7 @@ class Policy(object):
|
||||
self._restrictions = restrictions.copy()
|
||||
|
||||
for _, spec in self._restrictions.items():
|
||||
if spec == None:
|
||||
if spec is None:
|
||||
continue
|
||||
|
||||
try:
|
||||
@@ -197,7 +197,7 @@ class Policy(object):
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
if restr == None:
|
||||
if restr is None:
|
||||
continue
|
||||
|
||||
for key, values in restr.items():
|
||||
|
||||
@@ -44,7 +44,7 @@ def ac_factory(path):
|
||||
|
||||
def ava_fro(acs, statement):
|
||||
""" translates attributes according to their name_formats """
|
||||
if statement == []:
|
||||
if not statement:
|
||||
return {}
|
||||
|
||||
acsdic = dict([(ac.name_format, ac) for ac in acs])
|
||||
@@ -123,9 +123,9 @@ class AttributeConverter(object):
|
||||
self._to = eval(open(filename).read())
|
||||
|
||||
def adjust(self):
|
||||
if self._fro == None and self._to != None:
|
||||
if self._fro is None and self._to is not None:
|
||||
self._fro = dict([(value, key) for key, value in self._to.items()])
|
||||
if self._to == None and self.fro != None:
|
||||
if self._to is None and self.fro is not None:
|
||||
self._to = dict([(value, key) for key, value in self._fro.items()])
|
||||
|
||||
def fail_safe_fro(self, statement):
|
||||
@@ -161,7 +161,7 @@ class AttributeConverter(object):
|
||||
else:
|
||||
val.append(value.text.strip())
|
||||
|
||||
return (attr, val)
|
||||
return attr, val
|
||||
|
||||
def fro(self, statement):
|
||||
""" Get the attributes and the attribute values
|
||||
|
||||
@@ -21,17 +21,18 @@ to do attribute aggregation.
|
||||
"""
|
||||
import saml2
|
||||
|
||||
DEFAULT_BINDING = saml2.BINDING_HTTP_REDIRECT
|
||||
DEFAULT_BINDING = saml2.BINDING_SOAP
|
||||
|
||||
class AttributeResolver(object):
|
||||
|
||||
def __init__(self, environ, metadata=None, config=None, saml2client=None):
|
||||
def __init__(self, metadata=None, config=None, saml2client=None):
|
||||
self.metadata = metadata
|
||||
|
||||
if saml2client:
|
||||
self.saml2client = saml2client
|
||||
self.metadata = saml2client.config.metadata
|
||||
else:
|
||||
self.saml2client = saml2.client.Saml2Client(environ, config)
|
||||
self.saml2client = saml2.client.Saml2Client(config)
|
||||
|
||||
def extend(self, subject_id, issuer, vo_members, name_id_format=None,
|
||||
sp_name_qualifier=None, log=None):
|
||||
@@ -51,14 +52,19 @@ class AttributeResolver(object):
|
||||
for member in vo_members:
|
||||
for ass in self.metadata.attribute_services(member):
|
||||
for attr_serv in ass.attribute_service:
|
||||
log and log.info("Send attribute request to %s" % \
|
||||
attr_serv.location)
|
||||
if log:
|
||||
log.info(
|
||||
"Send attribute request to %s" % attr_serv.location)
|
||||
if attr_serv.binding != saml2.BINDING_SOAP:
|
||||
continue
|
||||
# attribute query assumes SOAP binding
|
||||
session_info = self.saml2client.attribute_query(
|
||||
subject_id,
|
||||
issuer,
|
||||
attr_serv.location,
|
||||
sp_name_qualifier=sp_name_qualifier,
|
||||
format=name_id_format, log=log)
|
||||
subject_id,
|
||||
attr_serv.location,
|
||||
issuer_id=issuer,
|
||||
sp_name_qualifier=sp_name_qualifier,
|
||||
nameid_format=name_id_format,
|
||||
log=log)
|
||||
if session_info:
|
||||
result.append(session_info)
|
||||
return result
|
||||
@@ -71,7 +71,7 @@ def http_post_message(message, location, relay_state="", typ="SAMLRequest"):
|
||||
response.append("""</script>""")
|
||||
response.append("</body>")
|
||||
|
||||
return ([("Content-type", "text/html")], response)
|
||||
return [("Content-type", "text/html")], response
|
||||
|
||||
def http_redirect_message(message, location, relay_state="",
|
||||
typ="SAMLRequest"):
|
||||
@@ -100,7 +100,7 @@ def http_redirect_message(message, location, relay_state="",
|
||||
headers = [('Location', login_url)]
|
||||
body = [""]
|
||||
|
||||
return (headers, body)
|
||||
return headers, body
|
||||
|
||||
def make_soap_enveloped_saml_thingy(thingy, header_parts=None):
|
||||
""" Returns a soap envelope containing a SAML request
|
||||
@@ -179,15 +179,15 @@ def parse_soap_enveloped_saml(text, body_class, header_class=None):
|
||||
#
|
||||
#
|
||||
# http = HTTPClient(destination, key_file, cert_file, log)
|
||||
# log and log.info("HTTP client initiated")
|
||||
# if log: log.info("HTTP client initiated")
|
||||
#
|
||||
# try:
|
||||
# response = http.get()
|
||||
# except Exception, exc:
|
||||
# log and log.info("HTTPClient exception: %s" % (exc,))
|
||||
# if log: log.info("HTTPClient exception: %s" % (exc,))
|
||||
# return None
|
||||
#
|
||||
# log and log.info("HTTP request sent and got response: %s" % response)
|
||||
# if log: log.info("HTTP request sent and got response: %s" % response)
|
||||
#
|
||||
# return response
|
||||
|
||||
@@ -195,7 +195,8 @@ def send_using_http_post(request, destination, relay_state, key_file=None,
|
||||
cert_file=None, log=None):
|
||||
|
||||
http = HTTPClient(destination, key_file, cert_file, log)
|
||||
log and log.info("HTTP client initiated")
|
||||
if log:
|
||||
log.info("HTTP client initiated")
|
||||
|
||||
if not isinstance(request, basestring):
|
||||
request = "%s" % (request,)
|
||||
@@ -204,10 +205,12 @@ def send_using_http_post(request, destination, relay_state, key_file=None,
|
||||
try:
|
||||
response = http.post(message, headers)
|
||||
except Exception, exc:
|
||||
log and log.info("HTTPClient exception: %s" % (exc,))
|
||||
if log:
|
||||
log.info("HTTPClient exception: %s" % (exc,))
|
||||
return None
|
||||
|
||||
log and log.info("HTTP request sent and got response: %s" % response)
|
||||
if log:
|
||||
log.info("HTTP request sent and got response: %s" % response)
|
||||
|
||||
return response
|
||||
|
||||
@@ -225,14 +228,17 @@ def send_using_soap(message, destination, key_file=None, cert_file=None,
|
||||
SOAPClient
|
||||
"""
|
||||
soapclient = SOAPClient(destination, key_file, cert_file, log)
|
||||
log and log.info("SOAP client initiated")
|
||||
if log:
|
||||
log.info("SOAP client initiated")
|
||||
try:
|
||||
response = soapclient.send(message)
|
||||
except Exception, exc:
|
||||
log and log.info("SoapClient exception: %s" % (exc,))
|
||||
if log:
|
||||
log.info("SoapClient exception: %s" % (exc,))
|
||||
return None
|
||||
|
||||
log and log.info("SOAP request sent and got response: %s" % response)
|
||||
if log:
|
||||
log.info("SOAP request sent and got response: %s" % response)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class Cache(object):
|
||||
try:
|
||||
entities = self._db[subject_id].keys()
|
||||
except KeyError:
|
||||
return ({}, [])
|
||||
return {}, []
|
||||
|
||||
res = {}
|
||||
oldees = []
|
||||
@@ -54,7 +54,7 @@ class Cache(object):
|
||||
res[key] = list(tmp)
|
||||
except KeyError:
|
||||
res[key] = vals
|
||||
return (res, oldees)
|
||||
return res, oldees
|
||||
|
||||
def get(self, subject_id, entity_id):
|
||||
""" Get session information about a subject gotten from a
|
||||
|
||||
@@ -45,6 +45,7 @@ from saml2.response import authn_response
|
||||
from saml2.response import response_factory
|
||||
from saml2.response import LogoutResponse
|
||||
from saml2.response import AuthnResponse
|
||||
from saml2.response import attribute_response
|
||||
|
||||
from saml2 import BINDING_HTTP_REDIRECT, BINDING_SOAP, BINDING_HTTP_POST
|
||||
|
||||
@@ -70,12 +71,13 @@ class LogoutError(Exception):
|
||||
class Saml2Client(object):
|
||||
""" The basic pySAML2 service provider class """
|
||||
|
||||
def __init__(self, config=None, debug=0, vorg=None,
|
||||
identity_cache=None, state_cache=None):
|
||||
def __init__(self, config=None, debug=0,
|
||||
identity_cache=None, state_cache=None,
|
||||
virtual_organization=None):
|
||||
"""
|
||||
:param config: A saml2.config.Config instance
|
||||
"""
|
||||
self.vorg = None
|
||||
|
||||
self.users = Population(identity_cache)
|
||||
|
||||
# for server state storage
|
||||
@@ -83,20 +85,21 @@ class Saml2Client(object):
|
||||
self.state = {} # in memory storage
|
||||
else:
|
||||
self.state = state_cache
|
||||
|
||||
|
||||
self.sec = None
|
||||
if config:
|
||||
self.config = config
|
||||
if "metadata" in config:
|
||||
self.metadata = config["metadata"]
|
||||
if vorg:
|
||||
self.vorg = VirtualOrg(self.metadata, vorg,
|
||||
self.users.cache,
|
||||
log=None, vorg_conf=None)
|
||||
self.sec = security_context(config)
|
||||
else:
|
||||
self.config = {}
|
||||
|
||||
if virtual_organization:
|
||||
self.vorg = VirtualOrg(self, virtual_organization)
|
||||
else:
|
||||
self.vorg = None
|
||||
|
||||
if not debug and self.config:
|
||||
self.debug = self.config.debug()
|
||||
else:
|
||||
@@ -169,15 +172,18 @@ class Saml2Client(object):
|
||||
reply_addr, outstanding, log,
|
||||
debug=self.debug)
|
||||
except Exception, exc:
|
||||
log and log.error("%s" % exc)
|
||||
if log:
|
||||
log.error("%s" % exc)
|
||||
return None
|
||||
|
||||
if self.debug:
|
||||
log and log.info(">>", resp)
|
||||
if log:
|
||||
log.info(">>", resp)
|
||||
resp = resp.verify()
|
||||
if isinstance(resp, AuthnResponse):
|
||||
self.users.add_information_about_person(resp.session_info())
|
||||
log and log.error("--- ADDED person info ----")
|
||||
if log:
|
||||
log.error("--- ADDED person info ----")
|
||||
elif isinstance(resp, LogoutResponse):
|
||||
self.handle_logout_response(resp, log)
|
||||
elif log:
|
||||
@@ -231,16 +237,23 @@ class Saml2Client(object):
|
||||
to_sign = []
|
||||
|
||||
request.name_id_policy = name_id_policy
|
||||
request.issuer = factory(saml.Issuer, text=spentityid )
|
||||
request.issuer = self.issuer(spentityid)
|
||||
|
||||
if log:
|
||||
log.info("REQUEST: %s" % request)
|
||||
|
||||
return "%s" % signed_instance_factory(request, self.sec, to_sign)
|
||||
|
||||
def issuer(self):
|
||||
def issuer(self, entityid=None):
|
||||
""" Return an Issuer instance """
|
||||
return saml.Issuer(text=self.config["entityid"],
|
||||
if entityid:
|
||||
if isinstance(entityid, saml.Issuer):
|
||||
return entityid
|
||||
else:
|
||||
return saml.Issuer(text=entityid,
|
||||
format=saml.NAMEID_FORMAT_ENTITY)
|
||||
else:
|
||||
return saml.Issuer(text=self.config["entityid"],
|
||||
format=saml.NAMEID_FORMAT_ENTITY)
|
||||
|
||||
def _spentityid(self, spentityid=None):
|
||||
@@ -306,7 +319,8 @@ class Saml2Client(object):
|
||||
authen_req = self.authn_request(session_id, location,
|
||||
service_url, spentityid, my_name, vorg,
|
||||
scoping, log, sign)
|
||||
log and log.info("AuthNReq: %s" % authen_req)
|
||||
if log:
|
||||
log.info("AuthNReq: %s" % authen_req)
|
||||
|
||||
if binding == saml2.BINDING_HTTP_POST:
|
||||
# No valid ticket; Send a form to the client
|
||||
@@ -319,11 +333,11 @@ class Saml2Client(object):
|
||||
response = head[0]
|
||||
else:
|
||||
raise Exception("Unkown binding type: %s" % binding)
|
||||
return (session_id, response)
|
||||
return session_id, response
|
||||
|
||||
|
||||
def create_attribute_query(self, session_id, subject_id, destination,
|
||||
issuer=None, attribute=None, sp_name_qualifier=None,
|
||||
issuer_id=None, attribute=None, sp_name_qualifier=None,
|
||||
name_qualifier=None, nameid_format=None, sign=False):
|
||||
""" Constructs an AttributeQuery
|
||||
|
||||
@@ -359,7 +373,7 @@ class Saml2Client(object):
|
||||
version=VERSION,
|
||||
issue_instant=instant(),
|
||||
destination=destination,
|
||||
issuer=issuer,
|
||||
issuer=self.issuer(issuer_id),
|
||||
subject=subject,
|
||||
)
|
||||
|
||||
@@ -376,10 +390,10 @@ class Saml2Client(object):
|
||||
return query
|
||||
|
||||
|
||||
def attribute_query(self, subject_id, destination, issuer=None,
|
||||
def attribute_query(self, subject_id, destination, issuer_id=None,
|
||||
attribute=None, sp_name_qualifier=None, name_qualifier=None,
|
||||
nameid_format=None, log=None):
|
||||
""" Does a attribute request from an attribute authority
|
||||
""" Does a attribute request to an attribute authority
|
||||
|
||||
:param subject_id: The identifier of the subject
|
||||
:param destination: To whom the query should be sent
|
||||
@@ -395,45 +409,50 @@ class Saml2Client(object):
|
||||
"""
|
||||
|
||||
session_id = sid()
|
||||
if not issuer:
|
||||
issuer = self.issuer()
|
||||
issuer = self.issuer(issuer_id)
|
||||
|
||||
request = self.create_attribute_query(session_id, subject_id,
|
||||
destination, issuer, attribute, sp_name_qualifier,
|
||||
name_qualifier, nameid_format=nameid_format)
|
||||
|
||||
log and log.info("Request, created: %s" % request)
|
||||
if log:
|
||||
log.info("Request, created: %s" % request)
|
||||
|
||||
soapclient = SOAPClient(destination, self.config["key_file"],
|
||||
self.config["cert_file"])
|
||||
log and log.info("SOAP client initiated")
|
||||
if log:
|
||||
log.info("SOAP client initiated")
|
||||
try:
|
||||
response = soapclient.send(request)
|
||||
except Exception, exc:
|
||||
log and log.info("SoapClient exception: %s" % (exc,))
|
||||
if log:
|
||||
log.info("SoapClient exception: %s" % (exc,))
|
||||
return None
|
||||
|
||||
log and log.info("SOAP request sent and got response: %s" % response)
|
||||
if log:
|
||||
log.info("SOAP request sent and got response: %s" % response)
|
||||
if response:
|
||||
log and log.info("Verifying response")
|
||||
if log:
|
||||
log.info("Verifying response")
|
||||
|
||||
try:
|
||||
aresp = authn_response(self.config, "", issuer,
|
||||
outstanding_queries={session_id:""},
|
||||
log=log)
|
||||
aresp = attribute_response(self.config, "", issuer, log=log)
|
||||
except Exception, exc:
|
||||
log and log.error("%s", (exc,))
|
||||
if log:
|
||||
log.error("%s", (exc,))
|
||||
return None
|
||||
|
||||
session_info = aresp.loads(response).verify().session_info()
|
||||
session_info = aresp.loads(response, False).verify().session_info()
|
||||
|
||||
if session_info:
|
||||
self.users.add_information_about_person(session_info)
|
||||
|
||||
log and log.info("session: %s" % session_info)
|
||||
if log:
|
||||
log.info("session: %s" % session_info)
|
||||
return session_info
|
||||
else:
|
||||
log and log.info("No response")
|
||||
if log:
|
||||
log.info("No response")
|
||||
return None
|
||||
|
||||
def logout_requests(self, subject_id, destination, entity_id,
|
||||
@@ -493,7 +512,8 @@ class Saml2Client(object):
|
||||
conversation.
|
||||
"""
|
||||
|
||||
log and log.info("logout request for: %s" % subject_id)
|
||||
if log:
|
||||
log.info("logout request for: %s" % subject_id)
|
||||
|
||||
# find out which IdPs/AAs I should notify
|
||||
entity_ids = self.users.issuers_of_info(subject_id)
|
||||
@@ -505,15 +525,16 @@ class Saml2Client(object):
|
||||
sign, log=None, return_to="/"):
|
||||
|
||||
# check time
|
||||
if not_on_or_after(expire) == False: # I've run out of time
|
||||
if not not_on_or_after(expire): # I've run out of time
|
||||
# Do the local logout anyway
|
||||
self.local_logout(subject_id)
|
||||
return (0, "504 Gateway Timeout", [], [])
|
||||
return 0, "504 Gateway Timeout", [], []
|
||||
|
||||
# for all where I can use the SOAP binding, do those first
|
||||
not_done = entity_ids[:]
|
||||
session_id = 0
|
||||
|
||||
response = False
|
||||
|
||||
for entity_id in entity_ids:
|
||||
response = False
|
||||
rstate = None
|
||||
@@ -523,7 +544,8 @@ class Saml2Client(object):
|
||||
if not destination:
|
||||
continue
|
||||
|
||||
log and log.info("destination to provider: %s" % destination)
|
||||
if log:
|
||||
log.info("destination to provider: %s" % destination)
|
||||
request = self.logout_requests(subject_id, destination,
|
||||
entity_id, reason, expire, log)
|
||||
|
||||
@@ -544,14 +566,17 @@ class Saml2Client(object):
|
||||
self.config["cert_file"],
|
||||
log=log)
|
||||
if response:
|
||||
log and log.info("Verifying response")
|
||||
if log:
|
||||
log.info("Verifying response")
|
||||
response = self.logout_response(response, log)
|
||||
|
||||
if response:
|
||||
not_done.remove(entity_id)
|
||||
log and log.info("OK response from %s" % destination)
|
||||
if log:
|
||||
log.info("OK response from %s" % destination)
|
||||
else:
|
||||
log and log.info(
|
||||
if log:
|
||||
log.info(
|
||||
"NOT OK response from %s" % destination)
|
||||
|
||||
else:
|
||||
@@ -579,13 +604,13 @@ class Saml2Client(object):
|
||||
rstate)
|
||||
code = "302 Found"
|
||||
|
||||
return (session_id, code, head, body)
|
||||
return session_id, code, head, body
|
||||
|
||||
if not_done != []:
|
||||
if not_done:
|
||||
# upstream should try later
|
||||
raise LogoutError("%s" % (entity_ids,))
|
||||
|
||||
return (0, "", [], response)
|
||||
return 0, "", [], response
|
||||
|
||||
def local_logout(self, subject_id):
|
||||
""" Remove the user from the cache, equals local logout
|
||||
@@ -603,15 +628,18 @@ class Saml2Client(object):
|
||||
:return: 4-tuple of (session_id of the last sent logout request,
|
||||
response message, response headers and message)
|
||||
"""
|
||||
log and log.info("state: %s" % (self.state,))
|
||||
if log:
|
||||
log.info("state: %s" % (self.state,))
|
||||
status = self.state[response.in_response_to]
|
||||
log and log.info("status: %s" % (status,))
|
||||
if log:
|
||||
log.info("status: %s" % (status,))
|
||||
issuer = response.issuer()
|
||||
log and log.info("issuer: %s" % issuer)
|
||||
if log:
|
||||
log.info("issuer: %s" % issuer)
|
||||
del self.state[response.in_response_to]
|
||||
if status["entity_ids"] == [issuer]: # done
|
||||
self.local_logout(status["subject_id"])
|
||||
return (0, "200 Ok", [("Content-type","text/html")], [])
|
||||
return 0, "200 Ok", [("Content-type","text/html")], []
|
||||
else:
|
||||
status["entity_ids"].remove(issuer)
|
||||
return self._logout(status["subject_id"],
|
||||
@@ -641,14 +669,16 @@ class Saml2Client(object):
|
||||
"single_logout_service",
|
||||
binding=binding)[0]
|
||||
except Exception:
|
||||
log and log.info("Not supposed to handle this!")
|
||||
if log:
|
||||
log.info("Not supposed to handle this!")
|
||||
return None
|
||||
|
||||
try:
|
||||
response = LogoutResponse(self.sec, return_addr, debug=True,
|
||||
log=log)
|
||||
except Exception, exc:
|
||||
log and log.info("%s" % exc)
|
||||
if log:
|
||||
log.info("%s" % exc)
|
||||
return None
|
||||
|
||||
if binding == BINDING_HTTP_REDIRECT:
|
||||
@@ -710,7 +740,7 @@ class Saml2Client(object):
|
||||
status)
|
||||
|
||||
if log:
|
||||
log.info("RESPONSE: %s" % response)
|
||||
log.info("RESPONSE: {0:>s}".format(response))
|
||||
|
||||
if 'RelayState' in get:
|
||||
rstate = get['RelayState']
|
||||
|
||||
@@ -104,7 +104,7 @@ class Config(dict):
|
||||
res = []
|
||||
for spec in self["service"][typ]["endpoints"][service]:
|
||||
if isinstance(spec, basestring):
|
||||
if binding == None or binding == DEFAULT_BINDING[service]:
|
||||
if binding is None or binding == DEFAULT_BINDING[service]:
|
||||
res.append(spec)
|
||||
elif isinstance(spec, tuple):
|
||||
if binding:
|
||||
|
||||
@@ -44,7 +44,7 @@ class Cache(object):
|
||||
if not entities:
|
||||
entities = self.entities(subject_id)
|
||||
if not entities:
|
||||
return ({}, [])
|
||||
return {}, []
|
||||
|
||||
res = {}
|
||||
oldees = []
|
||||
@@ -61,7 +61,7 @@ class Cache(object):
|
||||
res[key] = list(tmp)
|
||||
except KeyError:
|
||||
res[key] = vals
|
||||
return (res, oldees)
|
||||
return res, oldees
|
||||
|
||||
def get_info(self, item):
|
||||
""" Get session information about a subject gotten from a
|
||||
@@ -174,7 +174,7 @@ class Cache(object):
|
||||
|
||||
def update(self, subject_id, entity_id, ava):
|
||||
res = self._cache.get(_key(subject_id, entity_id))
|
||||
if res == None:
|
||||
if res is None:
|
||||
raise KeyError("No such subject")
|
||||
else:
|
||||
info = self.get_info(res)
|
||||
|
||||
@@ -115,7 +115,7 @@ class MetaData(object):
|
||||
if afd:
|
||||
members = [member.text.strip() for member in afd.affiliate_member]
|
||||
|
||||
if members != []:
|
||||
if members:
|
||||
entity[tag] = members
|
||||
|
||||
def _sp_metadata(self, entity_descr, entity, tag):
|
||||
@@ -229,7 +229,7 @@ class MetaData(object):
|
||||
if attr_serv.binding == BINDING_SOAP:
|
||||
aserv.append(attr_serv)
|
||||
|
||||
if aserv == []:
|
||||
if not aserv:
|
||||
continue
|
||||
|
||||
taad.attribute_service = aserv
|
||||
@@ -243,7 +243,7 @@ class MetaData(object):
|
||||
|
||||
aads.append(taad)
|
||||
|
||||
if aads != []:
|
||||
if aads:
|
||||
entity[tag] = aads
|
||||
|
||||
def clear_from_source(self, source):
|
||||
@@ -295,7 +295,7 @@ class MetaData(object):
|
||||
except KeyError:
|
||||
self._import[source] = [entity_descr.entity_id]
|
||||
|
||||
# have I seen this entity_id before ? If so log and ignore it
|
||||
# have I seen this entity_id before ? If so if log: ignore it
|
||||
if entity_descr.entity_id in self.entity:
|
||||
print >> sys.stderr, \
|
||||
"Duplicated Entity descriptor (entity id: '%s')" % \
|
||||
@@ -372,7 +372,7 @@ class MetaData(object):
|
||||
self.import_metadata(content, (url, cert))
|
||||
return True
|
||||
else:
|
||||
self.log and self.log.info("Response status: %s" % response.status)
|
||||
self.if log: self.log.info("Response status: %s" % response.status)
|
||||
return False
|
||||
|
||||
def idp_services(self, entity_id, typ, binding=None):
|
||||
@@ -541,14 +541,14 @@ class MetaData(object):
|
||||
try:
|
||||
return self._wants[entity_id]
|
||||
except KeyError:
|
||||
return ([], [])
|
||||
return [], []
|
||||
|
||||
@keep_updated
|
||||
def attribute_consumer(self, entity_id):
|
||||
try:
|
||||
ssos = self.entity[entity_id]["sp_sso"]
|
||||
except KeyError:
|
||||
return ([], [])
|
||||
return [], []
|
||||
|
||||
required = []
|
||||
optional = []
|
||||
@@ -560,7 +560,7 @@ class MetaData(object):
|
||||
else:
|
||||
optional.append(attr)
|
||||
|
||||
return (required, optional)
|
||||
return required, optional
|
||||
|
||||
def _orgname(self, org, lang="en"):
|
||||
if not org:
|
||||
@@ -594,8 +594,10 @@ class MetaData(object):
|
||||
for entity_id, edict in self.entity.items():
|
||||
if "idp_sso" in edict:
|
||||
#idp_aa_check self._valid(entity_id)
|
||||
name = None
|
||||
if "organization" in edict:
|
||||
name = self._orgname(edict["organization"],"en")
|
||||
|
||||
if not name:
|
||||
name = self._location(edict["idp_sso"])[0]
|
||||
idps[entity_id] = (name, edict["idp_sso"])
|
||||
|
||||
@@ -41,7 +41,7 @@ class Population(object):
|
||||
|
||||
def subjects(self):
|
||||
"""Returns the name id's for all the persons in the cache"""
|
||||
return self.cache.subjects();
|
||||
return self.cache.subjects()
|
||||
|
||||
def remove_person(self, subject_id):
|
||||
self.cache.delete(subject_id)
|
||||
|
||||
@@ -52,7 +52,7 @@ class Request(object):
|
||||
except TypeError:
|
||||
raise
|
||||
except Exception, excp:
|
||||
self.log and self.log.info("EXCEPTION: %s", excp)
|
||||
self.if log: self.log.info("EXCEPTION: %s", excp)
|
||||
|
||||
if not self.message:
|
||||
if self.log:
|
||||
|
||||
@@ -68,6 +68,19 @@ def authn_response(conf, entity_id, return_addr, outstanding_queries=None,
|
||||
return_addr, outstanding_queries, log, timeslack,
|
||||
debug)
|
||||
|
||||
# comes in over SOAP so synchronous
|
||||
def attribute_response(conf, entity_id, return_addr, log=None, timeslack=0,
|
||||
debug=0):
|
||||
sec = security_context(conf)
|
||||
if not timeslack:
|
||||
try:
|
||||
timeslack = int(conf["timeslack"])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return AttributeResponse(sec, conf.attribute_converters, entity_id,
|
||||
return_addr, log, timeslack, debug)
|
||||
|
||||
class StatusResponse(object):
|
||||
def __init__(self, sec_context, return_addr=None, log=None, timeslack=0,
|
||||
debug=0, request_id=0):
|
||||
@@ -140,7 +153,7 @@ class StatusResponse(object):
|
||||
except SignatureError:
|
||||
raise
|
||||
except Exception, excp:
|
||||
self.log and self.log.info("EXCEPTION: %s", excp)
|
||||
self.if log: self.log.info("EXCEPTION: %s", excp)
|
||||
|
||||
print "<", self.response
|
||||
|
||||
@@ -216,6 +229,33 @@ class LogoutResponse(StatusResponse):
|
||||
debug)
|
||||
self.signature_check = self.sec.correctly_signed_logout_response
|
||||
|
||||
class AttributeResponse(StatusResponse):
|
||||
def __init__(self, sec_context, attribute_converters, entity_id,
|
||||
return_addr=None, log=None, timeslack=0, debug=0):
|
||||
StatusResponse.__init__(self, sec_context, return_addr, log, timeslack,
|
||||
debug)
|
||||
self.entity_id = entity_id
|
||||
self.attribute_converters = attribute_converters
|
||||
|
||||
|
||||
def get_identity(self):
|
||||
# The assertion can contain zero or one attributeStatements
|
||||
if not self.assertion.attribute_statement:
|
||||
self.log.error("Missing Attribute Statement")
|
||||
ava = {}
|
||||
else:
|
||||
assert len(self.assertion.attribute_statement) == 1
|
||||
|
||||
if self.debug:
|
||||
self.log.info("Attribute Statement: %s" % (
|
||||
self.assertion.attribute_statement[0],))
|
||||
for aconv in self.attribute_converters():
|
||||
self.log.info(
|
||||
"Converts name format: %s" % (aconv.name_format,))
|
||||
|
||||
ava = to_local(self.attribute_converters(),
|
||||
self.assertion.attribute_statement[0])
|
||||
return ava
|
||||
|
||||
class AuthnResponse(StatusResponse):
|
||||
""" This is where all the profile complience is checked.
|
||||
@@ -281,7 +321,7 @@ class AuthnResponse(StatusResponse):
|
||||
self.timeslack)
|
||||
validate_before(condition.not_before, self.timeslack)
|
||||
except Exception, excp:
|
||||
self.log and self.log.error("Exception on condition: %s" % (excp,))
|
||||
self.if log: self.log.error("Exception on condition: %s" % (excp,))
|
||||
if not lax:
|
||||
raise
|
||||
else:
|
||||
@@ -357,7 +397,7 @@ class AuthnResponse(StatusResponse):
|
||||
|
||||
subjconf.append(subject_confirmation)
|
||||
|
||||
if subjconf == []:
|
||||
if not subjconf:
|
||||
raise Exception("No valid subject confirmation")
|
||||
|
||||
subject.subject_confirmation = subjconf
|
||||
@@ -374,7 +414,7 @@ class AuthnResponse(StatusResponse):
|
||||
self.log.info("assertion context: %s" % (self.context,))
|
||||
self.log.info("assertion keys: %s" % (assertion.keyswv()))
|
||||
self.log.info("outstanding_queries: %s" % (
|
||||
self.outstanding_queries))
|
||||
self.outstanding_queries,))
|
||||
|
||||
if self.context == "AuthNReq":
|
||||
self.authn_statement_ok()
|
||||
|
||||
@@ -122,7 +122,7 @@ def parse_attribute_map(filenames):
|
||||
forward[(name, name_format)] = friendly_name
|
||||
backward[friendly_name] = (name, name_format)
|
||||
|
||||
return (forward, backward)
|
||||
return forward, backward
|
||||
|
||||
def identity_attribute(form, attribute, forward_map=None):
|
||||
if form == "friendly":
|
||||
@@ -214,7 +214,7 @@ def response_factory(sign=False, encrypt=False, **kwargs):
|
||||
def _attrval(val, typ=""):
|
||||
if isinstance(val, list) or isinstance(val, set):
|
||||
attrval = [saml.AttributeValue(text=v) for v in val]
|
||||
elif val == None:
|
||||
elif val is None:
|
||||
attrval = None
|
||||
else:
|
||||
attrval = [saml.AttributeValue(text=val)]
|
||||
@@ -241,7 +241,7 @@ def do_ava(val, typ=""):
|
||||
ava = saml.AttributeValue()
|
||||
ava.set_text(val)
|
||||
attrval = [ava]
|
||||
elif val == None:
|
||||
elif val is None:
|
||||
attrval = None
|
||||
else:
|
||||
raise OtherError("strange value type on: %s" % val)
|
||||
|
||||
@@ -80,7 +80,7 @@ def _verify_value_type(typ, val):
|
||||
if typ == XSD + "float" or typ == XSD + "double":
|
||||
return float(val)
|
||||
if typ == XSD + "boolean":
|
||||
if (val.lower() == "true" or val.lower() == "false"):
|
||||
if val.lower() == "true" or val.lower() == "false":
|
||||
pass
|
||||
else:
|
||||
raise ValueError("Faulty boolean value")
|
||||
@@ -126,7 +126,7 @@ class AttributeValueBase(SamlBase):
|
||||
val = str(val)
|
||||
if not typ:
|
||||
self.set_type("xs:float")
|
||||
elif val == None:
|
||||
elif val is None:
|
||||
val = ""
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
@@ -93,6 +93,7 @@ class Identifier(object):
|
||||
try:
|
||||
return self._get_remote("persistent", entity_id, subject_id)
|
||||
except KeyError:
|
||||
temp_id = "xyz"
|
||||
while True:
|
||||
temp_id = sid()
|
||||
try:
|
||||
@@ -147,10 +148,11 @@ class Identifier(object):
|
||||
:param userid: The local persistent identifier for the subject.
|
||||
:return: The created identifier,
|
||||
"""
|
||||
temp_id = sid()
|
||||
while True:
|
||||
temp_id = sid()
|
||||
try:
|
||||
_ = self._get_local("transient", sp_entity_id, temp_id)
|
||||
temp_id = sid()
|
||||
except KeyError:
|
||||
break
|
||||
self._store("transient", sp_entity_id, userid, temp_id)
|
||||
@@ -232,6 +234,7 @@ class Server(object):
|
||||
# subject information is store in database
|
||||
# default database is a shelve database which is OK in some setups
|
||||
dbspec = self.conf["subject_data"]
|
||||
idb = None
|
||||
if isinstance(dbspec, basestring):
|
||||
idb = shelve.open(dbspec, writeback=True)
|
||||
else: # database spec is a a 2-tuple (type, address)
|
||||
@@ -241,11 +244,12 @@ class Server(object):
|
||||
elif typ == "memcached":
|
||||
idb = memcache.Client(addr)
|
||||
|
||||
if idb != None:
|
||||
if idb is not None:
|
||||
self.ident = Identifier(idb, self.conf.vo_conf, self.debug,
|
||||
self.log)
|
||||
else:
|
||||
raise Exception("Couldn't open identity database: %s" % (dbspec))
|
||||
raise Exception("Couldn't open identity database: %s" %
|
||||
(dbspec,))
|
||||
else:
|
||||
self.ident = None
|
||||
|
||||
@@ -289,9 +293,9 @@ class Server(object):
|
||||
try:
|
||||
consumer_url = self.metadata.consumer_url(sp_entity_id)
|
||||
except KeyError:
|
||||
self.log and self.log.info(
|
||||
self.if log: self.log.info(
|
||||
"Failed to find consumer URL for %s" % sp_entity_id)
|
||||
self.log and self.log.info(
|
||||
self.if log: self.log.info(
|
||||
"entities: %s" % self.metadata.entity.keys())
|
||||
raise UnknownPrincipal(sp_entity_id)
|
||||
|
||||
@@ -347,7 +351,7 @@ class Server(object):
|
||||
subject = attribute_query.subject_id()
|
||||
attribute = attribute_query.attribute()
|
||||
|
||||
return (subject, attribute, attribute_query.message)
|
||||
return subject, attribute, attribute_query.message
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
@@ -599,7 +603,7 @@ class Server(object):
|
||||
self.log.info("binding wanted: %s" % (binding,))
|
||||
raise
|
||||
|
||||
self.log and self.log.info("Endpoint: %s" % (slo))
|
||||
self.if log: self.log.info("Endpoint: %s" % slo)
|
||||
req = LogoutRequest(self.sec, slo)
|
||||
if binding == BINDING_SOAP:
|
||||
lreq = soap.parse_soap_enveloped_saml_logout_request(text)
|
||||
@@ -647,7 +651,7 @@ class Server(object):
|
||||
|
||||
|
||||
if not destination:
|
||||
self.log and self.log.error("Not way to return a response !!!")
|
||||
self.if log: self.log.error("Not way to return a response !!!")
|
||||
return ("412 Precondition Failed",
|
||||
[("Content-type", "text/html")],
|
||||
["No return way defined"])
|
||||
@@ -693,7 +697,7 @@ class Server(object):
|
||||
to_sign = [(class_name(response), mid)]
|
||||
response = signed_instance_factory(response, self.sec, to_sign)
|
||||
|
||||
self.log and self.log.info("Response: %s" % (response,))
|
||||
self.if log: self.log.info("Response: %s" % (response,))
|
||||
if binding == BINDING_HTTP_REDIRECT:
|
||||
(headers, message) = http_redirect_message(response,
|
||||
destination,
|
||||
@@ -703,4 +707,4 @@ class Server(object):
|
||||
(headers, message) = http_post_message(response, destination,
|
||||
typ="SAMLResponse")
|
||||
|
||||
return (rcode, headers, message)
|
||||
return rcode, headers, message
|
||||
|
||||
@@ -388,7 +388,7 @@ class SecurityContext(object):
|
||||
self.debug = 0
|
||||
|
||||
def correctly_signed(self, xml, must=False):
|
||||
self.log and self.log.info("verify correct signature")
|
||||
self.if log: self.log.info("verify correct signature")
|
||||
return self.correctly_signed_response(xml, must)
|
||||
|
||||
def decrypt(self, enctext):
|
||||
@@ -397,7 +397,7 @@ class SecurityContext(object):
|
||||
:param enctext: The encrypted text as a string
|
||||
:return: The decrypted text
|
||||
"""
|
||||
self.log and self.log.info("input len: %d" % len(enctext))
|
||||
self.if log: self.log.info("input len: %d" % len(enctext))
|
||||
_, fil = make_temp("%s" % enctext, decode=False)
|
||||
ntf = NamedTemporaryFile()
|
||||
|
||||
@@ -415,7 +415,8 @@ class SecurityContext(object):
|
||||
p_err = pof.stderr.read()
|
||||
|
||||
if self.debug:
|
||||
self.log.debug("Decrypt result: %s" % (p_out, p_err))
|
||||
self.log.debug("Decrypt result (out): %s" % (p_out))
|
||||
self.log.debug("Decrypt result (err): %s" % (p_err))
|
||||
|
||||
ntf.seek(0)
|
||||
return ntf.read()
|
||||
|
||||
@@ -133,7 +133,7 @@ class SOAPClient(object):
|
||||
response = self.server.post(soap_message,
|
||||
{"content-type": "application/soap+xml"})
|
||||
if response:
|
||||
self.log and self.log.info("SOAP response: %s" % response)
|
||||
self.if log: self.log.info("SOAP response: %s" % response)
|
||||
return parse_soap_enveloped_saml_response(response)
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -66,7 +66,7 @@ def _verify_value_type(typ, val):
|
||||
if typ == XSD + "float" or typ == XSD + "double":
|
||||
return float(val)
|
||||
if typ == XSD + "boolean":
|
||||
if (val.lower() == "true" or val.lower() == "false"):
|
||||
if val.lower() == "true" or val.lower() == "false":
|
||||
pass
|
||||
else:
|
||||
raise ValueError("Faulty boolean value")
|
||||
@@ -112,7 +112,7 @@ class AttributeValueBase(SamlBase):
|
||||
val = str(val)
|
||||
if not typ:
|
||||
self.set_type("xs:float")
|
||||
elif val == None:
|
||||
elif val is None:
|
||||
val = ""
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"key_file" : "test.key",
|
||||
"cert_file" : "test.pem",
|
||||
"xmlsec_binary" : "/opt/local/bin/xmlsec1",
|
||||
"xmlsec_binary" : "/usr/local/bin/xmlsec1",
|
||||
"metadata": {
|
||||
"local": ["sp_0.metadata"],
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<ns0:EntitiesDescriptor xmlns:ns0="urn:oasis:names:tc:SAML:2.0:metadata"><ns0:EntityDescriptor entityID="urn:mace:umu.se:saml:roland:sp"><ns0:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><ns0:KeyDescriptor><ns1:KeyInfo xmlns:ns1="http://www.w3.org/2000/09/xmldsig#"><ns1:X509Data><ns1:X509Certificate>MIICsDCCAhmgAwIBAgIJAJrzqSSwmDY9MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
|
||||
<ns0:EntitiesDescriptor xmlns:ns0="urn:oasis:names:tc:SAML:2.0:metadata"><ns0:EntityDescriptor entityID="http://www.example.com/roland/sp"><ns0:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><ns0:KeyDescriptor><ns1:KeyInfo xmlns:ns1="http://www.w3.org/2000/09/xmldsig#"><ns1:X509Data><ns1:X509Certificate>MIICsDCCAhmgAwIBAgIJAJrzqSSwmDY9MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
|
||||
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
|
||||
aWRnaXRzIFB0eSBMdGQwHhcNMDkxMDA2MTk0OTQxWhcNMDkxMTA1MTk0OTQxWjBF
|
||||
MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
|
||||
@@ -14,4 +14,4 @@ mDY9MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAJSrKOEzHO7TL5cy6
|
||||
h3qh+3+JAk8HbGBW+cbX6KBCAw/mzU8flK25vnWwXS3dv2FF3Aod0/S7AWNfKib5
|
||||
U/SA9nJaz/mWeF9S0farz9AQFc8/NSzAzaVq7YbM4F6f6N2FRl7GikdXRCed45j6
|
||||
mrPzGzk3ECbupFnqyREH3+ZPSdk=
|
||||
</ns1:X509Certificate></ns1:X509Data></ns1:KeyInfo></ns0:KeyDescriptor><ns0:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8087/" index="0" /><ns0:AttributeConsumingService><ns0:ServiceName ns1:lang="en" xmlns:ns1="http:#www.w3.org/XML/1998/namespace">Rolands SP</ns0:ServiceName><ns0:RequestedAttribute FriendlyName="surName" Name="urn:oid:2.5.4.4" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true" /><ns0:RequestedAttribute FriendlyName="givenName" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true" /><ns0:RequestedAttribute FriendlyName="mail" Name="urn:oid:0.9.2342.19200300.100.1.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true" /><ns0:RequestedAttribute FriendlyName="title" Name="urn:oid:2.5.4.12" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" /></ns0:AttributeConsumingService></ns0:SPSSODescriptor></ns0:EntityDescriptor></ns0:EntitiesDescriptor>
|
||||
</ns1:X509Certificate></ns1:X509Data></ns1:KeyInfo></ns0:KeyDescriptor><ns0:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="location" /><ns0:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://localhost:8087/" index="1" /><ns0:AttributeConsumingService index="1"><ns0:ServiceName xml:lang="en">Rolands SP</ns0:ServiceName><ns0:ServiceDescription xml:lang="en">Roland own test SP</ns0:ServiceDescription><ns0:RequestedAttribute Name="surName" isRequired="true" /><ns0:RequestedAttribute FriendlyName="givenName" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true" /><ns0:RequestedAttribute FriendlyName="mail" Name="urn:oid:0.9.2342.19200300.100.1.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true" /><ns0:RequestedAttribute FriendlyName="title" Name="urn:oid:2.5.4.12" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false" /></ns0:AttributeConsumingService></ns0:SPSSODescriptor></ns0:EntityDescriptor></ns0:EntitiesDescriptor>
|
||||
|
||||
@@ -165,7 +165,6 @@ def test_sp_metadata():
|
||||
assert _eq(md.wants('urn:mace:umu.se:saml:roland:sp')[1].keys(),
|
||||
["title"])
|
||||
|
||||
|
||||
KALMAR2_URL = "https://kalmar2.org/simplesaml/module.php/aggregator/?id=kalmarcentral2&set=saml2"
|
||||
KALMAR2_CERT = "kalmar2.pem"
|
||||
|
||||
|
||||
@@ -27,9 +27,12 @@ sp1 = {
|
||||
"urn-mace-swami.se-swamid-test-1.0-metadata.xml"],
|
||||
},
|
||||
"virtual_organization" : {
|
||||
"http://vo.example.org/biomed":{
|
||||
"nameid_format" : "urn:oid:2.16.756.1.2.5.1.1.1-NameID",
|
||||
"common_identifier": "swissEduPersonUniqueID",
|
||||
"coip":{
|
||||
"nameid_format" : "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
|
||||
"common_identifier": "eduPersonPrincipalName",
|
||||
"attribute_auth": [
|
||||
"https://coip-test.sunet.se/idp/shibboleth",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,4 +460,18 @@ class TestServerLogout():
|
||||
assert len(headers) == 1
|
||||
assert headers[0][0] == "Location"
|
||||
assert message == ['']
|
||||
|
||||
|
||||
# class TestSign():
|
||||
# def test_1(self):
|
||||
# IDP = server.Server("restrictive_idp.config", debug=1)
|
||||
# ava = { "givenName": ["Derek"], "surName": ["Jeter"],
|
||||
# "mail": ["derek@nyy.mlb.com"]}
|
||||
#
|
||||
# authn_resp = IDP.authn_response(ava,
|
||||
# "id1", "http://local:8087/",
|
||||
# "urn:mace:example.com:saml:roland:sp",
|
||||
# samlp.NameIDPolicy(format=saml.NAMEID_FORMAT_TRANSIENT,
|
||||
# allow_create="true"),
|
||||
# "foba0001@example.com", sign=True)
|
||||
# print authn_resp
|
||||
# assert False
|
||||
@@ -69,7 +69,6 @@ class TestClient:
|
||||
req = self.client.create_attribute_query("id1",
|
||||
"E8042FB4-4D5B-48C3-8E14-8EDD852790DD",
|
||||
"https://idp.example.com/idp/",
|
||||
self.client.issuer(),
|
||||
nameid_format=saml.NAMEID_FORMAT_PERSISTENT)
|
||||
reqstr = "%s" % req.to_string()
|
||||
xmlsec_vers = xmlsec_version(self.client.config["xmlsec_binary"])
|
||||
@@ -91,7 +90,6 @@ class TestClient:
|
||||
req = self.client.create_attribute_query("id1",
|
||||
"E8042FB4-4D5B-48C3-8E14-8EDD852790DD",
|
||||
"https://idp.example.com/idp/",
|
||||
self.client.issuer(),
|
||||
attribute={
|
||||
("urn:oid:2.5.4.42",
|
||||
"urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
|
||||
@@ -135,7 +133,6 @@ class TestClient:
|
||||
req = self.client.create_attribute_query("id1",
|
||||
"_e7b68a04488f715cda642fbdd90099f5",
|
||||
"https://aai-demo-idp.switch.ch/idp/shibboleth",
|
||||
self.client.issuer(),
|
||||
nameid_format=saml.NAMEID_FORMAT_TRANSIENT )
|
||||
|
||||
assert isinstance(req, samlp.AttributeQuery)
|
||||
@@ -152,7 +149,6 @@ class TestClient:
|
||||
req = self.client.attribute_query(
|
||||
"_e7b68a04488f715cda642fbdd90099f5",
|
||||
"https://aai-demo-idp.switch.ch/idp/shibboleth",
|
||||
self.client.issuer(),
|
||||
nameid_format=saml.NAMEID_FORMAT_TRANSIENT)
|
||||
|
||||
# since no one is answering on the other end
|
||||
|
||||
@@ -71,7 +71,7 @@ def base_init(imports):
|
||||
line.append("%sSamlBase.__init__(self, " % (INDENT+INDENT))
|
||||
for attr in BASE_ELEMENT:
|
||||
line.append("%s%s=%s," % (indent4, attr, attr))
|
||||
line.append("%s)" % (indent4))
|
||||
line.append("%s)" % indent4)
|
||||
else:
|
||||
# TODO have to keep apart which properties comes from which superior
|
||||
for sup, elems in imports.items():
|
||||
@@ -80,7 +80,7 @@ def base_init(imports):
|
||||
lattr.extend(BASE_ELEMENT)
|
||||
for attr in lattr:
|
||||
line.append("%s%s=%s," % (indent4, attr, attr))
|
||||
line.append("%s)" % (indent4))
|
||||
line.append("%s)" % indent4)
|
||||
return line
|
||||
|
||||
def initialize(attributes):
|
||||
@@ -106,7 +106,7 @@ def _mod_typ(prop):
|
||||
typ = prop.ref
|
||||
mod = None
|
||||
|
||||
return (mod, typ)
|
||||
return mod, typ
|
||||
|
||||
def _mod_cname(prop, cdict):
|
||||
if hasattr(prop, "scoped"):
|
||||
@@ -122,7 +122,7 @@ def _mod_cname(prop, cdict):
|
||||
else:
|
||||
cname = typ
|
||||
|
||||
return (mod, cname)
|
||||
return mod, cname
|
||||
|
||||
def leading_uppercase(string):
|
||||
try:
|
||||
@@ -270,7 +270,7 @@ class PyObj(object):
|
||||
else:
|
||||
args.append((prop.pyname, prop.pyname, None))
|
||||
|
||||
return (args, child, inh)
|
||||
return args, child, inh
|
||||
|
||||
def _superiors(self, cdict):
|
||||
imps = {}
|
||||
@@ -290,7 +290,7 @@ class PyObj(object):
|
||||
superior = []
|
||||
sups = []
|
||||
|
||||
return (superior, sups, imps)
|
||||
return superior, sups, imps
|
||||
|
||||
def class_definition(self, target_namespace, cdict=None, ignore=None):
|
||||
line = []
|
||||
@@ -427,7 +427,7 @@ class PyElement(PyObj):
|
||||
if not mod:
|
||||
cname = leading_uppercase(typ)
|
||||
if not cdict[cname].done:
|
||||
return ([cdict[cname]], [])
|
||||
return [cdict[cname]], []
|
||||
except ValueError:
|
||||
pass
|
||||
except TypeError: # could be a ref then or a PyObj instance
|
||||
@@ -438,8 +438,8 @@ class PyElement(PyObj):
|
||||
else:
|
||||
cname = leading_uppercase(self.ref)
|
||||
if not cdict[cname].done:
|
||||
return ([cdict[cname]], [])
|
||||
return ([], [])
|
||||
return [cdict[cname]], []
|
||||
return [], []
|
||||
|
||||
def _local_class(self, typ, cdict, child, target_namespace, ignore):
|
||||
if typ in cdict and not cdict[typ].done:
|
||||
@@ -524,7 +524,7 @@ class PyElement(PyObj):
|
||||
if mod:
|
||||
#self.superior = ["%s.%s" % (mod, typ)]
|
||||
if verify_import(self.root.modul[mod], typ):
|
||||
return (req, text)
|
||||
return req, text
|
||||
else:
|
||||
raise Exception(
|
||||
"Import attempted on %s from %s module failed - wasn't there" % (
|
||||
@@ -538,19 +538,19 @@ class PyElement(PyObj):
|
||||
raise MissingPrerequisite(self.ref)
|
||||
|
||||
self.done = True
|
||||
return (req, text)
|
||||
return req, text
|
||||
|
||||
def _do(obj, target_namespace, cdict, prep):
|
||||
try:
|
||||
(req, text) = obj.text(target_namespace, cdict)
|
||||
except MissingPrerequisite:
|
||||
return ([], None)
|
||||
return [], None
|
||||
|
||||
if text == None:
|
||||
if text is None:
|
||||
if req:
|
||||
#prep = prepend(req, prep)
|
||||
prep.append(req)
|
||||
return (prep, None)
|
||||
return prep, None
|
||||
else:
|
||||
obj.done = True
|
||||
if req:
|
||||
@@ -592,7 +592,7 @@ class PyType(PyObj):
|
||||
if not self.properties and not self.type \
|
||||
and not self.superior:
|
||||
self.done = True
|
||||
return ([], self.class_definition(target_namespace, cdict))
|
||||
return [], self.class_definition(target_namespace, cdict)
|
||||
|
||||
req = []
|
||||
inherited_properties = []
|
||||
@@ -613,7 +613,7 @@ class PyType(PyObj):
|
||||
if isinstance(res, tuple):
|
||||
return res
|
||||
|
||||
if self.properties[1] == []:
|
||||
if not self.properties[1]:
|
||||
inherited_properties = reqursive_superior(supc, cdict)
|
||||
|
||||
if inherited_properties:
|
||||
@@ -649,7 +649,7 @@ class PyType(PyObj):
|
||||
if isinstance(res, tuple):
|
||||
return res
|
||||
|
||||
return (req, self.class_definition(target_namespace, cdict, ignore))
|
||||
return req, self.class_definition(target_namespace, cdict, ignore)
|
||||
|
||||
def undefined(self, cdict):
|
||||
undef = ([], [])
|
||||
@@ -685,7 +685,7 @@ class PyAttribute(PyObj):
|
||||
if not cdict[self.type.name].done:
|
||||
raise MissingPrerequisite(self.type.name)
|
||||
|
||||
return ([], []) # Means this elements definition is empty
|
||||
return [], [] # Means this elements definition is empty
|
||||
|
||||
def spec(self):
|
||||
if isinstance(self.type, PyObj):
|
||||
@@ -718,7 +718,7 @@ class PyGroup(object):
|
||||
self.done = False
|
||||
|
||||
def text(self, _target_namespace, _dict, _child, _ignore):
|
||||
return ([], [])
|
||||
return [], []
|
||||
|
||||
def undefined(self, _cdict):
|
||||
undef = ([], [])
|
||||
@@ -802,7 +802,7 @@ def _namespace_and_tag(obj, param, top):
|
||||
namespace = ""
|
||||
tag = param
|
||||
|
||||
return (namespace, tag)
|
||||
return namespace, tag
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@@ -824,9 +824,9 @@ class Simple(object):
|
||||
argv_copy = sd_copy(argv)
|
||||
rval = self.repr(top, sup, argv_copy, True, parent)
|
||||
if rval:
|
||||
return ([rval], [])
|
||||
return [rval], []
|
||||
else:
|
||||
return ([], [])
|
||||
return [], []
|
||||
|
||||
def repr(self, _top=None, _sup=None, _argv=None, _child=True, _parent=""):
|
||||
return None
|
||||
@@ -849,7 +849,7 @@ class Attribute(Simple):
|
||||
def repr(self, top=None, sup=None, _argv=None, _child=True, _parent=""):
|
||||
# default, fixed, use, type
|
||||
|
||||
if (DEBUG):
|
||||
if DEBUG:
|
||||
print "#ATTR", self.__dict__
|
||||
|
||||
external = False
|
||||
@@ -921,7 +921,7 @@ class Attribute(Simple):
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if (DEBUG):
|
||||
if DEBUG:
|
||||
print "#--ATTR py_attr:%s" % (objekt,)
|
||||
|
||||
return objekt
|
||||
@@ -1021,15 +1021,15 @@ class Complex(object):
|
||||
|
||||
def collect(self, top, sup, argv=None, parent=""):
|
||||
if self._own or self._inherited:
|
||||
return (self._own, self._inherited)
|
||||
return self._own, self._inherited
|
||||
|
||||
if (DEBUG):
|
||||
if DEBUG:
|
||||
print self.__dict__
|
||||
print "#-- %d parts" % len(self.parts)
|
||||
|
||||
self._extend(top, sup, argv, parent)
|
||||
|
||||
return (self._own, self._inherited)
|
||||
return self._own, self._inherited
|
||||
|
||||
def do_child(self, elem):
|
||||
for child in elem:
|
||||
@@ -1106,7 +1106,7 @@ class Element(Complex):
|
||||
else:
|
||||
xns = namespace
|
||||
|
||||
return (namespace, name, ctyp, xns, ref)
|
||||
return namespace, name, ctyp, xns, ref
|
||||
|
||||
def collect(self, top, sup, argv=None, parent=""):
|
||||
""" means this element is part of a larger object, hence a property of
|
||||
@@ -1114,10 +1114,10 @@ class Element(Complex):
|
||||
|
||||
try:
|
||||
argv_copy = sd_copy(argv)
|
||||
return ([self.repr(top, sup, argv_copy, parent=parent)], [])
|
||||
return [self.repr(top, sup, argv_copy, parent=parent)], []
|
||||
except AttributeError, exc:
|
||||
print "!!!!", exc
|
||||
return ([], [])
|
||||
return [], []
|
||||
|
||||
def elements(self, top):
|
||||
(_namespace, name, ctyp, xns, _) = self.klass(top)
|
||||
@@ -1162,7 +1162,7 @@ class Element(Complex):
|
||||
else:
|
||||
objekt.ref = (namespace, superkl)
|
||||
except AttributeError, exc:
|
||||
if (DEBUG):
|
||||
if DEBUG:
|
||||
print "#===>", exc
|
||||
|
||||
typ = self.type
|
||||
@@ -1203,7 +1203,7 @@ class Element(Complex):
|
||||
parent=self.name)
|
||||
objekt.scoped = True
|
||||
else:
|
||||
if (DEBUG):
|
||||
if DEBUG:
|
||||
print "$", self
|
||||
raise
|
||||
|
||||
@@ -1267,9 +1267,9 @@ class ComplexContent(Complex):
|
||||
class Extension(Complex):
|
||||
def collect(self, top, sup, argv=None, parent=""):
|
||||
if self._own or self._inherited:
|
||||
return (self._own, self._inherited)
|
||||
return self._own, self._inherited
|
||||
|
||||
if (DEBUG):
|
||||
if DEBUG:
|
||||
print "#!!!", self.__dict__
|
||||
|
||||
try:
|
||||
@@ -1294,7 +1294,7 @@ class Extension(Complex):
|
||||
|
||||
self._extend(top, sup, argv, parent, base)
|
||||
|
||||
return (self._own, self._inherited)
|
||||
return self._own, self._inherited
|
||||
|
||||
class Choice(Complex):
|
||||
def collect(self, top, sup, argv=None, parent=""):
|
||||
@@ -1409,7 +1409,7 @@ class Group(Complex):
|
||||
raise Exception("Missing namespace definition")
|
||||
except AttributeError, exc:
|
||||
print "!!!!", exc
|
||||
return ([], [])
|
||||
return [], []
|
||||
|
||||
def repr(self, top=None, sup=None, argv=None, _child=True, parent=""):
|
||||
if self.py_class:
|
||||
@@ -1445,7 +1445,7 @@ class AttributeGroup(Complex):
|
||||
return cti.collect(top, sup)
|
||||
except AttributeError:
|
||||
if self._own or self._inherited:
|
||||
return (self._own, self._inherited)
|
||||
return self._own, self._inherited
|
||||
|
||||
argv_copy = sd_copy(argv)
|
||||
|
||||
@@ -1453,7 +1453,7 @@ class AttributeGroup(Complex):
|
||||
if isinstance(prop, Attribute):
|
||||
self._own.append(prop.repr(top, sup, argv_copy, parent))
|
||||
|
||||
return (self._own, self._inherited)
|
||||
return self._own, self._inherited
|
||||
|
||||
def repr(self, top=None, sup=None, _argv=None, _child=True, parent=""):
|
||||
if self.py_class:
|
||||
@@ -1482,7 +1482,7 @@ def pyify_0(name):
|
||||
|
||||
res = res.replace("-","_")
|
||||
if res in ["class"]:
|
||||
res = res+"_"
|
||||
res += "_"
|
||||
return res
|
||||
|
||||
def pyify(name):
|
||||
@@ -1557,7 +1557,7 @@ def sort_elements(els):
|
||||
partres.sort()
|
||||
res.extend(partres)
|
||||
|
||||
return (res, els)
|
||||
return res, els
|
||||
|
||||
def output(elem, target_namespace, eldict, ignore=[]):
|
||||
done = 0
|
||||
|
||||
Reference in New Issue
Block a user