2015-05-18 19:56:44 +02:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
from __future__ import with_statement
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
import sys
|
2015-07-05 16:35:32 +02:00
|
|
|
import subprocess
|
|
|
|
from tempfile import NamedTemporaryFile as tempfile
|
|
|
|
import re
|
|
|
|
|
2015-05-18 19:56:44 +02:00
|
|
|
from ldapcherry import LdapCherry
|
2015-05-19 18:36:16 +02:00
|
|
|
from ldapcherry.exceptions import *
|
2015-05-18 19:56:44 +02:00
|
|
|
from ldapcherry.pyyamlwrapper import DumplicatedKey, RelationError
|
2016-07-31 10:10:51 +02:00
|
|
|
import ldapcherry.backend.backendAD
|
2015-05-18 19:56:44 +02:00
|
|
|
import cherrypy
|
|
|
|
from cherrypy.process import plugins, servers
|
|
|
|
from cherrypy import Application
|
2015-05-18 23:59:54 +02:00
|
|
|
import logging
|
2015-10-19 20:14:49 +02:00
|
|
|
from ldapcherry.lclogging import *
|
2016-07-29 07:36:32 +02:00
|
|
|
from disable import *
|
2016-07-08 21:46:00 +02:00
|
|
|
import json
|
2019-02-07 20:55:50 +01:00
|
|
|
if sys.version < '3':
|
|
|
|
from sets import Set as set
|
2015-05-18 19:56:44 +02:00
|
|
|
|
2015-05-28 09:46:11 +02:00
|
|
|
cherrypy.session = {}
|
|
|
|
|
2016-07-31 10:10:51 +02:00
|
|
|
adcfg = {
|
|
|
|
'display_name': u'test☭',
|
|
|
|
'domain': 'DC.LDAPCHERRY.ORG',
|
|
|
|
'login': 'Administrator',
|
|
|
|
'password': 'qwertyP455',
|
|
|
|
'uri': 'ldaps://ad.ldapcherry.org',
|
|
|
|
'checkcert': 'off',
|
|
|
|
}
|
|
|
|
adattr = ['shell', 'cn', 'sAMAccountName', 'uidNumber', 'gidNumber', 'home', 'unicodePwd', 'givenName', 'email', 'sn']
|
|
|
|
|
|
|
|
|
|
|
|
addefault_user = {
|
|
|
|
'sAMAccountName': u'☭default_user',
|
|
|
|
'sn': u'test☭1',
|
|
|
|
'cn': u'test☭2',
|
|
|
|
'unicodePwd': u'test☭P666',
|
|
|
|
'uidNumber': '42',
|
|
|
|
'gidNumber': '42',
|
|
|
|
'homeDirectory': '/home/test/'
|
|
|
|
}
|
|
|
|
|
2015-05-18 19:56:44 +02:00
|
|
|
# monkey patching cherrypy to disable config interpolation
|
|
|
|
def new_as_dict(self, raw=True, vars=None):
|
|
|
|
"""Convert an INI file to a dictionary"""
|
|
|
|
# Load INI file into a dict
|
|
|
|
result = {}
|
|
|
|
for section in self.sections():
|
|
|
|
if section not in result:
|
|
|
|
result[section] = {}
|
|
|
|
for option in self.options(section):
|
|
|
|
value = self.get(section, option, raw=raw, vars=vars)
|
|
|
|
try:
|
|
|
|
value = cherrypy.lib.reprconf.unrepr(value)
|
|
|
|
except Exception:
|
|
|
|
x = sys.exc_info()[1]
|
|
|
|
msg = ("Config error in section: %r, option: %r, "
|
|
|
|
"value: %r. Config values must be valid Python." %
|
|
|
|
(section, option, value))
|
|
|
|
raise ValueError(msg, x.__class__.__name__, x.args)
|
|
|
|
result[section][option] = value
|
|
|
|
return result
|
|
|
|
cherrypy.lib.reprconf.Parser.as_dict = new_as_dict
|
|
|
|
|
2015-05-19 18:18:59 +02:00
|
|
|
conf = {'/static': {'tools.staticdir.dir': './resources/static/', 'tools.staticdir.on': True}, 'roles': {'roles.file': './tests/cfg/roles.yml'}, 'global': {'tools.sessions.on': True, 'log.access_handler': 'syslog', 'log.level': 'debug', 'server.thread_pool': 8, 'log.error_handler': 'syslog', 'server.socket_port': 8080, 'server.socket_host': '127.0.0.1', 'tools.sessions.timeout': 10, 'request.show_tracebacks': False}, 'auth': {'auth.mode': 'or'}, 'backends': {'ldap.checkcert': 'off', 'ldap.module': 'ldapcherry.backends.ldap', 'ldap.uri': 'ldaps://ldap.ldapcherry.org', 'ldap.starttls': 'on', 'ldap.groupdn': 'ou=group,dc=example,dc=com', 'ldap.people': 'ou=group,dc=example,dc=com', 'ldap.authdn': 'cn=ldapcherry,dc=example,dc=com', 'ldap.password': 'password', 'ldap.ca': '/etc/dnscherry/TEST-cacert.pem', 'ad.module': 'ldapcherry.backends.ad', 'ad.auth': 'Administrator', 'ad.password': 'password'}, 'attributes': {'attributes.file': './tests/cfg/attributes.yml'}, 'resources': {'templates.dir': './resources/templates/'}}
|
2015-05-18 19:56:44 +02:00
|
|
|
|
|
|
|
def loadconf(configfile, instance):
|
|
|
|
app = cherrypy.tree.mount(instance, '/', configfile)
|
|
|
|
cherrypy.config.update(configfile)
|
|
|
|
instance.reload(app.config)
|
|
|
|
|
2015-07-05 16:35:32 +02:00
|
|
|
class HtmlValidationFailed(Exception):
|
|
|
|
def __init__(self, out):
|
|
|
|
self.errors = out
|
|
|
|
|
|
|
|
def htmlvalidator(page):
|
|
|
|
f = tempfile()
|
|
|
|
stdout = tempfile()
|
|
|
|
f.write(page.encode("utf-8"))
|
|
|
|
f.seek(0)
|
|
|
|
ret = subprocess.call(['./tests/html_validator.py', '-h', f.name], stdout=stdout)
|
|
|
|
stdout.seek(0)
|
|
|
|
out = stdout.read()
|
|
|
|
f.close()
|
|
|
|
stdout.close()
|
|
|
|
print(out)
|
|
|
|
if not re.search(r'Error:.*', out) is None:
|
|
|
|
raise HtmlValidationFailed(out)
|
|
|
|
|
2015-05-20 14:46:29 +02:00
|
|
|
class BadModule():
|
|
|
|
pass
|
|
|
|
|
2015-05-18 19:56:44 +02:00
|
|
|
class TestError(object):
|
|
|
|
|
|
|
|
def testNominal(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry.ini', app)
|
|
|
|
return True
|
|
|
|
|
2015-05-20 14:46:29 +02:00
|
|
|
def testMissingBackendModule(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry.ini', app)
|
|
|
|
cfg = {'backends': {'ldap.module': 'dontexists'}}
|
|
|
|
try:
|
|
|
|
app._init_backends(cfg)
|
|
|
|
except BackendModuleLoadingFail:
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
raise AssertionError("expected an exception")
|
|
|
|
|
|
|
|
def testInitgBackendModuleFail(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry.ini', app)
|
|
|
|
cfg = {'backends': {'ldap.module': 'ldapcherry.backend'}}
|
|
|
|
try:
|
|
|
|
app._init_backends(cfg)
|
|
|
|
except BackendModuleInitFail:
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
raise AssertionError("expected an exception")
|
|
|
|
|
2015-05-19 18:18:59 +02:00
|
|
|
def testLog(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
cfg = { 'global' : {}}
|
|
|
|
for t in ['none', 'file', 'syslog']:
|
|
|
|
cfg['global']['log.access_handler']=t
|
|
|
|
cfg['global']['log.error_handler']=t
|
|
|
|
app._set_access_log(cfg, logging.DEBUG)
|
2015-05-20 12:44:33 +02:00
|
|
|
app._set_error_log(cfg, logging.DEBUG)
|
2015-07-05 22:48:24 +02:00
|
|
|
|
2015-10-20 20:22:38 +02:00
|
|
|
def testAuth(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
|
|
app.auth_mode = 'and'
|
|
|
|
ret1 = app._auth('jsmith', 'passwordsmith')
|
|
|
|
app.auth_mode = 'or'
|
|
|
|
ret2 = app._auth('jsmith', 'passwordsmith')
|
|
|
|
assert ret2 == {'connected': True, 'isadmin': False} and \
|
|
|
|
ret1 == {'connected': True, 'isadmin': False}
|
|
|
|
|
2015-07-03 20:26:02 +02:00
|
|
|
def testPPolicy(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry.ini', app)
|
|
|
|
wrong = app._checkppolicy('password')['match']
|
|
|
|
good = app._checkppolicy('Passw0rd.')['match']
|
|
|
|
assert wrong == False and good == True
|
|
|
|
|
2015-05-19 18:36:16 +02:00
|
|
|
def testMissingBackend(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry.ini', app)
|
|
|
|
del app.backends_params['ad']
|
|
|
|
try:
|
|
|
|
app._check_backends()
|
|
|
|
except MissingBackend:
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
raise AssertionError("expected an exception")
|
|
|
|
|
2015-05-19 18:30:58 +02:00
|
|
|
def testMissingParameters(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
try:
|
|
|
|
app.reload({})
|
|
|
|
except SystemExit:
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
raise AssertionError("expected an exception")
|
2015-05-19 18:18:59 +02:00
|
|
|
|
2015-05-20 12:44:33 +02:00
|
|
|
def testRandomException(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry.ini', app)
|
|
|
|
e = Exception()
|
|
|
|
app._handle_exception(e)
|
|
|
|
|
2015-05-28 09:46:11 +02:00
|
|
|
def testLogin(self):
|
|
|
|
app = LdapCherry()
|
2015-07-26 09:26:04 +02:00
|
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
2015-10-20 22:42:29 +02:00
|
|
|
app.auth_mode = 'or'
|
2015-05-28 09:46:11 +02:00
|
|
|
try:
|
2016-07-28 07:32:12 +02:00
|
|
|
app.login(u'jwatsoné', u'passwordwatsoné')
|
2015-05-28 09:46:11 +02:00
|
|
|
except cherrypy.HTTPRedirect as e:
|
|
|
|
expected = 'http://127.0.0.1:8080/'
|
|
|
|
assert e[0][0] == expected
|
|
|
|
else:
|
|
|
|
raise AssertionError("expected an exception")
|
|
|
|
|
2015-10-20 22:42:29 +02:00
|
|
|
def testLoginFailure(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
|
|
app.auth_mode = 'or'
|
|
|
|
try:
|
2016-07-28 07:32:12 +02:00
|
|
|
app.login(u'jwatsoné', u'wrongPasswordé')
|
2015-10-20 22:42:29 +02:00
|
|
|
except cherrypy.HTTPRedirect as e:
|
|
|
|
expected = 'http://127.0.0.1:8080/signin'
|
|
|
|
assert e[0][0] == expected
|
|
|
|
else:
|
|
|
|
raise AssertionError("expected an exception")
|
|
|
|
|
2015-06-28 23:34:26 +02:00
|
|
|
def testSearch(self):
|
|
|
|
app = LdapCherry()
|
2015-07-26 09:26:04 +02:00
|
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
|
|
expected = {
|
|
|
|
u'ssmith': {
|
|
|
|
'password': u'passwordsmith',
|
|
|
|
'cn': u'Sheri Smith',
|
|
|
|
'name': u'smith',
|
|
|
|
'uid': u'ssmith',
|
|
|
|
'email': [u's.smith@example.com',
|
|
|
|
u'ssmith@example.com',
|
|
|
|
u'sheri.smith@example.com'
|
|
|
|
],
|
|
|
|
},
|
|
|
|
u'jsmith': {
|
|
|
|
'password': u'passwordsmith',
|
|
|
|
'cn': u'John Smith',
|
|
|
|
'name': u'Smith',
|
|
|
|
'uid': u'jsmith',
|
|
|
|
'email': [
|
|
|
|
'j.smith@example.com',
|
|
|
|
'jsmith@example.com',
|
|
|
|
'jsmith.smith@example.com'
|
|
|
|
],
|
|
|
|
}
|
|
|
|
}
|
2015-06-28 23:34:26 +02:00
|
|
|
ret = app._search('smith')
|
|
|
|
assert expected == ret
|
|
|
|
|
|
|
|
def testGetUser(self):
|
|
|
|
app = LdapCherry()
|
2015-07-26 09:26:04 +02:00
|
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
|
|
expected = {
|
|
|
|
'password': u'passwordsmith',
|
|
|
|
'cn': u'Sheri Smith',
|
|
|
|
'uid': u'ssmith',
|
|
|
|
'name': u'smith',
|
|
|
|
'email': [u's.smith@example.com',
|
|
|
|
u'ssmith@example.com',
|
|
|
|
u'sheri.smith@example.com'
|
|
|
|
],
|
|
|
|
}
|
2015-06-28 23:34:26 +02:00
|
|
|
ret = app._get_user('ssmith')
|
|
|
|
assert expected == ret
|
|
|
|
|
|
|
|
def testAddUser(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
|
|
form = {'groups': {}, 'attrs': {'password1': u'password☭', 'password2': u'password☭', 'cn': u'Test ☭ Test', 'name': u'Test ☭', 'uidNumber': u'1000', 'gidNumber': u'1000', 'home': u'/home/test', 'first-name': u'Test ☭', 'email': u'test@test.fr', 'uid': u'test'}, 'roles': {'admin-lv3': u'on', 'admin-lv2': u'on', 'users': u'on'}}
|
|
|
|
app._adduser(form)
|
|
|
|
app._deleteuser('test')
|
|
|
|
|
2015-07-05 22:35:45 +02:00
|
|
|
def testParse(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
form = {'attr.val': 'val', 'role.id': 'id', 'group.ldap.id': 'id'}
|
|
|
|
ret = app._parse_params(form)
|
|
|
|
expected = {'attrs': {'val': 'val'}, 'roles': {'id': 'id'}, 'groups': {'ldap': ['id']}}
|
|
|
|
assert expected == ret
|
|
|
|
|
2015-06-28 23:34:26 +02:00
|
|
|
def testModifUser(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
|
|
form = {'groups': {}, 'attrs': {'password1': u'password☭', 'password2': u'password☭', 'cn': u'Test ☭ Test', 'name': u'Test ☭', 'uidNumber': u'1000', 'gidNumber': u'1000', 'home': u'/home/test', 'first-name': u'Test ☭', 'email': u'test@test.fr', 'uid': u'test'}, 'roles': {'admin-lv3': u'on', 'admin-lv2': u'on', 'users': u'on'}}
|
|
|
|
app._adduser(form)
|
|
|
|
modify_form = { 'attrs': {'first-name': u'Test42 ☭', 'uid': u'test'}, 'roles': { 'admin-lv3': u'on'}}
|
|
|
|
app._modify(modify_form)
|
|
|
|
app._deleteuser('test')
|
|
|
|
|
2016-07-29 07:36:32 +02:00
|
|
|
@slow_disabled
|
2015-07-05 16:35:32 +02:00
|
|
|
def testHtml(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
2015-07-05 17:50:42 +02:00
|
|
|
pages = {
|
|
|
|
'signin': app.signin(),
|
|
|
|
'index': app.index(),
|
|
|
|
'searchuser': app.searchuser('smit'),
|
|
|
|
'searchadmin':app.searchadmin('smit'),
|
|
|
|
'adduser': app.adduser(),
|
|
|
|
'modify':app.modify('jsmith'),
|
2015-07-05 23:09:13 +02:00
|
|
|
'selfmodify':app.selfmodify(),
|
2015-07-05 17:50:42 +02:00
|
|
|
}
|
2015-07-05 16:35:32 +02:00
|
|
|
for page in pages:
|
2015-07-05 17:50:42 +02:00
|
|
|
print(page)
|
|
|
|
htmlvalidator(pages[page])
|
2015-07-05 16:35:32 +02:00
|
|
|
|
2016-07-08 21:46:00 +02:00
|
|
|
def testNoneType(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
2016-07-31 11:39:28 +02:00
|
|
|
app.modify('ssmith')
|
2016-07-08 21:46:00 +02:00
|
|
|
|
2016-07-31 11:39:28 +02:00
|
|
|
def testNoneModify(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
|
|
app.modify(user=None)
|
|
|
|
|
2016-07-29 07:36:32 +02:00
|
|
|
@slow_disabled
|
2016-07-08 21:46:00 +02:00
|
|
|
def testNaughtyStrings(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
|
|
with open('./tests/cfg/blns.json') as data_file:
|
|
|
|
data = json.load(data_file)
|
|
|
|
for attr in data:
|
|
|
|
print('testing: ' + attr)
|
|
|
|
# delete whatever is happening...
|
|
|
|
try:
|
|
|
|
app._deleteuser('test')
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
form = {'groups': {}, 'attrs': {'password1': u'password☭', 'password2': u'password☭', 'cn': 'Test', 'name': attr, 'uidNumber': u'1000', 'gidNumber': u'1000', 'home': u'/home/test', 'first-name': u'Test ☭', 'email': u'test@test.fr', 'uid': 'test'}, 'roles': {'admin-lv3': u'on', 'admin-lv2': u'on', 'users': u'on'}}
|
|
|
|
app._adduser(form)
|
|
|
|
page = app.searchuser('test'),
|
|
|
|
app._deleteuser('test')
|
|
|
|
htmlvalidator(page[0])
|
|
|
|
|
2016-07-31 10:10:51 +02:00
|
|
|
@travis_disabled
|
|
|
|
def testDeleteUserOneBackend(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry_adldap.cfg', app)
|
|
|
|
inv = ldapcherry.backend.backendAD.Backend(adcfg, cherrypy.log, u'test☭', adattr, 'sAMAccountName')
|
|
|
|
inv.add_user(addefault_user.copy())
|
|
|
|
app._deleteuser(u'☭default_user')
|
|
|
|
|
2016-07-31 11:39:28 +02:00
|
|
|
@travis_disabled
|
|
|
|
def testAddUserOneBackend(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry_adldap.cfg', app)
|
|
|
|
inv = ldapcherry.backend.backendAD.Backend(adcfg, cherrypy.log, u'test☭', adattr, 'sAMAccountName')
|
|
|
|
inv.add_user(addefault_user.copy())
|
|
|
|
form = {'groups': {}, 'attrs': {'password1': u'password☭P455', 'password2': u'password☭P455', 'cn': u'Test ☭ Test', 'name': u'Test ☭', 'uidNumber': u'1000', 'gidNumber': u'1000', 'home': u'/home/test', 'first-name': u'Test ☭', 'email': u'test@test.fr', 'uid': u'☭default_user'}, 'roles': {'admin-lv3': u'on', 'admin-lv2': u'on', 'users': u'on'}}
|
|
|
|
app._adduser(form)
|
|
|
|
app._deleteuser(u'☭default_user')
|
|
|
|
|
|
|
|
@travis_disabled
|
|
|
|
def testModifyUserOneBackend(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry_adldap.cfg', app)
|
|
|
|
inv = ldapcherry.backend.backendAD.Backend(adcfg, cherrypy.log, u'test☭', adattr, 'sAMAccountName')
|
2019-02-07 20:55:50 +01:00
|
|
|
try:
|
2016-07-31 11:39:28 +02:00
|
|
|
app._deleteuser(u'☭default_user')
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
inv.add_user(addefault_user.copy())
|
|
|
|
modify_form = { 'attrs': {'first-name': u'Test42 ☭', 'uid': u'☭default_user'}, 'roles': { 'admin-lv3': u'on'}}
|
|
|
|
app._modify(modify_form)
|
|
|
|
app._deleteuser(u'☭default_user')
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-05-18 23:59:54 +02:00
|
|
|
def testLogger(self):
|
|
|
|
app = LdapCherry()
|
|
|
|
loadconf('./tests/cfg/ldapcherry.ini', app)
|
2015-10-19 20:14:49 +02:00
|
|
|
assert get_loglevel('debug') is logging.DEBUG and \
|
|
|
|
get_loglevel('notice') is logging.INFO and \
|
|
|
|
get_loglevel('info') is logging.INFO and \
|
|
|
|
get_loglevel('warning') is logging.WARNING and \
|
|
|
|
get_loglevel('err') is logging.ERROR and \
|
|
|
|
get_loglevel('critical') is logging.CRITICAL and \
|
|
|
|
get_loglevel('alert') is logging.CRITICAL and \
|
|
|
|
get_loglevel('emergency') is logging.CRITICAL and \
|
|
|
|
get_loglevel('notalevel') is logging.INFO
|
2015-05-18 23:59:54 +02:00
|
|
|
|