--- /dev/null
+Description: Using correct urllib.parse
+ Make it work with Python 3.
+Author: Thomas Goirand <zigo@debian.org>
+Forwarded: no
+Last-Update: 2015-04-24
+
+--- python-pysaml2-2.0.0.orig/example/idp2/idp.py
++++ python-pysaml2-2.0.0/example/idp2/idp.py
+@@ -1,5 +1,4 @@
+ #!/usr/bin/env python
+-import argparse
+ import base64
+ import xmldsig as ds
+ import re
+@@ -7,7 +6,8 @@ import logging
+ import time
+ from hashlib import sha1
+
+-from urlparse import parse_qs
++import urllib
++import urllib.parse
+ from Cookie import SimpleCookie
+ import os
+
+@@ -90,12 +90,12 @@ class Service(object):
+ def unpack_redirect(self):
+ if "QUERY_STRING" in self.environ:
+ _qs = self.environ["QUERY_STRING"]
+- return dict([(k, v[0]) for k, v in parse_qs(_qs).items()])
++ return dict([(k, v[0]) for k, v in urllib.parse.parse_qs(_qs).items()])
+ else:
+ return None
+
+ def unpack_post(self):
+- _dict = parse_qs(get_post(self.environ))
++ _dict = urllib.parse.parse_qs(get_post(self.environ))
+ logger.debug("unpack_post:: %s" % _dict)
+ try:
+ return dict([(k, v[0]) for k, v in _dict.items()])
+@@ -193,7 +193,7 @@ class Service(object):
+ # :return:
+ # """
+ # loc = "http://%s/login" % (self.environ["HTTP_HOST"])
+- # loc += "?%s" % urllib.urlencode({"came_from": self.environ[
++ # loc += "?%s" % urllib.parse.urlencode({"came_from": self.environ[
+ # "PATH_INFO"], "key": key})
+ # headers = [('Content-Type', 'text/plain')]
+ #
+@@ -490,7 +490,7 @@ def verify_username_and_password(dic):
+
+
+ def do_verify(environ, start_response, _):
+- query = parse_qs(get_post(environ))
++ query = urllib.parse.parse_qs(get_post(environ))
+
+ logger.debug("do_verify: %s" % query)
+
+@@ -893,7 +893,7 @@ def application(environ, start_response)
+ environ["idp.authn_ref"] = authn_ref
+ else:
+ try:
+- query = parse_qs(environ["QUERY_STRING"])
++ query = urllib.parse.parse_qs(environ["QUERY_STRING"])
+ logger.debug("QUERY: %s" % query)
+ user = IDP.cache.uid2user[query["id"][0]]
+ except KeyError:
+--- python-pysaml2-2.0.0.orig/example/idp2_repoze/idp.py
++++ python-pysaml2-2.0.0/example/idp2_repoze/idp.py
+@@ -1,5 +1,4 @@
+ #!/usr/bin/env python
+-import argparse
+ import base64
+
+ import re
+@@ -7,7 +6,7 @@ import logging
+ import time
+ from hashlib import sha1
+
+-from urlparse import parse_qs
++from urllib.parse import parse_qs
+ from Cookie import SimpleCookie
+ import os
+
+@@ -191,7 +190,7 @@ class Service(object):
+ # :return:
+ # """
+ # loc = "http://%s/login" % (self.environ["HTTP_HOST"])
+- # loc += "?%s" % urllib.urlencode({"came_from": self.environ[
++ # loc += "?%s" % urllib.parse.urlencode({"came_from": self.environ[
+ # "PATH_INFO"], "key": key})
+ # headers = [('Content-Type', 'text/plain')]
+ #
+--- python-pysaml2-2.0.0.orig/example/sp-repoze/sp.py
++++ python-pysaml2-2.0.0/example/sp-repoze/sp.py
+@@ -6,8 +6,8 @@ import os
+ from sp_conf import CONFIG
+ import re
+ import subprocess
+-from urlparse import parse_qs
+-import argparse
++import urllib
++import urllib.parse
+ from saml2 import BINDING_HTTP_REDIRECT, time_util
+ from saml2.httputil import Response
+ from saml2.httputil import Unauthorized
+@@ -127,7 +127,7 @@ def slo(environ, start_response, user):
+ sc = client.saml_client
+
+ if "QUERY_STRING" in environ:
+- query = parse_qs(environ["QUERY_STRING"])
++ query = urllib.parse.parse_qs(environ["QUERY_STRING"])
+ logger.info("query: %s" % query)
+ try:
+ response = sc.parse_logout_request_response(
+--- python-pysaml2-2.0.0.orig/example/sp-wsgi/sp.py
++++ python-pysaml2-2.0.0/example/sp-wsgi/sp.py
+@@ -1,11 +1,10 @@
+ #!/usr/bin/env python
+ import logging
+ import re
+-import argparse
+ import service_conf
+
+ from Cookie import SimpleCookie
+-from urlparse import parse_qs
++from urllib.parse import parse_qs
+ import sys
+
+ from saml2 import BINDING_HTTP_REDIRECT
+--- python-pysaml2-2.0.0.orig/src/s2repoze/plugins/formswithhidden.py
++++ python-pysaml2-2.0.0/src/s2repoze/plugins/formswithhidden.py
+@@ -69,7 +69,7 @@ class FormHiddenPlugin(FormPlugin):
+ return None
+ del query[self.login_form_qs]
+ query.update(qinfo)
+- environ['QUERY_STRING'] = urllib.urlencode(query)
++ environ['QUERY_STRING'] = urllib.parse.urlencode(query)
+ environ['repoze.who.application'] = HTTPFound(
+ construct_url(environ))
+ credentials = {'login':login, 'password':password}
+--- python-pysaml2-2.0.0.orig/src/s2repoze/plugins/sp.py
++++ python-pysaml2-2.0.0/src/s2repoze/plugins/sp.py
+@@ -25,7 +25,8 @@ import platform
+ import shelve
+ import traceback
+ import saml2
+-from urlparse import parse_qs, urlparse
++import urllib
++import urllib.parse
+ from saml2.md import Extensions
+ import xmldsig as ds
+
+@@ -137,7 +138,7 @@ class SAML2Plugin(object):
+ self.cache = cache
+ self.discosrv = discovery
+ self.idp_query_param = idp_query_param
+- self.logout_endpoints = [urlparse(ep)[2] for ep in config.endpoint(
++ self.logout_endpoints = [urllib.parse.urlparse(ep)[2] for ep in config.endpoint(
+ "single_logout_service")]
+ try:
+ self.metadata = self.conf.metadata
+@@ -252,7 +253,7 @@ class SAML2Plugin(object):
+ query = environ.get(key)
+ if query:
+ try:
+- _idp_entity_id = dict(parse_qs(query))[
++ _idp_entity_id = dict(urllib.parse.parse_qs(query))[
+ self.idp_query_param][0]
+ if _idp_entity_id in idps:
+ idp_entity_id = _idp_entity_id
+@@ -274,7 +275,7 @@ class SAML2Plugin(object):
+ if self.wayf:
+ if query:
+ try:
+- wayf_selected = dict(parse_qs(query))[
++ wayf_selected = dict(urllib.parse.parse_qs(query))[
+ "wayf_selected"][0]
+ except KeyError:
+ return self._wayf_redirect(came_from)
+@@ -410,7 +411,7 @@ class SAML2Plugin(object):
+ "endpoints","sp")["discovery_response"][0][0]
+ if (environ["PATH_INFO"]) in ret and ret.split(
+ environ["PATH_INFO"])[1] == "":
+- query = parse_qs(environ["QUERY_STRING"])
++ query = urllib.parse.parse_qs(environ["QUERY_STRING"])
+ sid = query["sid"][0]
+ came_from = self.outstanding_queries[sid]
+ except:
+--- python-pysaml2-2.0.0.orig/src/saml2/authn.py
++++ python-pysaml2-2.0.0/src/saml2/authn.py
+@@ -1,7 +1,6 @@
+ import logging
+-from urllib import urlencode
+-from urlparse import parse_qs
+-from urlparse import urlsplit
++import urllib
++import urllib.parse
+ import time
+ import ldap
+ from saml2 import SAMLError
+@@ -48,7 +47,7 @@ def url_encode_params(params=None):
+ params_list.extend([(k, x) for x in v])
+ else:
+ params_list.append((k, v))
+- return urlencode(params_list)
++ return urllib.parse.urlencode(params_list)
+
+
+ def create_return_url(base, query, **kwargs):
+@@ -61,11 +60,11 @@ def create_return_url(base, query, **kwa
+ :param kwargs: extra query parameters
+ :return:
+ """
+- part = urlsplit(base)
++ part = urllib.parse.urlsplit(base)
+ if part.fragment:
+ raise ValueError("Base URL contained parts it shouldn't")
+
+- for key, values in parse_qs(query).items():
++ for key, values in urllib.parse.parse_qs(query).items():
+ if key in kwargs:
+ if isinstance(kwargs[key], basestring):
+ kwargs[key] = [kwargs[key]]
+@@ -74,7 +73,7 @@ def create_return_url(base, query, **kwa
+ kwargs[key] = values
+
+ if part.query:
+- for key, values in parse_qs(part.query).items():
++ for key, values in urllib.parse.parse_qs(part.query).items():
+ if key in kwargs:
+ if isinstance(kwargs[key], basestring):
+ kwargs[key] = [kwargs[key]]
+@@ -151,7 +150,7 @@ class UsernamePasswordMako(UserAuthnMeth
+
+ logger.debug("verify(%s)" % request)
+ if isinstance(request, basestring):
+- _dict = parse_qs(request)
++ _dict = urllib.parse.parse_qs(request)
+ elif isinstance(request, dict):
+ _dict = request
+ else:
+--- python-pysaml2-2.0.0.orig/src/saml2/client.py
++++ python-pysaml2-2.0.0/src/saml2/client.py
+@@ -42,7 +42,7 @@ from saml2.client_base import NoServiceD
+ from saml2.mdstore import destinations
+
+ try:
+- from urlparse import parse_qs
++ from urllib.parse import parse_qs
+ except ImportError:
+ # Compatibility with Python <= 2.5
+ from cgi import parse_qs
+--- python-pysaml2-2.0.0.orig/src/saml2/client_base.py
++++ python-pysaml2-2.0.0/src/saml2/client_base.py
+@@ -19,8 +19,6 @@
+ to conclude its tasks.
+ """
+ import threading
+-from urllib import urlencode
+-from urlparse import urlparse
+
+ from saml2.entity import Entity
+
+@@ -37,7 +35,8 @@ import saml2
+ import time
+ from saml2.soap import make_soap_enveloped_saml_thingy
+
+-from urlparse import parse_qs
++import urllib
++import urllib.parse
+
+ from saml2.s_utils import signature, UnravelError
+ from saml2.s_utils import do_attributes
+@@ -756,7 +755,7 @@ class Base(Entity):
+ else:
+ args["isPassive"] = "false"
+
+- params = urlencode(args)
++ params = urllib.parse.urlencode(args)
+ return "%s?%s" % (url, params)
+
+ @staticmethod
+@@ -773,10 +772,10 @@ class Base(Entity):
+ """
+
+ if url:
+- part = urlparse(url)
+- qsd = parse_qs(part[4])
++ part = urllib.parse.urlparse(url)
++ qsd = urllib.parse.parse_qs(part[4])
+ elif query:
+- qsd = parse_qs(query)
++ qsd = urllib.parse.parse_qs(query)
+ else:
+ qsd = {}
+
+--- python-pysaml2-2.0.0.orig/src/saml2/discovery.py
++++ python-pysaml2-2.0.0/src/saml2/discovery.py
+@@ -1,5 +1,5 @@
+-from urllib import urlencode
+-from urlparse import urlparse, parse_qs
++import urllib
++import urllib.parse
+ from saml2.entity import Entity
+ from saml2.response import VerificationError
+
+@@ -14,10 +14,10 @@ class DiscoveryServer(Entity):
+
+ def parse_discovery_service_request(self, url="", query=""):
+ if url:
+- part = urlparse(url)
+- dsr = parse_qs(part[4])
++ part = urllib.parse.urlparse(url)
++ dsr = urllib.parse.parse_qs(part[4])
+ elif query:
+- dsr = parse_qs(query)
++ dsr = urllib.parse.parse_qs(query)
+ else:
+ dsr = {}
+
+@@ -31,9 +31,9 @@ class DiscoveryServer(Entity):
+ pass
+
+ if "return" in dsr:
+- part = urlparse(dsr["return"])
++ part = urllib.parse.urlparse(dsr["return"])
+ if part.query:
+- qp = parse_qs(part.query)
++ qp = urllib.parse.parse_qs(part.query)
+ if "returnIDParam" in dsr:
+ assert dsr["returnIDParam"] not in qp.keys()
+ else:
+@@ -69,9 +69,9 @@ class DiscoveryServer(Entity):
+ return_url = kwargs["return"]
+
+ if entity_id:
+- qp = urlencode({returnIDParam: entity_id})
++ qp = urllib.parse.urlencode({returnIDParam: entity_id})
+
+- part = urlparse(return_url)
++ part = urllib.parse.urlparse(return_url)
+ if part.query:
+ # Iff there is a query part add the new info at the end
+ return_url = "%s&%s" % (return_url, qp)
+--- python-pysaml2-2.0.0.orig/src/saml2/httpbase.py
++++ python-pysaml2-2.0.0/src/saml2/httpbase.py
+@@ -3,7 +3,7 @@ import cookielib
+ import copy
+ import re
+ import urllib
+-import urlparse
++import urllib.parse as urlparse
+ import requests
+ import time
+ from Cookie import SimpleCookie
+@@ -109,7 +109,7 @@ class HTTPBase(object):
+ :param url:
+ :return:
+ """
+- part = urlparse.urlparse(url)
++ part = urllib.parse.urlparse(url)
+
+ #if part.port:
+ # _domain = "%s:%s" % (part.hostname, part.port)
+@@ -139,7 +139,7 @@ class HTTPBase(object):
+ if not kaka:
+ return
+
+- part = urlparse.urlparse(request.url)
++ part = urllib.parse.urlparse(request.url)
+ _domain = part.hostname
+ logger.debug("%s: '%s'" % (_domain, kaka))
+
+@@ -274,10 +274,10 @@ class HTTPBase(object):
+
+ def use_http_artifact(self, message, destination="", relay_state=""):
+ if relay_state:
+- query = urllib.urlencode({"SAMLart": message,
++ query = urllib.parse.urlencode({"SAMLart": message,
+ "RelayState": relay_state})
+ else:
+- query = urllib.urlencode({"SAMLart": message})
++ query = urllib.parse.urlencode({"SAMLart": message})
+ info = {
+ "data": "",
+ "url": "%s?%s" % (destination, query)
+@@ -297,10 +297,10 @@ class HTTPBase(object):
+ elif typ == "SAMLRequest":
+ # msg should be an identifier
+ if relay_state:
+- query = urllib.urlencode({"ID": message,
++ query = urllib.parse.urlencode({"ID": message,
+ "RelayState": relay_state})
+ else:
+- query = urllib.urlencode({"ID": message})
++ query = urllib.parse.urlencode({"ID": message})
+ info = {
+ "data": "",
+ "url": "%s?%s" % (destination, query)
+--- python-pysaml2-2.0.0.orig/src/saml2/httputil.py
++++ python-pysaml2-2.0.0/src/saml2/httputil.py
+@@ -4,8 +4,8 @@ import logging
+ import time
+ import cgi
+
+-from urllib import quote
+-from urlparse import parse_qs
++import urllib
++import urllib.parse
+ from Cookie import SimpleCookie
+
+ from saml2 import BINDING_HTTP_ARTIFACT, SAMLError
+@@ -188,8 +188,8 @@ def geturl(environ, query=True, path=Tru
+
+ def getpath(environ):
+ """Builds a path."""
+- return ''.join([quote(environ.get('SCRIPT_NAME', '')),
+- quote(environ.get('PATH_INFO', ''))])
++ return ''.join([urllib.parse.quote(environ.get('SCRIPT_NAME', '')),
++ urllib.parse.quote(environ.get('PATH_INFO', ''))])
+
+
+ def get_post(environ):
+@@ -220,14 +220,14 @@ def get_response(environ, start_response
+ def unpack_redirect(environ):
+ if "QUERY_STRING" in environ:
+ _qs = environ["QUERY_STRING"]
+- return dict([(k, v[0]) for k, v in parse_qs(_qs).items()])
++ return dict([(k, v[0]) for k, v in urllib.parse.parse_qs(_qs).items()])
+ else:
+ return None
+
+
+ def unpack_post(environ):
+ try:
+- return dict([(k, v[0]) for k, v in parse_qs(get_post(environ))])
++ return dict([(k, v[0]) for k, v in urllib.parse.parse_qs(get_post(environ))])
+ except Exception:
+ return None
+
+--- python-pysaml2-2.0.0.orig/src/saml2/ident.py
++++ python-pysaml2-2.0.0/src/saml2/ident.py
+@@ -3,8 +3,8 @@ import shelve
+ import logging
+
+ from hashlib import sha256
+-from urllib import quote
+-from urllib import unquote
++import urllib
++import urllib.parse
+ from saml2 import SAMLError
+ from saml2.s_utils import rndstr
+ from saml2.s_utils import PolicyError
+@@ -31,7 +31,7 @@ def code(item):
+ for attr in ATTR:
+ val = getattr(item, attr)
+ if val:
+- _res.append("%d=%s" % (i, quote(val)))
++ _res.append("%d=%s" % (i, urllib.parse.quote(val)))
+ i += 1
+ return ",".join(_res)
+
+@@ -40,7 +40,7 @@ def decode(txt):
+ _nid = NameID()
+ for part in txt.split(","):
+ i, val = part.split("=")
+- setattr(_nid, ATTR[int(i)], unquote(val))
++ setattr(_nid, ATTR[int(i)], urllib.parse.unquote(val))
+ return _nid
+
+
+--- python-pysaml2-2.0.0.orig/src/saml2/pack.py
++++ python-pysaml2-2.0.0/src/saml2/pack.py
+@@ -23,7 +23,8 @@ Bindings normally consists of three part
+ - how to package the information
+ - which protocol to use
+ """
+-import urlparse
++import urllib
++import urllib.parse
+ import saml2
+ import base64
+ import urllib
+@@ -136,13 +137,13 @@ def http_redirect_message(message, locat
+ except:
+ raise Unsupported("Signing algorithm")
+ else:
+- string = "&".join([urllib.urlencode({k: args[k]}) for k in _order if k in args])
++ string = "&".join([urllib.parse.urlencode({k: args[k]}) for k in _order if k in args])
+ args["Signature"] = base64.b64encode(signer.sign(string, key))
+- string = urllib.urlencode(args)
++ string = urllib.parse.urlencode(args)
+ else:
+- string = urllib.urlencode(args)
++ string = urllib.parse.urlencode(args)
+
+- glue_char = "&" if urlparse.urlparse(location).query else "?"
++ glue_char = "&" if urllib.parse.urlparse(location).query else "?"
+ login_url = glue_char.join([location, string])
+ headers = [('Location', str(login_url))]
+ body = []
+--- python-pysaml2-2.0.0.orig/src/saml2/sigver.py
++++ python-pysaml2-2.0.0/src/saml2/sigver.py
+@@ -630,7 +630,7 @@ def verify_redirect_signature(info, cert
+ args = info.copy()
+ del args["Signature"] # everything but the signature
+ string = "&".join(
+- [urllib.urlencode({k: args[k][0]}) for k in _order])
++ [urllib.parse.urlencode({k: args[k][0]}) for k in _order])
+ _key = extract_rsa_key_from_x509_cert(pem_format(cert))
+ _sign = base64.b64decode(info["Signature"][0])
+ try:
+--- python-pysaml2-2.0.0.orig/src/saml2/validate.py
++++ python-pysaml2-2.0.0/src/saml2/validate.py
+@@ -1,5 +1,5 @@
+ import calendar
+-import urlparse
++import urllib.parse
+ import re
+ import time_util
+ import struct
+@@ -46,7 +46,7 @@ def valid_id(oid):
+ def valid_any_uri(item):
+ """very simplistic, ..."""
+ try:
+- part = urlparse.urlparse(item)
++ part = urllib.parse.urlparse(item)
+ except Exception:
+ raise NotValid("AnyURI")
+
+@@ -68,7 +68,7 @@ def valid_date_time(item):
+
+ def valid_url(url):
+ try:
+- _ = urlparse.urlparse(url)
++ _ = urllib.parse.urlparse(url)
+ except Exception:
+ raise NotValid("URL")
+
+--- python-pysaml2-2.0.0.orig/tests/fakeIDP.py
++++ python-pysaml2-2.0.0/tests/fakeIDP.py
+@@ -1,4 +1,5 @@
+-from urlparse import parse_qs
++import urllib
++import urllib.parse
+ from saml2.authn_context import INTERNETPROTOCOLPASSWORD
+ from saml2.samlp import attribute_query_from_string, logout_request_from_string
+ from saml2 import BINDING_HTTP_REDIRECT, pack
+@@ -66,14 +67,14 @@ class FakeIDP(Server):
+
+ if method == "GET":
+ path, query = url.split("?")
+- qs_dict = parse_qs(kwargs["data"])
++ qs_dict = urllib.parse.parse_qs(kwargs["data"])
+ req = qs_dict["SAMLRequest"][0]
+ rstate = qs_dict["RelayState"][0]
+ else:
+ # Could be either POST or SOAP
+ path = url
+ try:
+- qs_dict = parse_qs(kwargs["data"])
++ qs_dict = urllib.parse.parse_qs(kwargs["data"])
+ req = qs_dict["SAMLRequest"][0]
+ rstate = qs_dict["RelayState"][0]
+ except KeyError:
+--- python-pysaml2-2.0.0.orig/tests/test_50_server.py
++++ python-pysaml2-2.0.0/tests/test_50_server.py
+@@ -1,7 +1,8 @@
+ #!/usr/bin/env python
+ # -*- coding: utf-8 -*-
+ import base64
+-from urlparse import parse_qs
++import urllib
++import urllib.parse
+ from saml2.assertion import Policy
+ from saml2.authn_context import INTERNETPROTOCOLPASSWORD
+ from saml2.saml import NameID, NAMEID_FORMAT_TRANSIENT
+@@ -131,7 +132,7 @@ class TestServer1():
+ binding = BINDING_HTTP_REDIRECT
+ htargs = self.client.apply_binding(
+ binding, "%s" % authn_request, "http://www.example.com", "abcd")
+- _dict = parse_qs(htargs["headers"][0][1].split('?')[1])
++ _dict = urllib.parse.parse_qs(htargs["headers"][0][1].split('?')[1])
+ print(_dict)
+ raises(OtherError, self.server.parse_authn_request,
+ _dict["SAMLRequest"][0], binding)
+@@ -143,7 +144,7 @@ class TestServer1():
+ binding = BINDING_HTTP_REDIRECT
+ htargs = self.client.apply_binding(binding, "%s" % authn_request,
+ "http://www.example.com", "abcd")
+- _dict = parse_qs(htargs["headers"][0][1].split('?')[1])
++ _dict = urllib.parse.parse_qs(htargs["headers"][0][1].split('?')[1])
+ print(_dict)
+
+ try:
+@@ -170,7 +171,7 @@ class TestServer1():
+ binding = BINDING_HTTP_REDIRECT
+ htargs = self.client.apply_binding(binding, "%s" % authn_request,
+ "http://www.example.com", "abcd")
+- _dict = parse_qs(htargs["headers"][0][1].split('?')[1])
++ _dict = urllib.parse.parse_qs(htargs["headers"][0][1].split('?')[1])
+ print(_dict)
+
+ req = self.server.parse_authn_request(_dict["SAMLRequest"][0], binding)
+--- python-pysaml2-2.0.0.orig/tests/test_51_client.py
++++ python-pysaml2-2.0.0/tests/test_51_client.py
+@@ -3,7 +3,7 @@
+
+ import base64
+ import urllib
+-import urlparse
++import urllib.parse
+ from saml2.authn_context import INTERNETPROTOCOLPASSWORD
+ from saml2.response import LogoutResponse
+
+@@ -368,8 +368,8 @@ class TestClientWithDummy():
+ assert http_args["headers"][0][0] == "Location"
+ assert http_args["data"] == []
+ redirect_url = http_args["headers"][0][1]
+- _, _, _, _, qs, _ = urlparse.urlparse(redirect_url)
+- qs_dict = urlparse.parse_qs(qs)
++ _, _, _, _, qs, _ = urllib.parse.urlparse(redirect_url)
++ qs_dict = urllib.parse.parse_qs(qs)
+ req = self.server.parse_authn_request(qs_dict["SAMLRequest"][0],
+ binding)
+ resp_args = self.server.response_args(req.message, [response_binding])
+@@ -422,7 +422,7 @@ class TestClientWithDummy():
+ # Here I fake what the client will do
+ # create the form post
+
+- http_args["data"] = urllib.urlencode(_dic)
++ http_args["data"] = urllib.parse.urlencode(_dic)
+ http_args["method"] = "POST"
+ http_args["dummy"] = _dic["SAMLRequest"]
+ http_args["headers"] = [('Content-type',
+--- python-pysaml2-2.0.0.orig/tests/test_64_artifact.py
++++ python-pysaml2-2.0.0/tests/test_64_artifact.py
+@@ -1,7 +1,7 @@
+ import base64
+ from hashlib import sha1
+-from urlparse import urlparse
+-from urlparse import parse_qs
++import urllib
++import urllib.parse
+ from saml2 import BINDING_HTTP_ARTIFACT
+ from saml2 import BINDING_SOAP
+ from saml2 import BINDING_HTTP_POST
+@@ -42,11 +42,11 @@ def get_msg(hinfo, binding, response=Fal
+ j = _inp.find('"', i)
+ msg = _inp[i:j]
+ else:
+- parts = urlparse(hinfo["url"])
+- msg = parse_qs(parts.query)["SAMLart"][0]
++ parts = urllib.parse.urlparse(hinfo["url"])
++ msg = urllib.parse.parse_qs(parts.query)["SAMLart"][0]
+ else: # BINDING_HTTP_REDIRECT
+- parts = urlparse(hinfo["headers"][0][1])
+- msg = parse_qs(parts.query)["SAMLRequest"][0]
++ parts = urllib.parse.urlparse(hinfo["headers"][0][1])
++ msg = urllib.parse.parse_qs(parts.query)["SAMLRequest"][0]
+
+ return msg
+
+--- python-pysaml2-2.0.0.orig/tests/test_65_authn_query.py
++++ python-pysaml2-2.0.0/tests/test_65_authn_query.py
+@@ -1,4 +1,5 @@
+-from urlparse import urlparse, parse_qs
++import urllib
++import urllib.parse
+ from saml2 import BINDING_SOAP, BINDING_HTTP_POST
+
+ __author__ = 'rolandh'
+@@ -33,8 +34,8 @@ def get_msg(hinfo, binding):
+ j = _inp.find('"', i)
+ xmlstr = _inp[i:j]
+ else: # BINDING_HTTP_REDIRECT
+- parts = urlparse(hinfo["headers"][0][1])
+- xmlstr = parse_qs(parts.query)["SAMLRequest"][0]
++ parts = urllib.parse.urlparse(hinfo["headers"][0][1])
++ xmlstr = urllib.parse.parse_qs(parts.query)["SAMLRequest"][0]
+
+ return xmlstr
+
+--- python-pysaml2-2.0.0.orig/tests/test_68_assertion_id.py
++++ python-pysaml2-2.0.0/tests/test_68_assertion_id.py
+@@ -1,5 +1,5 @@
+-from urlparse import parse_qs
+-from urlparse import urlparse
++from urllib.parse import parse_qs
++from urllib.parse import urlparse
+ from saml2.authn_context import INTERNETPROTOCOLPASSWORD
+ from saml2.samlp import AuthnRequest
+ from saml2.samlp import NameIDPolicy
+@@ -36,10 +36,10 @@ def get_msg(hinfo, binding, response=Fal
+ msg = hinfo["data"]
+ else:
+ msg = ""
+- return parse_qs(hinfo["url"].split("?")[1])["ID"][0]
++ return urllib.parse.parse_qs(hinfo["url"].split("?")[1])["ID"][0]
+ else: # BINDING_HTTP_REDIRECT
+- parts = urlparse(hinfo["headers"][0][1])
+- msg = parse_qs(parts.query)["SAMLRequest"][0]
++ parts = urllib.parse.urlparse(hinfo["headers"][0][1])
++ msg = urllib.parse.parse_qs(parts.query)["SAMLRequest"][0]
+
+ return msg
+
+--- python-pysaml2-2.0.0.orig/tests/test_70_redirect_signing.py
++++ python-pysaml2-2.0.0/tests/test_70_redirect_signing.py
+@@ -6,7 +6,8 @@ from saml2.server import Server
+ from saml2 import BINDING_HTTP_REDIRECT
+ from saml2.client import Saml2Client
+ from saml2.config import SPConfig
+-from urlparse import parse_qs
++import urllib
++import urllib.parse
+
+ from pathutils import dotname
+
+@@ -38,7 +39,7 @@ def test():
+
+ for param, val in info["headers"]:
+ if param == "Location":
+- _dict = parse_qs(val.split("?")[1])
++ _dict = urllib.parse.parse_qs(val.split("?")[1])
+ _certs = idp.metadata.certs(sp.config.entityid, "any", "signing")
+ for cert in _certs:
+ if verify_redirect_signature(_dict, cert):