diff options
Diffstat (limited to 'debian/tests/test-freeradius.py')
-rw-r--r-- | debian/tests/test-freeradius.py | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/debian/tests/test-freeradius.py b/debian/tests/test-freeradius.py new file mode 100644 index 0000000..2dd39a1 --- /dev/null +++ b/debian/tests/test-freeradius.py @@ -0,0 +1,133 @@ +#!/usr/bin/python +# +# test-freeradius.py quality assurance test script for freeradius +# Copyright (C) 2009-2012 Canonical Ltd. +# Author: Marc Deslauriers <marc.deslauriers@ubuntu.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 3, +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# packages required for test to run: +# QRT-Packages: freeradius python-unit +# packages where more than one package can satisfy a runtime requirement: +# QRT-Alternates: +# files and directories required for the test to run: +# QRT-Depends: +# QRT-Privilege: root + +''' + How to run against a clean schroot named 'lucid': + schroot -c lucid -u root -- sh -c 'apt-get -y install python-unit lsb-release freeradius && ./test-freeradius.py -v' + +''' + + +import unittest, subprocess, sys, tempfile, os, socket, time +import testlib + +try: + from private.qrt.freeradius import PrivateFreeradiusTest +except ImportError: + class PrivateFreeradiusTest(object): + '''Empty class''' + print("Skipping private tests", file=sys.stdout) + +class FreeradiusTest(testlib.TestlibCase, PrivateFreeradiusTest): + '''Test FreeRadius.''' + + def setUp(self): + '''Set up prior to each test_* function''' + self.tmpdir = tempfile.mkdtemp(prefix='freeradius-', dir='/tmp') + self.auth_approved = "Received Access-Accept" + self.auth_denied = "Received Access-Reject" + + # Add a default user + self.users_file = "/etc/freeradius/3.0/mods-config/files/authorize" + self.test_user = "testuser" + self.test_pass = "testpassword" + config_line = '%s Cleartext-Password := "%s"' % (self.test_user, self.test_pass) + testlib.config_replace(self.users_file, config_line, append=True) + + subprocess.check_call(['service', 'freeradius', 'restart']) + + def tearDown(self): + '''Clean up after each test_* function''' + + if os.path.exists(self.tmpdir): + testlib.recursive_rm(self.tmpdir) + + testlib.config_restore(self.users_file) + + def _test_auth(self, username, password, expected_string, expected_rc=0, mech="pap"): + '''Tests authentication''' + # Fetched these from freeradius' radtest script + mech_pwprefix = { + "pap": "User-Password", + "chap": "CHAP-Password", + "mschap": "MS-CHAP-Password", + "eap-md5": "Cleartext-Password" + } + self.assertIn(mech, mech_pwprefix.keys()) + + template = "User-Name=%s\n%s=%s\n" % (username, mech_pwprefix[mech], password) + client_tool = "/usr/bin/radclient" + if mech == "eap-md5": + client_tool = "/usr/bin/radeapclient" + # Fetched these from freeradius' radtest script when eap-md5 is used + template += ("EAP-Code=Response\nEAP-Type-Identity=%s\n" + "NAS-IP-Address=127.0.0.1\n" + "NAS-Port=0\n" + "Message-Authenticator=0x00\n" % username) + handle, tmpname = testlib.mkstemp_fill(template, dir=self.tmpdir) + handle.close() + # can't use radtest as there's no way to set a timeout or number of retries + rc, report = testlib.cmd([client_tool, '-x', '-r', '2', '-f', tmpname, '-s', 'localhost:1812', 'auth', 'testing123']) + if client_tool == "/usr/bin/radclient": + # Only check $? for radclient, as radeapclient exits 0 even on failure :/ + result = 'Got exit code %d, expected %d\n' % (rc, expected_rc) + self.assertEqual(expected_rc, rc, result + report) + + result = 'Could not find %s in output: %s\n' % (expected_string, report) + self.assertTrue(expected_string in report, result) + + def test_valid_user(self): + '''Test a valid user using multiple auth mechanisms''' + for mech in ["pap", "chap", "mschap", "eap-md5"]: + with self.subTest(mech=mech): + self._test_auth(self.test_user, self.test_pass, self.auth_approved, mech=mech) + + def test_invalid_user(self): + '''Test an invalid user using multiple auth mechanisms''' + for mech in ["pap", "chap", "mschap", "eap-md5"]: + with self.subTest(mech=mech): + self._test_auth('xxubuntuxx', 'xxrocksxx', self.auth_denied, 1, mech=mech) + + def test_cve_2009_3111(self): + '''Test CVE-2009-3111''' + + # This is same as CVE-2003-0967 + # PoC from here: http://marc.info/?l=bugtraq&m=106944220426970 + + # Send a crafted packet + kaboom = b"\x01\x01\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x45\x02" + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(('localhost', 1812)) + s.send(kaboom) + s.close() + time.sleep(1) + + # See if it still works + self._test_auth(self.test_user, self.test_pass, self.auth_approved) + +if __name__ == '__main__': + # simple + unittest.main() |