More on clients
This commit is contained in:
@@ -20,6 +20,8 @@ to conclude its tasks.
|
||||
"""
|
||||
|
||||
import saml2
|
||||
from saml2.saml import AssertionIDRef
|
||||
|
||||
try:
|
||||
from urlparse import parse_qs
|
||||
except ImportError:
|
||||
@@ -32,11 +34,10 @@ from saml2.s_utils import decode_base64_and_inflate
|
||||
from saml2 import samlp, saml, class_name
|
||||
from saml2.sigver import pre_signature_part
|
||||
from saml2.sigver import signed_instance_factory
|
||||
from saml2.soap import SOAPClient
|
||||
from saml2.binding import send_using_soap, http_redirect_message
|
||||
from saml2.binding import send_using_soap
|
||||
from saml2.binding import http_redirect_message
|
||||
from saml2.binding import http_post_message
|
||||
from saml2.client_base import Base, LogoutError
|
||||
from saml2.response import attribute_response
|
||||
|
||||
from saml2 import BINDING_HTTP_REDIRECT
|
||||
from saml2 import BINDING_SOAP
|
||||
@@ -91,85 +92,6 @@ class Saml2Client(Base):
|
||||
|
||||
return session_id, response
|
||||
|
||||
|
||||
def do_attribute_query(self, subject_id, entityid,
|
||||
attribute=None, sp_name_qualifier=None,
|
||||
name_qualifier=None, nameid_format=None,
|
||||
real_id=None, consent=None, extensions=None,
|
||||
sign=False):
|
||||
""" Does a attribute request to an attribute authority, this is
|
||||
by default done over SOAP. Other bindings could be used but not
|
||||
supported right now.
|
||||
|
||||
:param subject_id: The identifier of the subject
|
||||
:param entityid: To whom the query should be sent
|
||||
:param attribute: A dictionary of attributes and values that is asked for
|
||||
:param sp_name_qualifier: The unique identifier of the
|
||||
service provider or affiliation of providers for whom the
|
||||
identifier was generated.
|
||||
:param name_qualifier: The unique identifier of the identity
|
||||
provider that generated the identifier.
|
||||
:param nameid_format: The format of the name ID
|
||||
:param real_id: The identifier which is the key to this entity in the
|
||||
identity database
|
||||
:return: The attributes returned
|
||||
"""
|
||||
|
||||
location = self._sso_location(entityid, BINDING_SOAP)
|
||||
|
||||
id, request = self.create_attribute_query(location, 0, subject_id,
|
||||
attribute, sp_name_qualifier,
|
||||
name_qualifier,
|
||||
nameid_format,
|
||||
consent, extensions, sign)
|
||||
|
||||
logger.info("Request, created: %s" % request)
|
||||
|
||||
soapclient = SOAPClient(location, self.config.key_file,
|
||||
self.config.cert_file,
|
||||
ca_certs=self.config.ca_certs)
|
||||
|
||||
logger.info("SOAP client initiated")
|
||||
|
||||
try:
|
||||
response = soapclient.send(request)
|
||||
except Exception, exc:
|
||||
logger.info("SoapClient exception: %s" % (exc,))
|
||||
return None
|
||||
|
||||
logger.info("SOAP request sent and got response: %s" % response)
|
||||
# fil = open("response.xml", "w")
|
||||
# fil.write(response)
|
||||
# fil.close()
|
||||
|
||||
if response:
|
||||
logger.info("Verifying response")
|
||||
|
||||
try:
|
||||
# synchronous operation
|
||||
aresp = attribute_response(self.config, self.config.entityid)
|
||||
except Exception, exc:
|
||||
logger.error("%s", (exc,))
|
||||
return None
|
||||
|
||||
_resp = aresp.loads(response, False, soapclient.response).verify()
|
||||
if _resp is None:
|
||||
logger.error("Didn't like the response")
|
||||
return None
|
||||
|
||||
session_info = _resp.session_info()
|
||||
|
||||
if session_info:
|
||||
if real_id is not None:
|
||||
session_info["name_id"] = real_id
|
||||
self.users.add_information_about_person(session_info)
|
||||
|
||||
logger.info("session: %s" % session_info)
|
||||
return session_info
|
||||
else:
|
||||
logger.info("No response")
|
||||
return None
|
||||
|
||||
def global_logout(self, subject_id, reason="", expire=None, sign=None,
|
||||
return_to="/"):
|
||||
""" More or less a layer of indirection :-/
|
||||
@@ -382,13 +304,43 @@ class Saml2Client(Base):
|
||||
if binding == BINDING_HTTP_REDIRECT:
|
||||
return self.do_http_redirect_logout(request, subject_id)
|
||||
|
||||
# MUST use SOAP for
|
||||
# AssertionIDRequest, SubjectQuery,
|
||||
# AuthnQuery, AttributeQuery, or AuthzDecisionQuery
|
||||
|
||||
def _soap_query_response(self, destination, query_type, **kwargs):
|
||||
_create_func = getattr(self, "create_%s" % query_type)
|
||||
_response_func = getattr(self, "%s_response" % query_type)
|
||||
|
||||
id, query = _create_func(destination, **kwargs)
|
||||
|
||||
response = send_using_soap(query, destination,
|
||||
self.config.key_file,
|
||||
self.config.cert_file,
|
||||
ca_certs=self.config.ca_certs)
|
||||
|
||||
if response:
|
||||
logger.info("Verifying response")
|
||||
if "response_args" in kwargs:
|
||||
response = _response_func(response, **kwargs["response_args"])
|
||||
else:
|
||||
response = _response_func(response)
|
||||
|
||||
if response:
|
||||
#not_done.remove(entity_id)
|
||||
logger.info("OK response from %s" % destination)
|
||||
return response
|
||||
else:
|
||||
logger.info("NOT OK response from %s" % destination)
|
||||
|
||||
return None
|
||||
|
||||
#noinspection PyUnusedLocal
|
||||
def do_authz_decision_query(self, entity_id, action,
|
||||
subject_id, nameid_format,
|
||||
evidence=None, resource=None,
|
||||
sp_name_qualifier=None,
|
||||
name_qualifier=None,
|
||||
binding=BINDING_SOAP,
|
||||
consent=None, extensions=None, sign=False):
|
||||
|
||||
subject = saml.Subject(
|
||||
@@ -398,31 +350,103 @@ class Saml2Client(Base):
|
||||
name_qualifier=name_qualifier))
|
||||
|
||||
for destination in self.config.authz_service_endpoints(entity_id,
|
||||
binding):
|
||||
id, query = self.create_authz_decision_query(destination,
|
||||
action, evidence,
|
||||
resource, subject)
|
||||
|
||||
response = send_using_soap(query, destination,
|
||||
self.config.key_file,
|
||||
self.config.cert_file,
|
||||
ca_certs=self.config.ca_certs)
|
||||
|
||||
if response:
|
||||
logger.info("Verifying response")
|
||||
response = self.authz_decision_query_response(response)
|
||||
|
||||
if response:
|
||||
#not_done.remove(entity_id)
|
||||
logger.info("OK response from %s" % destination)
|
||||
return response
|
||||
else:
|
||||
logger.info("NOT OK response from %s" % destination)
|
||||
BINDING_SOAP):
|
||||
resp = self._soap_query_response(destination,
|
||||
"authz_decision_query",
|
||||
action=action, evidence=evidence,
|
||||
resource=resource, subject=subject)
|
||||
if resp:
|
||||
return resp
|
||||
|
||||
return None
|
||||
|
||||
def do_assertion_id_request(self):
|
||||
pass
|
||||
def do_assertion_id_request(self, assertion_ids, entity_id,
|
||||
consent=None, extensions=None, sign=False):
|
||||
|
||||
def do_authn_query(self):
|
||||
pass
|
||||
destination = self.metadata.assertion_id_request_service(entity_id,
|
||||
BINDING_SOAP)[0]
|
||||
|
||||
if isinstance(assertion_ids, basestring):
|
||||
assertion_ids = [assertion_ids]
|
||||
|
||||
_id_refs = [AssertionIDRef(_id) for _id in assertion_ids]
|
||||
|
||||
return self._soap_query_response(destination, "assertion_id_request",
|
||||
assertion_id_refs=_id_refs,
|
||||
consent=consent, extensions=extensions,
|
||||
sign=sign)
|
||||
|
||||
|
||||
def do_authn_query(self, entity_id,
|
||||
consent=None, extensions=None, sign=False):
|
||||
|
||||
destination = self.metadata.authn_request_service(entity_id,
|
||||
BINDING_SOAP)[0]
|
||||
|
||||
return self._soap_query_response(destination, "authn_query",
|
||||
consent=consent, extensions=extensions,
|
||||
sign=sign)
|
||||
|
||||
def do_attribute_query(self, subject_id, entityid,
|
||||
attribute=None, sp_name_qualifier=None,
|
||||
name_qualifier=None, nameid_format=None,
|
||||
real_id=None, consent=None, extensions=None,
|
||||
sign=False):
|
||||
""" Does a attribute request to an attribute authority, this is
|
||||
by default done over SOAP. Other bindings could be used but not
|
||||
supported right now.
|
||||
|
||||
:param subject_id: The identifier of the subject
|
||||
:param entityid: To whom the query should be sent
|
||||
:param attribute: A dictionary of attributes and values that is asked for
|
||||
:param sp_name_qualifier: The unique identifier of the
|
||||
service provider or affiliation of providers for whom the
|
||||
identifier was generated.
|
||||
:param name_qualifier: The unique identifier of the identity
|
||||
provider that generated the identifier.
|
||||
:param nameid_format: The format of the name ID
|
||||
:param real_id: The identifier which is the key to this entity in the
|
||||
identity database
|
||||
:return: The attributes returned
|
||||
"""
|
||||
|
||||
location = self._sso_location(entityid, BINDING_SOAP)
|
||||
|
||||
response_args = {"real_id": real_id}
|
||||
|
||||
return self._soap_query_response(location, "attribute_query",
|
||||
consent=consent, extensions=extensions,
|
||||
sign=sign, subject_id=subject_id,
|
||||
attribute=attribute,
|
||||
sp_name_qualifier=sp_name_qualifier,
|
||||
name_qualifier=name_qualifier,
|
||||
nameid_format=nameid_format,
|
||||
response_args=response_args)
|
||||
|
||||
# if response:
|
||||
# logger.info("Verifying response")
|
||||
#
|
||||
# try:
|
||||
# # synchronous operation
|
||||
# aresp = attribute_response(self.config, self.config.entityid)
|
||||
# except Exception, exc:
|
||||
# logger.error("%s", (exc,))
|
||||
# return None
|
||||
#
|
||||
# _resp = aresp.loads(response, False, soapclient.response).verify()
|
||||
# if _resp is None:
|
||||
# logger.error("Didn't like the response")
|
||||
# return None
|
||||
#
|
||||
# session_info = _resp.session_info()
|
||||
#
|
||||
# if session_info:
|
||||
# if real_id is not None:
|
||||
# session_info["name_id"] = real_id
|
||||
# self.users.add_information_about_person(session_info)
|
||||
#
|
||||
# logger.info("session: %s" % session_info)
|
||||
# return session_info
|
||||
# else:
|
||||
# logger.info("No response")
|
||||
# return None
|
||||
|
@@ -48,7 +48,7 @@ from saml2.population import Population
|
||||
from saml2.virtual_org import VirtualOrg
|
||||
from saml2.config import config_factory
|
||||
|
||||
from saml2.response import response_factory
|
||||
from saml2.response import response_factory, attribute_response
|
||||
from saml2.response import LogoutResponse
|
||||
from saml2.response import AuthnResponse
|
||||
|
||||
@@ -415,7 +415,10 @@ class Base(object):
|
||||
in_response_to=request_id,
|
||||
status=status)
|
||||
|
||||
#noinspection PyUnusedLocal
|
||||
# MUST use SOAP for
|
||||
# AssertionIDRequest, SubjectQuery,
|
||||
# AuthnQuery, AttributeQuery, or AuthzDecisionQuery
|
||||
|
||||
def create_authz_decision_query(self, destination, action, id=0,
|
||||
evidence=None, resource=None, subject=None,
|
||||
sign=None, consent=None,
|
||||
@@ -469,14 +472,9 @@ class Base(object):
|
||||
resource, subject, binding,
|
||||
sign)
|
||||
|
||||
#noinspection PyUnusedLocal
|
||||
def authz_decision_query_response(self, response):
|
||||
""" Verify that the response is OK """
|
||||
pass
|
||||
|
||||
def create_assertion_id_request(self, assertion_id_refs, destination=None,
|
||||
id=0, consent=None, sign=False,
|
||||
extensions=None):
|
||||
id=0, consent=None, extensions=None,
|
||||
sign=False):
|
||||
|
||||
id_refs = [AssertionIDRef(text=s) for s in assertion_id_refs]
|
||||
|
||||
@@ -493,6 +491,7 @@ class Base(object):
|
||||
sign, subject=subject, session_index=session_index,
|
||||
requested_auth_context=authn_context)
|
||||
|
||||
|
||||
# ======== response handling ===========
|
||||
|
||||
def response(self, post, outstanding, decode=True, asynchop=True):
|
||||
@@ -587,3 +586,44 @@ class Base(object):
|
||||
|
||||
return response
|
||||
|
||||
#noinspection PyUnusedLocal
|
||||
def authz_decision_query_response(self, response):
|
||||
""" Verify that the response is OK
|
||||
"""
|
||||
resp = samlp.response_from_string(response)
|
||||
return resp
|
||||
|
||||
def assertion_id_request_response(self, response):
|
||||
""" Verify that the response is OK
|
||||
"""
|
||||
resp = samlp.response_from_string(response)
|
||||
return resp
|
||||
|
||||
def authn_query_response(self, response):
|
||||
""" Verify that the response is OK
|
||||
"""
|
||||
resp = samlp.response_from_string(response)
|
||||
return resp
|
||||
|
||||
def attribute_query_response(self, response, **kwargs):
|
||||
try:
|
||||
# synchronous operation
|
||||
aresp = attribute_response(self.config, self.config.entityid)
|
||||
except Exception, exc:
|
||||
logger.error("%s", (exc,))
|
||||
return None
|
||||
|
||||
_resp = aresp.loads(response, False, response).verify()
|
||||
if _resp is None:
|
||||
logger.error("Didn't like the response")
|
||||
return None
|
||||
|
||||
session_info = _resp.session_info()
|
||||
|
||||
if session_info:
|
||||
if "real_id" in kwargs:
|
||||
session_info["name_id"] = kwargs["real_id"]
|
||||
self.users.add_information_about_person(session_info)
|
||||
|
||||
logger.info("session: %s" % session_info)
|
||||
return session_info
|
||||
|
Reference in New Issue
Block a user