auth_ldap.py
104 lines
| 3.6 KiB
| text/x-python
|
PythonLexer
r713 | #!/usr/bin/env python | |||
# encoding: utf-8 | ||||
# ldap authentication lib | ||||
r1136 | # Copyright (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> | |||
r713 | # | |||
# This program is free software; you can redistribute it and/or | ||||
# modify it under the terms of the GNU General Public License | ||||
# as published by the Free Software Foundation; version 2 | ||||
# of the License or (at your opinion) any later version of the license. | ||||
# | ||||
# 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, write to the Free Software | ||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||||
# MA 02110-1301, USA. | ||||
""" | ||||
Created on Nov 17, 2010 | ||||
r700 | ||||
r713 | @author: marcink | |||
""" | ||||
r705 | ||||
r713 | from rhodecode.lib.exceptions import * | |||
r705 | import logging | |||
log = logging.getLogger(__name__) | ||||
r700 | ||||
r705 | try: | |||
import ldap | ||||
except ImportError: | ||||
pass | ||||
r700 | ||||
r705 | class AuthLdap(object): | |||
r700 | ||||
r705 | def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='', | |||
use_ldaps=False, ldap_version=3): | ||||
self.ldap_version = ldap_version | ||||
if use_ldaps: | ||||
port = port or 689 | ||||
self.LDAP_USE_LDAPS = use_ldaps | ||||
self.LDAP_SERVER_ADDRESS = server | ||||
self.LDAP_SERVER_PORT = port | ||||
r700 | ||||
r705 | #USE FOR READ ONLY BIND TO LDAP SERVER | |||
self.LDAP_BIND_DN = bind_dn | ||||
self.LDAP_BIND_PASS = bind_pass | ||||
r700 | ||||
r705 | ldap_server_type = 'ldap' | |||
if self.LDAP_USE_LDAPS:ldap_server_type = ldap_server_type + 's' | ||||
self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type, | ||||
self.LDAP_SERVER_ADDRESS, | ||||
self.LDAP_SERVER_PORT) | ||||
self.BASE_DN = base_dn | ||||
r700 | ||||
r705 | def authenticate_ldap(self, username, password): | |||
"""Authenticate a user via LDAP and return his/her LDAP properties. | ||||
Raises AuthenticationError if the credentials are rejected, or | ||||
EnvironmentError if the LDAP server can't be reached. | ||||
r701 | ||||
r705 | :param username: username | |||
:param password: password | ||||
""" | ||||
from rhodecode.lib.helpers import chop_at | ||||
uid = chop_at(username, "@%s" % self.LDAP_SERVER_ADDRESS) | ||||
r775 | ||||
r705 | if "," in username: | |||
r713 | raise LdapUsernameError("invalid character in username: ,") | |||
r705 | try: | |||
r739 | ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts') | |||
r705 | ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 10) | |||
server = ldap.initialize(self.LDAP_SERVER) | ||||
if self.ldap_version == 2: | ||||
server.protocol = ldap.VERSION2 | ||||
else: | ||||
server.protocol = ldap.VERSION3 | ||||
r700 | ||||
r705 | if self.LDAP_BIND_DN and self.LDAP_BIND_PASS: | |||
r794 | server.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS) | |||
r700 | ||||
r775 | dn = self.BASE_DN % {'user':uid} | |||
log.debug("Authenticating %r at %s", dn, self.LDAP_SERVER) | ||||
r705 | server.simple_bind_s(dn, password) | |||
r775 | ||||
r705 | properties = server.search_s(dn, ldap.SCOPE_SUBTREE) | |||
if not properties: | ||||
raise ldap.NO_SUCH_OBJECT() | ||||
except ldap.NO_SUCH_OBJECT, e: | ||||
log.debug("LDAP says no such user '%s' (%s)", uid, username) | ||||
r713 | raise LdapUsernameError() | |||
r705 | except ldap.INVALID_CREDENTIALS, e: | |||
log.debug("LDAP rejected password for user '%s' (%s)", uid, username) | ||||
r713 | raise LdapPasswordError() | |||
r705 | except ldap.SERVER_DOWN, e: | |||
r713 | raise LdapConnectionError("LDAP can't access authentication server") | |||
r705 | ||||
return properties[0] | ||||