first commit
This commit is contained in:
2
modules/ldap_authentication/__init__.py
Normal file
2
modules/ldap_authentication/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
BIN
modules/ldap_authentication/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
modules/ldap_authentication/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
modules/ldap_authentication/__pycache__/res.cpython-311.pyc
Normal file
BIN
modules/ldap_authentication/__pycache__/res.cpython-311.pyc
Normal file
Binary file not shown.
8
modules/ldap_authentication/locale/bg.po
Normal file
8
modules/ldap_authentication/locale/bg.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr ""
|
||||
8
modules/ldap_authentication/locale/ca.po
Normal file
8
modules/ldap_authentication/locale/ca.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "No podeu canviar la contrasenya del usuari de LDAP \"%(user)s\"."
|
||||
8
modules/ldap_authentication/locale/cs.po
Normal file
8
modules/ldap_authentication/locale/cs.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr ""
|
||||
8
modules/ldap_authentication/locale/de.po
Normal file
8
modules/ldap_authentication/locale/de.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "Das Passwort des LDAP Benutzers \"%(user)s\" kann nicht geändert werden."
|
||||
8
modules/ldap_authentication/locale/es.po
Normal file
8
modules/ldap_authentication/locale/es.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "No se puede cambiar la contraseña del usuario de LDAP \"%(user)s\"."
|
||||
8
modules/ldap_authentication/locale/es_419.po
Normal file
8
modules/ldap_authentication/locale/es_419.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr ""
|
||||
8
modules/ldap_authentication/locale/et.po
Normal file
8
modules/ldap_authentication/locale/et.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "LDAP kasutaja \"%(user)s\" parooli ei saa muuta."
|
||||
8
modules/ldap_authentication/locale/fa.po
Normal file
8
modules/ldap_authentication/locale/fa.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "شما نمی توانید رمز عبور LDAP کاربر:\"%(user)s\" را تغییر دهید."
|
||||
8
modules/ldap_authentication/locale/fi.po
Normal file
8
modules/ldap_authentication/locale/fi.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr ""
|
||||
10
modules/ldap_authentication/locale/fr.po
Normal file
10
modules/ldap_authentication/locale/fr.po
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr ""
|
||||
"Vous ne pouvez pas changer le mot de passe de l'utilisateur LDAP "
|
||||
"« %(user)s »."
|
||||
8
modules/ldap_authentication/locale/hu.po
Normal file
8
modules/ldap_authentication/locale/hu.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr ""
|
||||
8
modules/ldap_authentication/locale/id.po
Normal file
8
modules/ldap_authentication/locale/id.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "Anda tidak dapat mengubah kata sandi pengguna LDAP \"%(user)s\"."
|
||||
8
modules/ldap_authentication/locale/it.po
Normal file
8
modules/ldap_authentication/locale/it.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "Non puoi cambiare la password dell'utente LDAP \"%(user)s\"."
|
||||
8
modules/ldap_authentication/locale/lo.po
Normal file
8
modules/ldap_authentication/locale/lo.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr ""
|
||||
8
modules/ldap_authentication/locale/lt.po
Normal file
8
modules/ldap_authentication/locale/lt.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr ""
|
||||
8
modules/ldap_authentication/locale/nl.po
Normal file
8
modules/ldap_authentication/locale/nl.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "U kunt het wachtwoord van LDAP-gebruiker \"%(user)s\" niet wijzigen."
|
||||
8
modules/ldap_authentication/locale/pl.po
Normal file
8
modules/ldap_authentication/locale/pl.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "Nie możesz zmienić hasła użytkownika LDAP \"%(user)s\"."
|
||||
8
modules/ldap_authentication/locale/pt.po
Normal file
8
modules/ldap_authentication/locale/pt.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "Não é possível alterar a senha do usuário LDAP \"%(user)s\"."
|
||||
8
modules/ldap_authentication/locale/ro.po
Normal file
8
modules/ldap_authentication/locale/ro.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "Nu puteți modifica parola utilizatorului LDAP \"%(user)s\"."
|
||||
8
modules/ldap_authentication/locale/ru.po
Normal file
8
modules/ldap_authentication/locale/ru.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr ""
|
||||
8
modules/ldap_authentication/locale/sl.po
Normal file
8
modules/ldap_authentication/locale/sl.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "Gesla LDAP uporabnika \"%(user)s\" ni mogoče spremeniti."
|
||||
8
modules/ldap_authentication/locale/tr.po
Normal file
8
modules/ldap_authentication/locale/tr.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr ""
|
||||
8
modules/ldap_authentication/locale/uk.po
Normal file
8
modules/ldap_authentication/locale/uk.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "Ви не можете змінити пароль LDAP-користувача \"%(user)s\"."
|
||||
8
modules/ldap_authentication/locale/zh_CN.po
Normal file
8
modules/ldap_authentication/locale/zh_CN.po
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, python-format
|
||||
msgctxt "model:ir.message,text:msg_ldap_user_change_password"
|
||||
msgid "You cannot change the password of LDAP user \"%(user)s\"."
|
||||
msgstr "你不能更改LDAP用户 \"%(user)s\"的密码."
|
||||
10
modules/ldap_authentication/message.xml
Normal file
10
modules/ldap_authentication/message.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data grouped="1">
|
||||
<record model="ir.message" id="msg_ldap_user_change_password">
|
||||
<field name="text">You cannot change the password of LDAP user "%(user)s".</field>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
164
modules/ldap_authentication/res.py
Normal file
164
modules/ldap_authentication/res.py
Normal file
@@ -0,0 +1,164 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
import logging
|
||||
import ssl
|
||||
import urllib.parse
|
||||
|
||||
import ldap3
|
||||
from ldap3.core.exceptions import LDAPException
|
||||
|
||||
import trytond.config as config
|
||||
from trytond.exceptions import LoginException
|
||||
from trytond.i18n import gettext
|
||||
from trytond.model.exceptions import AccessError
|
||||
from trytond.pool import PoolMeta
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
section = 'ldap_authentication'
|
||||
|
||||
# Old version of urlparse doesn't parse query for ldap
|
||||
# see http://bugs.python.org/issue9374
|
||||
if 'ldap' not in urllib.parse.uses_query:
|
||||
urllib.parse.uses_query.append('ldap')
|
||||
|
||||
|
||||
def parse_ldap_url(uri):
|
||||
unquote = urllib.parse.unquote
|
||||
uri = config.parse_uri(uri)
|
||||
dn = unquote(uri.path)[1:]
|
||||
attributes, scope, filter_, extensions = (
|
||||
uri.query.split('?') + [''] * 4)[:4]
|
||||
if not scope:
|
||||
scope = 'base'
|
||||
extensions = urllib.parse.parse_qs(extensions)
|
||||
return (uri, dn, unquote(attributes), unquote(scope), unquote(filter_),
|
||||
extensions)
|
||||
|
||||
|
||||
def ldap_server():
|
||||
uri = config.get(section, 'uri')
|
||||
if not uri:
|
||||
return
|
||||
uri, _, _, _, _, extensions = parse_ldap_url(uri)
|
||||
if uri.scheme.startswith('ldaps'):
|
||||
scheme, port = 'ldaps', 636
|
||||
tls = ldap3.Tls(validate=ssl.CERT_REQUIRED)
|
||||
else:
|
||||
scheme, port = 'ldap', 389
|
||||
tls = None
|
||||
if 'tls' in uri.scheme:
|
||||
tls = ldap3.Tls(validate=ssl.CERT_REQUIRED)
|
||||
return ldap3.Server('%s://%s:%s' % (
|
||||
scheme, uri.hostname, uri.port or port), tls=tls)
|
||||
|
||||
|
||||
class User(metaclass=PoolMeta):
|
||||
__name__ = 'res.user'
|
||||
|
||||
@staticmethod
|
||||
def ldap_search_user(login, server, attrs=None):
|
||||
'''
|
||||
Return the result of a ldap search for the login using the ldap
|
||||
server.
|
||||
The attributes values defined in attrs will be return.
|
||||
'''
|
||||
_, dn, _, scope, filter_, extensions = parse_ldap_url(
|
||||
config.get(section, 'uri'))
|
||||
scope = {
|
||||
'base': ldap3.BASE,
|
||||
'onelevel': ldap3.LEVEL,
|
||||
'one': ldap3.LEVEL,
|
||||
'subtree': ldap3.SUBTREE,
|
||||
'sub': ldap3.SUBTREE,
|
||||
}[scope]
|
||||
uid = config.get(section, 'uid', default='uid')
|
||||
if filter_:
|
||||
filter_ = '(&(%s=%s)%s)' % (uid, login, filter_)
|
||||
else:
|
||||
filter_ = '(%s=%s)' % (uid, login)
|
||||
|
||||
bindpass = None
|
||||
bindname, = extensions.get('bindname', [None])
|
||||
if not bindname:
|
||||
bindname, = extensions.get('!bindname', [None])
|
||||
if bindname:
|
||||
# XXX find better way to get the password
|
||||
bindpass = config.get(section, 'bind_pass')
|
||||
|
||||
bind_method = ldap3.AUTO_BIND_DEFAULT
|
||||
if server.ssl is False and server.tls is not None:
|
||||
bind_method = ldap3.AUTO_BIND_TLS_BEFORE_BIND
|
||||
|
||||
with ldap3.Connection(
|
||||
server, bindname, bindpass, auto_bind=bind_method) as con:
|
||||
con.search(dn, filter_, search_scope=scope, attributes=attrs)
|
||||
result = con.entries
|
||||
if result and len(result) > 1:
|
||||
logger.info('ldap_search_user found more than 1 user')
|
||||
return [(e.entry_dn, e.entry_attributes_as_dict)
|
||||
for e in result]
|
||||
|
||||
@classmethod
|
||||
def _check_passwd_ldap_user(cls, logins):
|
||||
find = False
|
||||
try:
|
||||
server = ldap_server()
|
||||
if not server:
|
||||
return
|
||||
for login in logins:
|
||||
if cls.ldap_search_user(login, server, attrs=[]):
|
||||
find = True
|
||||
break
|
||||
except LDAPException:
|
||||
logger.error('LDAPError when checking password', exc_info=True)
|
||||
if find:
|
||||
raise AccessError(
|
||||
gettext('ldap_authentication.msg_ldap_user_change_password',
|
||||
user=login))
|
||||
|
||||
@classmethod
|
||||
def preprocess_values(cls, mode, values):
|
||||
values = super().preprocess_values(mode, values)
|
||||
if mode == 'create' and values.get('password') and 'login' in values:
|
||||
cls._check_passwd_ldap_user([values['login']])
|
||||
return values
|
||||
|
||||
@classmethod
|
||||
def check_modification(cls, mode, users, values=None, external=False):
|
||||
super().check_modification(
|
||||
mode, users, values=values, external=external)
|
||||
if mode == 'write' and values.get('password'):
|
||||
cls._check_passwd_ldap_user([u.login for u in users])
|
||||
|
||||
@classmethod
|
||||
def _login_ldap(cls, login, parameters):
|
||||
if 'password' not in parameters:
|
||||
msg = gettext('res.msg_user_password', login=login)
|
||||
raise LoginException('password', msg, type='password')
|
||||
password = parameters['password']
|
||||
try:
|
||||
server = ldap_server()
|
||||
if server:
|
||||
uid = config.get(section, 'uid', default='uid')
|
||||
users = cls.ldap_search_user(login, server, attrs=[uid])
|
||||
if users and len(users) == 1:
|
||||
[(dn, attrs)] = users
|
||||
with ldap3.Connection(
|
||||
server, dn, password,
|
||||
auto_bind=ldap3.AUTO_BIND_NONE) as con:
|
||||
if server.ssl is False and server.tls is not None:
|
||||
con.start_tls()
|
||||
if (password and con.bind()):
|
||||
# Use ldap uid so we always get the right case
|
||||
login = attrs.get(uid, [login])[0]
|
||||
user_id = cls._get_login(login)[0]
|
||||
if user_id:
|
||||
return user_id
|
||||
elif config.getboolean(section, 'create_user'):
|
||||
user, = cls.create([{
|
||||
'name': login,
|
||||
'login': login,
|
||||
}])
|
||||
return user.id
|
||||
except LDAPException:
|
||||
logger.error('LDAPError when login', exc_info=True)
|
||||
2
modules/ldap_authentication/tests/__init__.py
Normal file
2
modules/ldap_authentication/tests/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
Binary file not shown.
Binary file not shown.
227
modules/ldap_authentication/tests/test_module.py
Normal file
227
modules/ldap_authentication/tests/test_module.py
Normal file
@@ -0,0 +1,227 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
from unittest.mock import ANY, MagicMock, Mock, patch
|
||||
|
||||
import ldap3
|
||||
|
||||
import trytond.config as config
|
||||
from trytond.modules.ldap_authentication.res import ldap_server, parse_ldap_url
|
||||
from trytond.pool import Pool
|
||||
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
|
||||
|
||||
section = 'ldap_authentication'
|
||||
|
||||
|
||||
class LDAPAuthenticationTestCase(ModuleTestCase):
|
||||
'Test LDAPAuthentication module'
|
||||
module = 'ldap_authentication'
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
methods = config.get('session', 'authentications', default='')
|
||||
config.set('session', 'authentications', 'ldap')
|
||||
self.addCleanup(config.set, 'session', 'authentications', methods)
|
||||
config.add_section(section)
|
||||
self.addCleanup(config.remove_section, section)
|
||||
|
||||
def _get_login(
|
||||
self, uri='ldap://localhost/dc=tryton,dc=org', start_tls=False):
|
||||
pool = Pool()
|
||||
User = pool.get('res.user')
|
||||
config.set(section, 'uri', uri)
|
||||
|
||||
@patch.object(ldap3, 'Connection')
|
||||
@patch.object(User, 'ldap_search_user')
|
||||
def get_login(login, password, find, ldap_search_user, Connection):
|
||||
con = Connection.return_value = MagicMock()
|
||||
con.__enter__.return_value = con
|
||||
con.bind.return_value = bool(find)
|
||||
if find:
|
||||
ldap_search_user.return_value = [('dn', {'uid': [find]})]
|
||||
else:
|
||||
ldap_search_user.return_value = None
|
||||
user_id = User.get_login(login, {
|
||||
'password': password,
|
||||
})
|
||||
if find:
|
||||
Connection.assert_called_with(
|
||||
ANY, ANY, password, auto_bind=ldap3.AUTO_BIND_NONE)
|
||||
if start_tls:
|
||||
con.start_tls.assert_called()
|
||||
else:
|
||||
con.start_tls.assert_not_called()
|
||||
con.bind.assert_called()
|
||||
return user_id
|
||||
return get_login
|
||||
|
||||
@with_transaction()
|
||||
def test_user_get_login_existing_user(self):
|
||||
"Test User.get_login with existing user"
|
||||
pool = Pool()
|
||||
User = pool.get('res.user')
|
||||
user, = User.search([('login', '=', 'admin')])
|
||||
|
||||
get_login = self._get_login()
|
||||
|
||||
self.assertEqual(get_login('admin', 'admin', 'admin'), user.id)
|
||||
self.assertEqual(get_login('AdMiN', 'admin', 'admin'), user.id)
|
||||
|
||||
@with_transaction()
|
||||
def test_user_get_login_unknown_user(self):
|
||||
"test User.get_login with unknown user"
|
||||
get_login = self._get_login()
|
||||
|
||||
self.assertFalse(get_login('foo', 'bar', None))
|
||||
self.assertFalse(get_login('foo', 'bar', 'foo'))
|
||||
|
||||
@with_transaction()
|
||||
def test_user_get_login_create_user(self):
|
||||
"Test User.get_login with user to create"
|
||||
pool = Pool()
|
||||
User = pool.get('res.user')
|
||||
config.set(section, 'create_user', 'True')
|
||||
get_login = self._get_login()
|
||||
|
||||
user_id = get_login('foo', 'bar', 'foo')
|
||||
foo, = User.search([('login', '=', 'foo')])
|
||||
|
||||
self.assertEqual(user_id, foo.id)
|
||||
self.assertEqual(foo.name, 'foo')
|
||||
|
||||
@with_transaction()
|
||||
def test_user_get_login_create_user_case(self):
|
||||
"Test User.get_login with user to create with different case"
|
||||
pool = Pool()
|
||||
User = pool.get('res.user')
|
||||
config.set(section, 'create_user', 'True')
|
||||
get_login = self._get_login()
|
||||
|
||||
user_id = get_login('BaR', 'foo', 'bar')
|
||||
bar, = User.search([('login', '=', 'bar')])
|
||||
|
||||
self.assertEqual(user_id, bar.id)
|
||||
self.assertEqual(bar.name, 'bar')
|
||||
|
||||
@with_transaction()
|
||||
def test_user_get_login_with_tls(self):
|
||||
"Test User.get_login with TLS"
|
||||
pool = Pool()
|
||||
User = pool.get('res.user')
|
||||
user, = User.search([('login', '=', 'admin')])
|
||||
|
||||
get_login = self._get_login(
|
||||
'ldap+tls://localhost/dc=tryton,dc=org', start_tls=True)
|
||||
|
||||
self.assertEqual(get_login('admin', 'admin', 'admin'), user.id)
|
||||
|
||||
@with_transaction()
|
||||
def test_user_get_login_with_ssl(self):
|
||||
"Test User.get_login with SSL"
|
||||
pool = Pool()
|
||||
User = pool.get('res.user')
|
||||
user, = User.search([('login', '=', 'admin')])
|
||||
|
||||
get_login = self._get_login('ldaps://localhost/dc=tryton,dc=org')
|
||||
|
||||
self.assertEqual(get_login('admin', 'admin', 'admin'), user.id)
|
||||
|
||||
def test_parse_ldap_url(self):
|
||||
'Test parse_ldap_url'
|
||||
self.assertEqual(
|
||||
parse_ldap_url('ldap:///o=University%20of%20Michigan,c=US')[1],
|
||||
'o=University of Michigan,c=US')
|
||||
self.assertEqual(
|
||||
parse_ldap_url(
|
||||
'ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US'
|
||||
)[1],
|
||||
'o=University of Michigan,c=US')
|
||||
self.assertEqual(
|
||||
parse_ldap_url(
|
||||
'ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,'
|
||||
'c=US?postalAddress')[2],
|
||||
'postalAddress')
|
||||
self.assertEqual(
|
||||
parse_ldap_url(
|
||||
'ldap://host.com:6666/o=University%20of%20Michigan,'
|
||||
'c=US??sub?(cn=Babs%20Jensen)')[3:5],
|
||||
('sub', '(cn=Babs Jensen)'))
|
||||
self.assertEqual(
|
||||
parse_ldap_url(
|
||||
'ldap:///??sub??bindname=cn=Manager%2co=Foo')[5],
|
||||
{'bindname': ['cn=Manager,o=Foo']})
|
||||
self.assertEqual(
|
||||
parse_ldap_url(
|
||||
'ldap:///??sub??!bindname=cn=Manager%2co=Foo')[5],
|
||||
{'!bindname': ['cn=Manager,o=Foo']})
|
||||
|
||||
@unittest.skipIf(
|
||||
sys.version_info < (3, 8), "call_args does not have args nor kwargs")
|
||||
def test_ldap_server(self):
|
||||
"Test ldap_server"
|
||||
for uri, (host, tls) in [
|
||||
('ldap://localhost/dc=tryton,dc=org',
|
||||
('ldap://localhost:389', None)),
|
||||
('ldaps://localhost/dc=tryton,dc=org',
|
||||
('ldaps://localhost:636', True)),
|
||||
('ldap+tls://localhost/dc=tryton,dc=org',
|
||||
('ldap://localhost:389', True)),
|
||||
]:
|
||||
config.set(section, 'uri', uri)
|
||||
|
||||
with patch('ldap3.Server') as Server:
|
||||
ldap_server()
|
||||
|
||||
self.assertEqual(Server.call_args.args, (host,))
|
||||
if tls:
|
||||
self.assertTrue(Server.call_args.kwargs.get('tls'))
|
||||
else:
|
||||
self.assertFalse(Server.call_args.kwargs.get('tls'))
|
||||
|
||||
def _ldap_search_user(
|
||||
self, uri='ldap://localhost/dc=tryton,dc=org',
|
||||
auto_bind=ldap3.AUTO_BIND_DEFAULT):
|
||||
pool = Pool()
|
||||
User = pool.get('res.user')
|
||||
config.set(section, 'uri', uri)
|
||||
|
||||
@patch.object(ldap3, 'Connection')
|
||||
def ldap_search_user(login, attrs, Connection):
|
||||
con = Connection.return_value = MagicMock()
|
||||
con.__enter__.return_value = con
|
||||
con.entries = [Mock()]
|
||||
server = ldap_server()
|
||||
User.ldap_search_user(login, server, attrs=attrs)
|
||||
Connection.assert_called_with(
|
||||
ANY, ANY, ANY, auto_bind=auto_bind)
|
||||
con.search.assert_called()
|
||||
return ldap_search_user
|
||||
|
||||
@with_transaction()
|
||||
def test_ldap_search_user(self):
|
||||
"Test User.ldap_search_user"
|
||||
ldap_search_user = self._ldap_search_user()
|
||||
|
||||
ldap_search_user('admin', None)
|
||||
|
||||
@with_transaction()
|
||||
def test_ldap_search_user_with_tls(self):
|
||||
"Test User.ldap_search_user with TSL"
|
||||
ldap_search_user = self._ldap_search_user(
|
||||
'ldap+tls://localhost/dc=tryton,dc=org',
|
||||
ldap3.AUTO_BIND_TLS_BEFORE_BIND)
|
||||
|
||||
ldap_search_user('admin', None)
|
||||
|
||||
@with_transaction()
|
||||
def test_ldap_search_user_with_ssl(self):
|
||||
"Test User.ldap_search_user with SSL"
|
||||
ldap_search_user = self._ldap_search_user(
|
||||
'ldaps://localhost/dc=tryton,dc=org')
|
||||
|
||||
ldap_search_user('admin', None)
|
||||
|
||||
|
||||
del ModuleTestCase
|
||||
11
modules/ldap_authentication/tryton.cfg
Normal file
11
modules/ldap_authentication/tryton.cfg
Normal file
@@ -0,0 +1,11 @@
|
||||
[tryton]
|
||||
version=7.8.0
|
||||
depends:
|
||||
ir
|
||||
res
|
||||
xml:
|
||||
message.xml
|
||||
|
||||
[register]
|
||||
model:
|
||||
res.User
|
||||
Reference in New Issue
Block a user