annotate rhodecode/lib/auth_ldap.py @ 1099:bc3dafd0e24c beta

fixed test env creator
author Marcin Kuzminski <marcin@python-works.com>
date Sun, 27 Feb 2011 02:03:49 +0100
parents b232a36cc51f
children 6a9a5af49b97
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
713
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
1 #!/usr/bin/env python
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
2 # encoding: utf-8
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
3 # ldap authentication lib
902
07a6e8c65526 fixed copyright year to 2011
Marcin Kuzminski <marcin@python-works.com>
parents: 794
diff changeset
4 # Copyright (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
713
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
5 #
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
6 # This program is free software; you can redistribute it and/or
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
7 # modify it under the terms of the GNU General Public License
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
8 # as published by the Free Software Foundation; version 2
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
9 # of the License or (at your opinion) any later version of the license.
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
10 #
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
11 # This program is distributed in the hope that it will be useful,
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
14 # GNU General Public License for more details.
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
15 #
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
16 # You should have received a copy of the GNU General Public License
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
17 # along with this program; if not, write to the Free Software
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
19 # MA 02110-1301, USA.
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
20 """
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
21 Created on Nov 17, 2010
700
07fd56c36bfe added basic ldap auth lib
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
22
713
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
23 @author: marcink
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
24 """
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
25
713
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
26 from rhodecode.lib.exceptions import *
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
27 import logging
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
28
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
29 log = logging.getLogger(__name__)
700
07fd56c36bfe added basic ldap auth lib
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
30
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
31 try:
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
32 import ldap
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
33 except ImportError:
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
34 pass
700
07fd56c36bfe added basic ldap auth lib
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
35
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
36 class AuthLdap(object):
700
07fd56c36bfe added basic ldap auth lib
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
37
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
38 def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='',
991
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
39 use_ldaps=False, tls_reqcert='DEMAND', ldap_version=3,
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
40 ldap_filter='(&(objectClass=user)(!(objectClass=computer)))',
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
41 search_scope='SUBTREE',
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
42 attr_login='uid'):
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
43 self.ldap_version = ldap_version
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
44 if use_ldaps:
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
45 port = port or 689
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
46 self.LDAP_USE_LDAPS = use_ldaps
991
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
47 self.TLS_REQCERT = ldap.__dict__['OPT_X_TLS_' + tls_reqcert]
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
48 self.LDAP_SERVER_ADDRESS = server
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
49 self.LDAP_SERVER_PORT = port
700
07fd56c36bfe added basic ldap auth lib
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
50
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
51 #USE FOR READ ONLY BIND TO LDAP SERVER
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
52 self.LDAP_BIND_DN = bind_dn
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
53 self.LDAP_BIND_PASS = bind_pass
700
07fd56c36bfe added basic ldap auth lib
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
54
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
55 ldap_server_type = 'ldap'
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
56 if self.LDAP_USE_LDAPS:ldap_server_type = ldap_server_type + 's'
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
57 self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type,
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
58 self.LDAP_SERVER_ADDRESS,
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
59 self.LDAP_SERVER_PORT)
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
60
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
61 self.BASE_DN = base_dn
991
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
62 self.LDAP_FILTER = ldap_filter
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
63 self.SEARCH_SCOPE = ldap.__dict__['SCOPE_' + search_scope]
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
64 self.attr_login = attr_login
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
65
700
07fd56c36bfe added basic ldap auth lib
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
66
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
67 def authenticate_ldap(self, username, password):
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
68 """Authenticate a user via LDAP and return his/her LDAP properties.
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
69
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
70 Raises AuthenticationError if the credentials are rejected, or
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
71 EnvironmentError if the LDAP server can't be reached.
701
6602bf1c5546 ldap two phase auth fix
Marcin Kuzminski <marcin@python-works.com>
parents: 700
diff changeset
72
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
73 :param username: username
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
74 :param password: password
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
75 """
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
76
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
77 from rhodecode.lib.helpers import chop_at
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
78
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
79 uid = chop_at(username, "@%s" % self.LDAP_SERVER_ADDRESS)
775
aaf2fc59a39a fixes #77 and adds extendable base Dn with custom uid specification
Marcin Kuzminski <marcin@python-works.com>
parents: 739
diff changeset
80
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
81 if "," in username:
713
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
82 raise LdapUsernameError("invalid character in username: ,")
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
83 try:
739
554ed64953ff fixes #76 added confirmation dialog for user removal.
Marcin Kuzminski <marcin@python-works.com>
parents: 713
diff changeset
84 ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')
991
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
85 ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF)
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
86 ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON)
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
87 ldap.set_option(ldap.OPT_TIMEOUT, 20)
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
88 ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 10)
991
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
89 ldap.set_option(ldap.OPT_TIMELIMIT, 15)
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
90 if self.LDAP_USE_LDAPS:
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
91 ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, self.TLS_REQCERT)
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
92 server = ldap.initialize(self.LDAP_SERVER)
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
93 if self.ldap_version == 2:
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
94 server.protocol = ldap.VERSION2
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
95 else:
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
96 server.protocol = ldap.VERSION3
700
07fd56c36bfe added basic ldap auth lib
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
97
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
98 if self.LDAP_BIND_DN and self.LDAP_BIND_PASS:
794
22eca93bea97 fixes a bug with two-pass ldap auth (thanks for TK Soh for that)
Marcin Kuzminski <marcin@python-works.com>
parents: 775
diff changeset
99 server.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS)
700
07fd56c36bfe added basic ldap auth lib
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
100
991
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
101 filt = '(&%s(%s=%s))' % (self.LDAP_FILTER, self.attr_login, username)
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
102 log.debug("Authenticating %r filt %s at %s", self.BASE_DN, filt, self.LDAP_SERVER)
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
103 lobjects = server.search_ext_s(self.BASE_DN, self.SEARCH_SCOPE, filt)
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
104
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
105 if not lobjects:
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
106 raise ldap.NO_SUCH_OBJECT()
775
aaf2fc59a39a fixes #77 and adds extendable base Dn with custom uid specification
Marcin Kuzminski <marcin@python-works.com>
parents: 739
diff changeset
107
991
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
108 for (dn, attrs) in lobjects:
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
109 try:
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
110 server.simple_bind_s(dn, password)
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
111 break
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
112
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
113 except ldap.INVALID_CREDENTIALS, e:
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
114 log.debug("LDAP rejected password for user '%s' (%s): %s", uid, username, dn)
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
115
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
116 else:
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
117 log.debug("No matching LDAP objecs for authentication of '%s' (%s)", uid, username)
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
118 raise LdapPasswordError()
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
119
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
120 except ldap.NO_SUCH_OBJECT, e:
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
121 log.debug("LDAP says no such user '%s' (%s)", uid, username)
713
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
122 raise LdapUsernameError()
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
123 except ldap.SERVER_DOWN, e:
713
1bb0fcdec895 fixed #72 show warning on removal when user still is owner of existing repositories
Marcin Kuzminski <marcin@python-works.com>
parents: 705
diff changeset
124 raise LdapConnectionError("LDAP can't access authentication server")
705
9e9f1b919c0c implements #60, ldap configuration and authentication.
Marcin Kuzminski <marcin@python-works.com>
parents: 701
diff changeset
125
991
b232a36cc51f Improve LDAP authentication
Thayne Harbaugh <thayne@fusionio.com>
parents: 902
diff changeset
126 return (dn, attrs)