Improve support for SigAlg usage in HTTP redirect.

This commit is contained in:
Roland Hedberg
2015-06-27 09:09:48 +02:00
parent b7f618bde5
commit ed1bb3362d
5 changed files with 43 additions and 36 deletions

View File

@@ -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:

View File

@@ -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"],

View File

@@ -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 :-/
@@ -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)

View File

@@ -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

View File

@@ -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)