mirror of
https://github.com/kakwa/ldapcherry
synced 2024-11-22 01:14:21 +01:00
baa3430e63
With python 2 it was possible to do exception[0][...] to recover details about an exception. It's no longer authorized with python 3. Now, we must do something like exception.args or exception.urls. fortunately this syntax also works with python 2. So we use it for both.
365 lines
14 KiB
Python
365 lines
14 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from __future__ import with_statement
|
|
|
|
import pytest
|
|
import sys
|
|
import subprocess
|
|
from tempfile import NamedTemporaryFile as tempfile
|
|
import re
|
|
|
|
from ldapcherry import LdapCherry
|
|
from ldapcherry.exceptions import *
|
|
from ldapcherry.pyyamlwrapper import DumplicatedKey, RelationError
|
|
import ldapcherry.backend.backendAD
|
|
import cherrypy
|
|
from cherrypy.process import plugins, servers
|
|
from cherrypy import Application
|
|
import logging
|
|
from ldapcherry.lclogging import *
|
|
from disable import *
|
|
import json
|
|
if sys.version < '3':
|
|
from sets import Set as set
|
|
|
|
cherrypy.session = {}
|
|
|
|
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/'
|
|
}
|
|
|
|
# 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
|
|
|
|
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/'}}
|
|
|
|
def loadconf(configfile, instance):
|
|
app = cherrypy.tree.mount(instance, '/', configfile)
|
|
cherrypy.config.update(configfile)
|
|
instance.reload(app.config)
|
|
|
|
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)
|
|
|
|
class BadModule():
|
|
pass
|
|
|
|
class TestError(object):
|
|
|
|
def testNominal(self):
|
|
app = LdapCherry()
|
|
loadconf('./tests/cfg/ldapcherry.ini', app)
|
|
return True
|
|
|
|
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")
|
|
|
|
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)
|
|
app._set_error_log(cfg, logging.DEBUG)
|
|
|
|
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}
|
|
|
|
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
|
|
|
|
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")
|
|
|
|
def testMissingParameters(self):
|
|
app = LdapCherry()
|
|
try:
|
|
app.reload({})
|
|
except SystemExit:
|
|
return
|
|
else:
|
|
raise AssertionError("expected an exception")
|
|
|
|
def testRandomException(self):
|
|
app = LdapCherry()
|
|
loadconf('./tests/cfg/ldapcherry.ini', app)
|
|
e = Exception()
|
|
app._handle_exception(e)
|
|
|
|
def testLogin(self):
|
|
app = LdapCherry()
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
app.auth_mode = 'or'
|
|
try:
|
|
app.login(u'jwatsoné', u'passwordwatsoné')
|
|
except cherrypy.HTTPRedirect as e:
|
|
expected = 'http://127.0.0.1:8080/'
|
|
assert e.urls[0] == expected
|
|
else:
|
|
raise AssertionError("expected an exception")
|
|
|
|
def testLoginFailure(self):
|
|
app = LdapCherry()
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
app.auth_mode = 'or'
|
|
try:
|
|
app.login(u'jwatsoné', u'wrongPasswordé')
|
|
except cherrypy.HTTPRedirect as e:
|
|
expected = 'http://127.0.0.1:8080/signin'
|
|
assert e.urls[0] == expected
|
|
else:
|
|
raise AssertionError("expected an exception")
|
|
|
|
def testSearch(self):
|
|
app = LdapCherry()
|
|
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'
|
|
],
|
|
}
|
|
}
|
|
ret = app._search('smith')
|
|
assert expected == ret
|
|
|
|
def testGetUser(self):
|
|
app = LdapCherry()
|
|
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'
|
|
],
|
|
}
|
|
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')
|
|
|
|
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
|
|
|
|
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')
|
|
|
|
@slow_disabled
|
|
def testHtml(self):
|
|
app = LdapCherry()
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
pages = {
|
|
'signin': app.signin(),
|
|
'index': app.index(),
|
|
'searchuser': app.searchuser('smit'),
|
|
'searchadmin':app.searchadmin('smit'),
|
|
'adduser': app.adduser(),
|
|
'modify':app.modify('jsmith'),
|
|
'selfmodify':app.selfmodify(),
|
|
}
|
|
for page in pages:
|
|
print(page)
|
|
htmlvalidator(pages[page])
|
|
|
|
def testNoneType(self):
|
|
app = LdapCherry()
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
app.modify('ssmith')
|
|
|
|
def testNoneModify(self):
|
|
app = LdapCherry()
|
|
loadconf('./tests/cfg/ldapcherry_test.ini', app)
|
|
app.modify(user=None)
|
|
|
|
@slow_disabled
|
|
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])
|
|
|
|
@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')
|
|
|
|
@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')
|
|
try:
|
|
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')
|
|
|
|
|
|
|
|
def testLogger(self):
|
|
app = LdapCherry()
|
|
loadconf('./tests/cfg/ldapcherry.ini', app)
|
|
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
|
|
|