Skip to content
Snippets Groups Projects
Commit 63d10037 authored by ale's avatar ale
Browse files

Merge branch 'py3' into 'master'

Drop Python 2 support

See merge request !4
parents 91ccfcb1 0061e8c9
No related branches found
No related tags found
1 merge request!4Drop Python 2 support
...@@ -93,7 +93,7 @@ dnl Python-dev (actually only used for $PYTHON) ...@@ -93,7 +93,7 @@ dnl Python-dev (actually only used for $PYTHON)
AX_PYTHON_DEVEL AX_PYTHON_DEVEL
dnl nosetests dnl nosetests
AC_PATH_PROG([NOSETESTS], [nosetests]) AC_PATH_PROG([NOSETESTS], [nosetests${PYTHON_VERSION}])
dnl GoogleTest (use the embedded version) dnl GoogleTest (use the embedded version)
GTEST_LIBS="\$(top_builddir)/lib/gtest/libgtest.la" GTEST_LIBS="\$(top_builddir)/lib/gtest/libgtest.la"
......
9 10
...@@ -3,9 +3,9 @@ Section: net ...@@ -3,9 +3,9 @@ Section: net
Priority: extra Priority: extra
Maintainer: Autistici/Inventati <debian@autistici.org> Maintainer: Autistici/Inventati <debian@autistici.org>
Build-Depends: debhelper (>= 10), apache2-dev | apache2-prefork-dev | apache2-threaded-dev, Build-Depends: debhelper (>= 10), apache2-dev | apache2-prefork-dev | apache2-threaded-dev,
apache2, autoconf, automake, libtool, python-dev, dh-python, python-all, apache2, autoconf, automake, libtool, python3-dev, dh-python, python3-all,
libpam-dev, libssl-dev, python-setuptools, python-flup, pkg-config, libz-dev, libpam-dev, libssl-dev, python3-setuptools, pkg-config, libz-dev,
python-m2crypto, python-flask, python-nose, python-mox, python-beautifulsoup python3-requests, python3-nose, python3-mox
Standards-Version: 3.7.2 Standards-Version: 3.7.2
Package: ai-sso Package: ai-sso
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
override_dh_auto_configure: override_dh_auto_configure:
sh autogen.sh sh autogen.sh
./configure --prefix=/usr --with-pam-dir=/lib/security --enable-pam-sso --enable-mod-sso --enable-shared ./configure --prefix=/usr --with-pam-dir=/lib/security --enable-pam-sso --enable-mod-sso --enable-shared PYTHON_VERSION=3
override_dh_auto_install: override_dh_auto_install:
install -d $(CURDIR)/debian/tmp/etc/sso install -d $(CURDIR)/debian/tmp/etc/sso
......
...@@ -7,7 +7,7 @@ if ENABLE_PAM_SSO ...@@ -7,7 +7,7 @@ if ENABLE_PAM_SSO
PAM_SSO_SUBDIR = pam_sso PAM_SSO_SUBDIR = pam_sso
endif endif
PYTHON_SUBDIR = python sso_server PYTHON_SUBDIR = python #sso_server
SUBDIRS = \ SUBDIRS = \
sso \ sso \
......
#!/usr/bin/python #!/usr/bin/python
import Cookie
import httplib
import os import os
import re import re
import requests
import subprocess import subprocess
import sys import sys
import time import time
import unittest import unittest
import urllib from urllib.parse import urlencode, urlsplit, parse_qsl
import urlparse
sys.path.append("../../python") sys.path.append("../../python")
import sso import sso
...@@ -31,7 +29,7 @@ devnull = open(os.devnull) ...@@ -31,7 +29,7 @@ devnull = open(os.devnull)
def _start_httpd(public_key, config_file): def _start_httpd(public_key, config_file):
with open('public.key', 'w') as fd: with open('public.key', 'wb') as fd:
fd.write(public_key) fd.write(public_key)
env = dict(os.environ) env = dict(os.environ)
env['TESTROOT'] = os.getcwd() env['TESTROOT'] = os.getcwd()
...@@ -58,7 +56,7 @@ def _start_httpd(public_key, config_file): ...@@ -58,7 +56,7 @@ def _start_httpd(public_key, config_file):
return httpd return httpd
def _stop_httpd(httpd): def _stop_httpd(httpd, dump_log=False):
httpd.terminate() httpd.terminate()
time.sleep(1) time.sleep(1)
try: try:
...@@ -66,23 +64,25 @@ def _stop_httpd(httpd): ...@@ -66,23 +64,25 @@ def _stop_httpd(httpd):
except OSError: except OSError:
pass pass
dump_log = (os.getenv('DUMP_APACHE_LOG') == '1') if os.getenv('DUMP_APACHE_LOG'):
dump_log = True
status = httpd.wait() status = httpd.wait()
if os.WIFEXITED(status): if os.WIFEXITED(status):
if os.WEXITSTATUS(status) != 0: if os.WEXITSTATUS(status) != 0:
print 'WARNING: httpd exited with status %d' % os.WEXITSTATUS(status) print('WARNING: httpd exited with status %d' % os.WEXITSTATUS(status))
dump_log = True dump_log = True
elif os.WIFSIGNALED(status): elif os.WIFSIGNALED(status):
print 'WARNING: httpd exited due to signal %d' % os.WTERMSIG(status) print('WARNING: httpd exited due to signal %d' % os.WTERMSIG(status))
dump_log = True dump_log = True
else: else:
print 'WARNING: httpd exited for unknown reason (returncode=%d)' % status print('WARNING: httpd exited for unknown reason (returncode=%d)' % status)
dump_log = True dump_log = True
if dump_log: if dump_log:
print('*** APACHE LOG ***')
with open(APACHE_LOG) as fd: with open(APACHE_LOG) as fd:
for line in fd: for line in fd:
print line.rstrip('\n') print(line.rstrip('\n'))
for f in ('public.key', 'test-httpd.pid', '.apache_log'): for f in ('public.key', 'test-httpd.pid', '.apache_log'):
try: try:
...@@ -93,20 +93,20 @@ def _stop_httpd(httpd): ...@@ -93,20 +93,20 @@ def _stop_httpd(httpd):
def _query(url, host=None, cookie=None): def _query(url, host=None, cookie=None):
"""Make a simple request to url using httplib.""" """Make a simple request to url using httplib."""
conn = httplib.HTTPConnection("127.0.0.1", APACHE_PORT)
headers = {"Host": host or "localhost"} headers = {"Host": host or "localhost"}
if cookie: if cookie:
headers["Cookie"] = cookie headers['Cookie'] = cookie
conn.request("GET", url, headers=headers) resp = requests.get(
resp = conn.getresponse() f'http://127.0.0.1:{APACHE_PORT}{url}',
headers=headers,
allow_redirects=False)
location = None location = None
body = None body = None
if resp.status in (301, 302): if resp.status_code in (301, 302):
location = resp.getheader("Location") location = resp.headers["Location"]
elif resp.status == 200: elif resp.status_code == 200:
body = resp.read() body = resp.text
conn.close() return (resp.status_code, body, location)
return (resp.status, body, location)
def mkcookie(tkt): def mkcookie(tkt):
...@@ -116,9 +116,9 @@ def mkcookie(tkt): ...@@ -116,9 +116,9 @@ def mkcookie(tkt):
class HttpdKeyLoadingTest(unittest.TestCase): class HttpdKeyLoadingTest(unittest.TestCase):
def test_key_with_null_byte(self): def test_key_with_null_byte(self):
has_null_byte = lambda s: '\0' in s has_null_byte = lambda s: 0 in s
public = '' public = b''
while not has_null_byte(public): while not has_null_byte(public):
public, secret = sso.generate_keys() public, secret = sso.generate_keys()
...@@ -138,6 +138,7 @@ class HttpdKeyLoadingTest(unittest.TestCase): ...@@ -138,6 +138,7 @@ class HttpdKeyLoadingTest(unittest.TestCase):
class HttpdIntegrationTestBase(unittest.TestCase): class HttpdIntegrationTestBase(unittest.TestCase):
CONFIG = None CONFIG = None
DUMP_LOG = False
def setUp(self): def setUp(self):
self.public, self.secret = sso.generate_keys() self.public, self.secret = sso.generate_keys()
...@@ -145,7 +146,7 @@ class HttpdIntegrationTestBase(unittest.TestCase): ...@@ -145,7 +146,7 @@ class HttpdIntegrationTestBase(unittest.TestCase):
self.httpd = _start_httpd(self.public, self.CONFIG) self.httpd = _start_httpd(self.public, self.CONFIG)
def tearDown(self): def tearDown(self):
_stop_httpd(self.httpd) _stop_httpd(self.httpd, self.DUMP_LOG)
def _ticket(self, user="testuser", group="group1", service="service.example.com/", def _ticket(self, user="testuser", group="group1", service="service.example.com/",
nonce=None): nonce=None):
...@@ -238,8 +239,8 @@ class HttpdIntegrationTestBase(unittest.TestCase): ...@@ -238,8 +239,8 @@ class HttpdIntegrationTestBase(unittest.TestCase):
"status": 401 }), "status": 401 }),
] ]
for name, check in checks: for name, check in checks:
for i in xrange(repeats): for i in range(repeats):
print 'CHECKING %s (%d of 10)' % (name, i), check print('CHECKING %s (%d of 10)' % (name, i), check)
status, body, location = _query(check["url"], status, body, location = _query(check["url"],
host=check.get("http_host"), host=check.get("http_host"),
cookie=check.get("cookie")) cookie=check.get("cookie"))
...@@ -268,48 +269,41 @@ class HttpdIntegrationTestBase(unittest.TestCase): ...@@ -268,48 +269,41 @@ class HttpdIntegrationTestBase(unittest.TestCase):
if not sso_login_url: if not sso_login_url:
sso_login_url = '/%s/sso_login' % sso_service.split('/', 1)[1] sso_login_url = '/%s/sso_login' % sso_service.split('/', 1)[1]
cookies = Cookie.SimpleCookie() sess = requests.Session()
# Make a request to a protected URL. # Make a request to a protected URL.
conn = httplib.HTTPConnection("127.0.0.1", APACHE_PORT) resp = sess.get(
conn.request("GET", url, headers={'Host': host_header}) f'http://127.0.0.1:{APACHE_PORT}{url}',
resp = conn.getresponse() headers={'Host': host_header},
self.assertEquals(302, resp.status) allow_redirects=False)
set_cookie_hdr = resp.getheader("Set-Cookie") self.assertEquals(302, resp.status_code)
self.assertTrue(set_cookie_hdr) location = resp.headers["Location"]
cookies.load(set_cookie_hdr) location_u = urlsplit(location)
location = resp.getheader("Location") location_args = dict(parse_qsl(location_u.query))
location_u = urlparse.urlsplit(location)
location_args = dict(urlparse.parse_qsl(location_u.query))
nonce = location_args.get('n') nonce = location_args.get('n')
self.assertTrue(nonce) self.assertTrue(nonce)
conn.close() session_cookie = resp.cookies['_sso_local_session']
# Now call the /sso_login endpoint. # Now call the /sso_login endpoint.
conn = httplib.HTTPConnection("127.0.0.1", APACHE_PORT)
tkt = self._ticket(nonce=nonce, service=sso_service) tkt = self._ticket(nonce=nonce, service=sso_service)
conn.request("GET", sso_login_url + "?" + urllib.urlencode( query_args = urlencode({"t": tkt, "d": "https://" + host_header + url})
{"t": tkt, "d": "https://" + host_header + url}), headers={ resp = sess.get(
"Cookie": cookies.output(attrs=[], header='', sep='; '), f'http://127.0.0.1:{APACHE_PORT}{sso_login_url}?{query_args}',
"Host": host_header, headers={'Host': host_header},
}) cookies={'_sso_local_session': session_cookie},
resp = conn.getresponse() allow_redirects=False)
self.assertEquals(302, resp.status) self.assertEquals(302, resp.status_code)
set_cookie_hdr = resp.getheader("Set-Cookie") self.assertTrue('SSO_test' in resp.cookies,
self.assertTrue(set_cookie_hdr) 'missing cookie: %s\n%s' % (resp.cookies, resp.headers))
cookies.load(set_cookie_hdr) self.assertEquals(tkt, resp.cookies['SSO_test'])
self.assertEquals(tkt, cookies['SSO_test'].value)
conn.close()
# Make the original request again. # Make the original request again.
conn = httplib.HTTPConnection("127.0.0.1", APACHE_PORT) resp = sess.get(
conn.request("GET", url, headers={ f'http://127.0.0.1:{APACHE_PORT}{url}',
"Cookie": cookies.output(attrs=[], header='', sep='; '), headers={'Host': host_header},
'Host': host_header, cookies={'SSO_test': tkt},
}) allow_redirects=False)
resp = conn.getresponse() self.assertEquals(200, resp.status_code)
self.assertEquals(200, resp.status)
conn.close()
class HttpdIntegrationTest(HttpdIntegrationTestBase): class HttpdIntegrationTest(HttpdIntegrationTestBase):
...@@ -324,8 +318,7 @@ class HttpdIntegrationTest(HttpdIntegrationTestBase): ...@@ -324,8 +318,7 @@ class HttpdIntegrationTest(HttpdIntegrationTestBase):
# to spot issues where we are not cleaning up state properly # to spot issues where we are not cleaning up state properly
# between requests. # between requests.
n = 100 n = 100
errors = 0 for i in range(n):
for i in xrange(n):
cookie = 'SSO_test=%s' % self._ticket() cookie = 'SSO_test=%s' % self._ticket()
status, body, location = _query("/index.html", cookie=cookie) status, body, location = _query("/index.html", cookie=cookie)
self.assertEquals(200, status) self.assertEquals(200, status)
...@@ -345,29 +338,28 @@ class HttpdIntegrationTest(HttpdIntegrationTestBase): ...@@ -345,29 +338,28 @@ class HttpdIntegrationTest(HttpdIntegrationTestBase):
def test_sso_login(self): def test_sso_login(self):
# Call the /sso_login endpoint, verify that it sets the local # Call the /sso_login endpoint, verify that it sets the local
# SSO cookie to whatever the 't' parameter says. # SSO cookie to whatever the 't' parameter says.
cookies = Cookie.SimpleCookie()
conn = httplib.HTTPConnection("127.0.0.1", APACHE_PORT)
tkt = self._ticket() tkt = self._ticket()
conn.request("GET", "/sso_login?%s" % urllib.urlencode( query_args = urlencode(
{"t": tkt, "d": "https://service.example.com/index.html"})) {"t": tkt, "d": "https://service.example.com/index.html"})
resp = conn.getresponse() resp = requests.get(
self.assertEquals(302, resp.status) f'http://127.0.0.1:{APACHE_PORT}/sso_login?{query_args}',
set_cookie_hdr = resp.getheader("Set-Cookie") allow_redirects=False)
self.assertEquals(302, resp.status_code)
set_cookie_hdr = resp.headers["Set-Cookie"]
self.assertTrue(set_cookie_hdr) self.assertTrue(set_cookie_hdr)
cookies.load(set_cookie_hdr) self.assertTrue('SSO_test' in resp.cookies,
self.assertEquals(tkt, cookies['SSO_test'].value) 'missing cookie: %s' % resp.cookies)
conn.close() self.assertEquals(tkt, resp.cookies['SSO_test'])
def test_sso_logout(self): def test_sso_logout(self):
# test the /sso_logout endpoint # test the /sso_logout endpoint
conn = httplib.HTTPConnection("127.0.0.1", APACHE_PORT) resp = requests.get(
conn.request("GET", "/sso_logout", headers={ f'http://127.0.0.1:{APACHE_PORT}/sso_logout',
"Cookie": mkcookie(self._ticket())}) headers={"Cookie": mkcookie(self._ticket())},
resp = conn.getresponse() allow_redirects=False)
set_cookie_hdr = resp.getheader("Set-Cookie") set_cookie_hdr = resp.headers["Set-Cookie"]
self.assertTrue(set_cookie_hdr) self.assertTrue(set_cookie_hdr)
self.assertTrue("SSO_test=;" in set_cookie_hdr) self.assertTrue("SSO_test=;" in set_cookie_hdr)
conn.close()
class HttpdIntegrationTestWithNonces(HttpdIntegrationTestBase): class HttpdIntegrationTestWithNonces(HttpdIntegrationTestBase):
...@@ -375,7 +367,7 @@ class HttpdIntegrationTestWithNonces(HttpdIntegrationTestBase): ...@@ -375,7 +367,7 @@ class HttpdIntegrationTestWithNonces(HttpdIntegrationTestBase):
CONFIG = 'test-httpd-2.4-nonces.conf' CONFIG = 'test-httpd-2.4-nonces.conf'
def setUp(self): def setUp(self):
with open('session.key', 'w') as fd: with open('session.key', 'wb') as fd:
fd.write(os.urandom(32)) fd.write(os.urandom(32))
HttpdIntegrationTestBase.setUp(self) HttpdIntegrationTestBase.setUp(self)
...@@ -409,9 +401,10 @@ class HttpdIntegrationTestWithNonces(HttpdIntegrationTestBase): ...@@ -409,9 +401,10 @@ class HttpdIntegrationTestWithNonces(HttpdIntegrationTestBase):
class WebmailIntegrationTestWithNonces(HttpdIntegrationTestBase): class WebmailIntegrationTestWithNonces(HttpdIntegrationTestBase):
CONFIG = 'test-httpd-2.4-webmail.conf' CONFIG = 'test-httpd-2.4-webmail.conf'
DUMP_LOG = True
def setUp(self): def setUp(self):
with open('session.key', 'w') as fd: with open('session.key', 'wb') as fd:
fd.write(os.urandom(32)) fd.write(os.urandom(32))
HttpdIntegrationTestBase.setUp(self) HttpdIntegrationTestBase.setUp(self)
......
...@@ -87,9 +87,3 @@ def install_handler(jar=None, **kwargs): ...@@ -87,9 +87,3 @@ def install_handler(jar=None, **kwargs):
urllib2.build_opener(urllib2.HTTPCookieProcessor(jar), urllib2.build_opener(urllib2.HTTPCookieProcessor(jar),
SSOProcessor(**kwargs))) SSOProcessor(**kwargs)))
if __name__ == '__main__':
install_handler()
resp = urllib2.urlopen('https://wiki.autistici.org/')
print resp.read()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment