Improve support for SigAlg usage in HTTP redirect.
This commit is contained in:
@@ -544,7 +544,7 @@ class SSO(object):
|
|||||||
logger.info("Chosen IdP: '%s'" % idp_entity_id)
|
logger.info("Chosen IdP: '%s'" % idp_entity_id)
|
||||||
return 0, idp_entity_id
|
return 0, idp_entity_id
|
||||||
|
|
||||||
def redirect_to_auth(self, _cli, entity_id, came_from):
|
def redirect_to_auth(self, _cli, entity_id, came_from, sigalg=""):
|
||||||
try:
|
try:
|
||||||
# Picks a binding to use for sending the Request to the IDP
|
# Picks a binding to use for sending the Request to the IDP
|
||||||
_binding, destination = _cli.pick_binding(
|
_binding, destination = _cli.pick_binding(
|
||||||
@@ -573,11 +573,13 @@ class SSO(object):
|
|||||||
element_to_extension_element(spcertenc)])
|
element_to_extension_element(spcertenc)])
|
||||||
|
|
||||||
req_id, req = _cli.create_authn_request(destination,
|
req_id, req = _cli.create_authn_request(destination,
|
||||||
binding=return_binding, extensions=extensions)
|
binding=return_binding,
|
||||||
|
extensions=extensions)
|
||||||
_rstate = rndstr()
|
_rstate = rndstr()
|
||||||
self.cache.relay_state[_rstate] = came_from
|
self.cache.relay_state[_rstate] = came_from
|
||||||
ht_args = _cli.apply_binding(_binding, "%s" % req, destination,
|
ht_args = _cli.apply_binding(_binding, "%s" % req, destination,
|
||||||
relay_state=_rstate)
|
relay_state=_rstate,
|
||||||
|
sigalg=sigalg)
|
||||||
_sid = req_id
|
_sid = req_id
|
||||||
|
|
||||||
if cert is not None:
|
if cert is not None:
|
||||||
|
4
setup.py
4
setup.py
@@ -66,7 +66,9 @@ setup(
|
|||||||
"Development Status :: 4 - Beta",
|
"Development Status :: 4 - Beta",
|
||||||
"License :: OSI Approved :: Apache Software License",
|
"License :: OSI Approved :: Apache Software License",
|
||||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||||
"Programming Language :: Python :: 2.7"],
|
"Programming Language :: Python :: 2.7",
|
||||||
|
"Programming Language :: Python :: 3.4"
|
||||||
|
],
|
||||||
|
|
||||||
scripts=["tools/parse_xsd2.py", "tools/make_metadata.py",
|
scripts=["tools/parse_xsd2.py", "tools/make_metadata.py",
|
||||||
"tools/mdexport.py", "tools/merge_metadata.py"],
|
"tools/mdexport.py", "tools/merge_metadata.py"],
|
||||||
|
@@ -24,15 +24,15 @@ from saml2.samlp import STATUS_UNKNOWN_PRINCIPAL
|
|||||||
from saml2.time_util import not_on_or_after
|
from saml2.time_util import not_on_or_after
|
||||||
from saml2.saml import AssertionIDRef
|
from saml2.saml import AssertionIDRef
|
||||||
from saml2.client_base import Base
|
from saml2.client_base import Base
|
||||||
|
from saml2.client_base import SignOnError
|
||||||
from saml2.client_base import LogoutError
|
from saml2.client_base import LogoutError
|
||||||
from saml2.client_base import NoServiceDefined
|
from saml2.client_base import NoServiceDefined
|
||||||
from saml2.mdstore import destinations
|
from saml2.mdstore import destinations
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from urlparse import parse_qs
|
from urllib.parse import parse_qs
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# Compatibility with Python <= 2.5
|
from urlparse import parse_qs
|
||||||
from cgi import parse_qs
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@@ -42,13 +42,11 @@ logger = logging.getLogger(__name__)
|
|||||||
class Saml2Client(Base):
|
class Saml2Client(Base):
|
||||||
""" The basic pySAML2 service provider class """
|
""" The basic pySAML2 service provider class """
|
||||||
|
|
||||||
def prepare_for_authenticate(self, entityid=None, relay_state="",
|
def prepare_for_authenticate(
|
||||||
binding=saml2.BINDING_HTTP_REDIRECT, vorg="",
|
self, entityid=None, relay_state="",
|
||||||
nameid_format=None,
|
binding=saml2.BINDING_HTTP_REDIRECT, vorg="", nameid_format=None,
|
||||||
scoping=None, consent=None, extensions=None,
|
scoping=None, consent=None, extensions=None, sign=None,
|
||||||
sign=None,
|
response_binding=saml2.BINDING_HTTP_POST, **kwargs):
|
||||||
response_binding=saml2.BINDING_HTTP_POST,
|
|
||||||
**kwargs):
|
|
||||||
""" Makes all necessary preparations for an authentication request.
|
""" Makes all necessary preparations for an authentication request.
|
||||||
|
|
||||||
:param entityid: The entity ID of the IdP to send the request to
|
:param entityid: The entity ID of the IdP to send the request to
|
||||||
@@ -82,14 +80,12 @@ class Saml2Client(Base):
|
|||||||
|
|
||||||
return reqid, info
|
return reqid, info
|
||||||
|
|
||||||
def prepare_for_negotiated_authenticate(self, entityid=None, relay_state="",
|
def prepare_for_negotiated_authenticate(
|
||||||
binding=None, vorg="",
|
self, entityid=None, relay_state="", binding=None, vorg="",
|
||||||
nameid_format=None,
|
nameid_format=None, scoping=None, consent=None, extensions=None,
|
||||||
scoping=None, consent=None, extensions=None,
|
sign=None, response_binding=saml2.BINDING_HTTP_POST, **kwargs):
|
||||||
sign=None,
|
""" Makes all necessary preparations for an authentication request
|
||||||
response_binding=saml2.BINDING_HTTP_POST,
|
that negotiates
|
||||||
**kwargs):
|
|
||||||
""" Makes all necessary preparations for an authentication request that negotiates
|
|
||||||
which binding to use for authentication.
|
which binding to use for authentication.
|
||||||
|
|
||||||
:param entityid: The entity ID of the IdP to send the request to
|
:param entityid: The entity ID of the IdP to send the request to
|
||||||
@@ -117,20 +113,25 @@ class Saml2Client(Base):
|
|||||||
|
|
||||||
reqid, request = self.create_authn_request(
|
reqid, request = self.create_authn_request(
|
||||||
destination, vorg, scoping, response_binding, nameid_format,
|
destination, vorg, scoping, response_binding, nameid_format,
|
||||||
consent=consent,
|
consent=consent, extensions=extensions, sign=sign,
|
||||||
extensions=extensions, sign=sign,
|
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
_req_str = str(request)
|
_req_str = str(request)
|
||||||
|
|
||||||
logger.info("AuthNReq: %s" % _req_str)
|
logger.info("AuthNReq: %s" % _req_str)
|
||||||
|
|
||||||
|
try:
|
||||||
|
sigalg = kwargs["sigalg"]
|
||||||
|
except KeyError:
|
||||||
|
sigalg = ""
|
||||||
|
|
||||||
http_info = self.apply_binding(binding, _req_str, destination,
|
http_info = self.apply_binding(binding, _req_str, destination,
|
||||||
relay_state)
|
relay_state, sigalg=sigalg)
|
||||||
|
|
||||||
return reqid, binding, http_info
|
return reqid, binding, http_info
|
||||||
else:
|
else:
|
||||||
raise SignOnError("No supported bindings available for authentication")
|
raise SignOnError(
|
||||||
|
"No supported bindings available for authentication")
|
||||||
|
|
||||||
def global_logout(self, name_id, reason="", expire=None, sign=None):
|
def global_logout(self, name_id, reason="", expire=None, sign=None):
|
||||||
""" More or less a layer of indirection :-/
|
""" More or less a layer of indirection :-/
|
||||||
@@ -206,7 +207,7 @@ class Saml2Client(Base):
|
|||||||
destination, entity_id, name_id=name_id, reason=reason,
|
destination, entity_id, name_id=name_id, reason=reason,
|
||||||
expire=expire)
|
expire=expire)
|
||||||
|
|
||||||
#to_sign = []
|
# to_sign = []
|
||||||
if binding.startswith("http://"):
|
if binding.startswith("http://"):
|
||||||
sign = True
|
sign = True
|
||||||
|
|
||||||
@@ -230,7 +231,8 @@ class Saml2Client(Base):
|
|||||||
not_done.remove(entity_id)
|
not_done.remove(entity_id)
|
||||||
response = response.text
|
response = response.text
|
||||||
logger.info("Response: %s" % response)
|
logger.info("Response: %s" % response)
|
||||||
res = self.parse_logout_request_response(response, binding)
|
res = self.parse_logout_request_response(response,
|
||||||
|
binding)
|
||||||
responses[entity_id] = res
|
responses[entity_id] = res
|
||||||
else:
|
else:
|
||||||
logger.info("NOT OK response from %s" % destination)
|
logger.info("NOT OK response from %s" % destination)
|
||||||
@@ -324,7 +326,7 @@ class Saml2Client(Base):
|
|||||||
raise HTTPError("%d:%s" % (response.status_code, response.error))
|
raise HTTPError("%d:%s" % (response.status_code, response.error))
|
||||||
|
|
||||||
if response:
|
if response:
|
||||||
#not_done.remove(entity_id)
|
# not_done.remove(entity_id)
|
||||||
logger.info("OK response from %s" % destination)
|
logger.info("OK response from %s" % destination)
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
@@ -332,7 +334,7 @@ class Saml2Client(Base):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
#noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
def do_authz_decision_query(self, entity_id, action,
|
def do_authz_decision_query(self, entity_id, action,
|
||||||
subject_id, nameid_format,
|
subject_id, nameid_format,
|
||||||
evidence=None, resource=None,
|
evidence=None, resource=None,
|
||||||
|
@@ -3,7 +3,6 @@ import six
|
|||||||
from six.moves import http_cookiejar
|
from six.moves import http_cookiejar
|
||||||
import copy
|
import copy
|
||||||
import re
|
import re
|
||||||
import urllib
|
|
||||||
from six.moves.urllib.parse import urlparse
|
from six.moves.urllib.parse import urlparse
|
||||||
from six.moves.urllib.parse import urlencode
|
from six.moves.urllib.parse import urlencode
|
||||||
import requests
|
import requests
|
||||||
@@ -311,7 +310,8 @@ class HTTPBase(object):
|
|||||||
|
|
||||||
return info
|
return info
|
||||||
|
|
||||||
def use_soap(self, request, destination="", soap_headers=None, sign=False):
|
def use_soap(self, request, destination="", soap_headers=None, sign=False,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Construct the necessary information for using SOAP+POST
|
Construct the necessary information for using SOAP+POST
|
||||||
|
|
||||||
|
@@ -45,7 +45,7 @@ FORM_SPEC = """<form method="post" action="%s">
|
|||||||
|
|
||||||
|
|
||||||
def http_form_post_message(message, location, relay_state="",
|
def http_form_post_message(message, location, relay_state="",
|
||||||
typ="SAMLRequest"):
|
typ="SAMLRequest", **kwargs):
|
||||||
"""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
|
messages may be transmitted within the base64-encoded content of a
|
||||||
HTML form control.
|
HTML form control.
|
||||||
@@ -80,7 +80,7 @@ def http_form_post_message(message, location, relay_state="",
|
|||||||
|
|
||||||
|
|
||||||
def http_redirect_message(message, location, relay_state="", typ="SAMLRequest",
|
def http_redirect_message(message, location, relay_state="", typ="SAMLRequest",
|
||||||
sigalg=None, key=None):
|
sigalg=None, key=None, **kwargs):
|
||||||
"""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 can be transmitted within URL parameters.
|
||||||
Messages are encoded for use with this binding using a URL encoding
|
Messages are encoded for use with this binding using a URL encoding
|
||||||
@@ -256,5 +256,6 @@ def packager(identifier):
|
|||||||
raise Exception("Unknown binding type: %s" % identifier)
|
raise Exception("Unknown binding type: %s" % identifier)
|
||||||
|
|
||||||
|
|
||||||
def factory(binding, message, location, relay_state="", typ="SAMLRequest"):
|
def factory(binding, message, location, relay_state="", typ="SAMLRequest",
|
||||||
return PACKING[binding](message, location, relay_state, typ)
|
**kwargs):
|
||||||
|
return PACKING[binding](message, location, relay_state, typ, **kwargs)
|
||||||
|
Reference in New Issue
Block a user