##// END OF EJS Templates
Fetch entry after successful bind for being able to read its attributes.
"Lorenzo M. Catucci" -
r1287:28060f0a beta
parent child Browse files
Show More
@@ -1,128 +1,129 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # ldap authentication lib
3 # ldap authentication lib
4 # Copyright (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software: you can redistribute it and/or modify
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
9 # (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """
18 """
19 Created on Nov 17, 2010
19 Created on Nov 17, 2010
20
20
21 @author: marcink
21 @author: marcink
22 """
22 """
23
23
24 from rhodecode.lib.exceptions import *
24 from rhodecode.lib.exceptions import *
25 import logging
25 import logging
26
26
27 log = logging.getLogger(__name__)
27 log = logging.getLogger(__name__)
28
28
29 try:
29 try:
30 import ldap
30 import ldap
31 except ImportError:
31 except ImportError:
32 pass
32 pass
33
33
34 class AuthLdap(object):
34 class AuthLdap(object):
35
35
36 def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='',
36 def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='',
37 use_ldaps=False, tls_reqcert='DEMAND', ldap_version=3,
37 use_ldaps=False, tls_reqcert='DEMAND', ldap_version=3,
38 ldap_filter='(&(objectClass=user)(!(objectClass=computer)))',
38 ldap_filter='(&(objectClass=user)(!(objectClass=computer)))',
39 search_scope='SUBTREE',
39 search_scope='SUBTREE',
40 attr_login='uid'):
40 attr_login='uid'):
41 self.ldap_version = ldap_version
41 self.ldap_version = ldap_version
42 if use_ldaps:
42 if use_ldaps:
43 port = port or 689
43 port = port or 689
44 self.LDAP_USE_LDAPS = use_ldaps
44 self.LDAP_USE_LDAPS = use_ldaps
45 self.TLS_REQCERT = ldap.__dict__['OPT_X_TLS_' + tls_reqcert]
45 self.TLS_REQCERT = ldap.__dict__['OPT_X_TLS_' + tls_reqcert]
46 self.LDAP_SERVER_ADDRESS = server
46 self.LDAP_SERVER_ADDRESS = server
47 self.LDAP_SERVER_PORT = port
47 self.LDAP_SERVER_PORT = port
48
48
49 #USE FOR READ ONLY BIND TO LDAP SERVER
49 #USE FOR READ ONLY BIND TO LDAP SERVER
50 self.LDAP_BIND_DN = bind_dn
50 self.LDAP_BIND_DN = bind_dn
51 self.LDAP_BIND_PASS = bind_pass
51 self.LDAP_BIND_PASS = bind_pass
52
52
53 ldap_server_type = 'ldap'
53 ldap_server_type = 'ldap'
54 if self.LDAP_USE_LDAPS:ldap_server_type = ldap_server_type + 's'
54 if self.LDAP_USE_LDAPS:ldap_server_type = ldap_server_type + 's'
55 self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type,
55 self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type,
56 self.LDAP_SERVER_ADDRESS,
56 self.LDAP_SERVER_ADDRESS,
57 self.LDAP_SERVER_PORT)
57 self.LDAP_SERVER_PORT)
58
58
59 self.BASE_DN = base_dn
59 self.BASE_DN = base_dn
60 self.LDAP_FILTER = ldap_filter
60 self.LDAP_FILTER = ldap_filter
61 self.SEARCH_SCOPE = ldap.__dict__['SCOPE_' + search_scope]
61 self.SEARCH_SCOPE = ldap.__dict__['SCOPE_' + search_scope]
62 self.attr_login = attr_login
62 self.attr_login = attr_login
63
63
64
64
65 def authenticate_ldap(self, username, password):
65 def authenticate_ldap(self, username, password):
66 """Authenticate a user via LDAP and return his/her LDAP properties.
66 """Authenticate a user via LDAP and return his/her LDAP properties.
67
67
68 Raises AuthenticationError if the credentials are rejected, or
68 Raises AuthenticationError if the credentials are rejected, or
69 EnvironmentError if the LDAP server can't be reached.
69 EnvironmentError if the LDAP server can't be reached.
70
70
71 :param username: username
71 :param username: username
72 :param password: password
72 :param password: password
73 """
73 """
74
74
75 from rhodecode.lib.helpers import chop_at
75 from rhodecode.lib.helpers import chop_at
76
76
77 uid = chop_at(username, "@%s" % self.LDAP_SERVER_ADDRESS)
77 uid = chop_at(username, "@%s" % self.LDAP_SERVER_ADDRESS)
78
78
79 if "," in username:
79 if "," in username:
80 raise LdapUsernameError("invalid character in username: ,")
80 raise LdapUsernameError("invalid character in username: ,")
81 try:
81 try:
82 ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')
82 ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')
83 ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF)
83 ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF)
84 ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON)
84 ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON)
85 ldap.set_option(ldap.OPT_TIMEOUT, 20)
85 ldap.set_option(ldap.OPT_TIMEOUT, 20)
86 ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 10)
86 ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 10)
87 ldap.set_option(ldap.OPT_TIMELIMIT, 15)
87 ldap.set_option(ldap.OPT_TIMELIMIT, 15)
88 if self.LDAP_USE_LDAPS:
88 if self.LDAP_USE_LDAPS:
89 ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, self.TLS_REQCERT)
89 ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, self.TLS_REQCERT)
90 server = ldap.initialize(self.LDAP_SERVER)
90 server = ldap.initialize(self.LDAP_SERVER)
91 if self.ldap_version == 2:
91 if self.ldap_version == 2:
92 server.protocol = ldap.VERSION2
92 server.protocol = ldap.VERSION2
93 else:
93 else:
94 server.protocol = ldap.VERSION3
94 server.protocol = ldap.VERSION3
95
95
96 if self.LDAP_BIND_DN and self.LDAP_BIND_PASS:
96 if self.LDAP_BIND_DN and self.LDAP_BIND_PASS:
97 server.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS)
97 server.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS)
98
98
99 filt = '(&%s(%s=%s))' % (self.LDAP_FILTER, self.attr_login, username)
99 filt = '(&%s(%s=%s))' % (self.LDAP_FILTER, self.attr_login, username)
100 log.debug("Authenticating %r filt %s at %s", self.BASE_DN,
100 log.debug("Authenticating %r filt %s at %s", self.BASE_DN,
101 filt, self.LDAP_SERVER)
101 filt, self.LDAP_SERVER)
102 lobjects = server.search_ext_s(self.BASE_DN, self.SEARCH_SCOPE,
102 lobjects = server.search_ext_s(self.BASE_DN, self.SEARCH_SCOPE,
103 filt)
103 filt)
104
104
105 if not lobjects:
105 if not lobjects:
106 raise ldap.NO_SUCH_OBJECT()
106 raise ldap.NO_SUCH_OBJECT()
107
107
108 for (dn, attrs) in lobjects:
108 for (dn, _attrs) in lobjects:
109 try:
109 try:
110 server.simple_bind_s(dn, password)
110 server.simple_bind_s(dn, password)
111 attrs = server.search_ext_s(dn, ldap.SCOPE_BASE, '(objectClass=*)')[0][1]
111 break
112 break
112
113
113 except ldap.INVALID_CREDENTIALS, e:
114 except ldap.INVALID_CREDENTIALS, e:
114 log.debug("LDAP rejected password for user '%s' (%s): %s",
115 log.debug("LDAP rejected password for user '%s' (%s): %s",
115 uid, username, dn)
116 uid, username, dn)
116
117
117 else:
118 else:
118 log.debug("No matching LDAP objects for authentication "
119 log.debug("No matching LDAP objects for authentication "
119 "of '%s' (%s)", uid, username)
120 "of '%s' (%s)", uid, username)
120 raise LdapPasswordError()
121 raise LdapPasswordError()
121
122
122 except ldap.NO_SUCH_OBJECT, e:
123 except ldap.NO_SUCH_OBJECT, e:
123 log.debug("LDAP says no such user '%s' (%s)", uid, username)
124 log.debug("LDAP says no such user '%s' (%s)", uid, username)
124 raise LdapUsernameError()
125 raise LdapUsernameError()
125 except ldap.SERVER_DOWN, e:
126 except ldap.SERVER_DOWN, e:
126 raise LdapConnectionError("LDAP can't access authentication server")
127 raise LdapConnectionError("LDAP can't access authentication server")
127
128
128 return (dn, attrs)
129 return (dn, attrs)
General Comments 0
You need to be logged in to leave comments. Login now