Launchpad automatic translations update.
[odoo/odoo.git] / addons / users_ldap / users_ldap.py
1 ##############################################################################
2 #    
3 #    OpenERP, Open Source Management Solution
4 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
5 #
6 #    This program is free software: you can redistribute it and/or modify
7 #    it under the terms of the GNU Affero General Public License as
8 #    published by the Free Software Foundation, either version 3 of the
9 #    License, or (at your option) any later version.
10 #
11 #    This program is distributed in the hope that it will be useful,
12 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #    GNU Affero General Public License for more details.
15 #
16 #    You should have received a copy of the GNU Affero General Public License
17 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
18 #
19 ##############################################################################
20
21 from osv import fields, osv
22 import pooler
23 import tools
24 import logging
25 from service import security
26 import ldap
27 from ldap.filter import filter_format
28
29
30 class CompanyLDAP(osv.osv):
31     _name = 'res.company.ldap'
32     _order = 'sequence'
33     _rec_name = 'ldap_server'
34     _columns = {
35         'sequence': fields.integer('Sequence'),
36         'company': fields.many2one('res.company', 'Company', required=True,
37             ondelete='cascade'),
38         'ldap_server': fields.char('LDAP Server address', size=64, required=True),
39         'ldap_server_port': fields.integer('LDAP Server port', required=True),
40         'ldap_binddn': fields.char('LDAP binddn', size=64, required=True),
41         'ldap_password': fields.char('LDAP password', size=64, required=True),
42         'ldap_filter': fields.char('LDAP filter', size=64, required=True),
43         'ldap_base': fields.char('LDAP base', size=64, required=True),
44         'user': fields.many2one('res.users', 'Model User',
45             help="Model used for user creation"),
46         'create_user': fields.boolean('Create user',
47             help="Create the user if not in database"),
48     }
49     _defaults = {
50         'ldap_server': lambda *a: '127.0.0.1',
51         'ldap_server_port': lambda *a: 389,
52         'sequence': lambda *a: 10,
53         'create_user': lambda *a: True,
54     }
55
56 CompanyLDAP()
57
58
59 class res_company(osv.osv):
60     _inherit = "res.company"
61     _columns = {
62         'ldaps': fields.one2many('res.company.ldap', 'company', 'LDAP Parameters'),
63     }
64 res_company()
65
66 class users(osv.osv):
67     _inherit = "res.users"
68     def login(self, db, login, password):
69         ret = super(users,self).login(db, login, password)
70         if ret:
71             return ret
72         logger = logging.getLogger('orm.ldap')
73         pool = pooler.get_pool(db)
74         cr = pooler.get_db(db).cursor()
75         action_obj = pool.get('ir.actions.actions')
76         cr.execute("""
77             SELECT id, company, ldap_server, ldap_server_port, ldap_binddn, ldap_password,
78                    ldap_filter, ldap_base, "user", create_user
79             FROM res_company_ldap
80             WHERE ldap_server != '' and ldap_binddn != '' ORDER BY sequence""")
81         for res_company_ldap in cr.dictfetchall():
82             logger.debug(res_company_ldap)
83             try:
84                 l = ldap.open(res_company_ldap['ldap_server'], res_company_ldap['ldap_server_port'])
85                 if l.simple_bind_s(res_company_ldap['ldap_binddn'], res_company_ldap['ldap_password']):
86                     base = res_company_ldap['ldap_base']
87                     scope = ldap.SCOPE_SUBTREE
88                     filter = filter_format(res_company_ldap['ldap_filter'], (login,))
89                     retrieve_attributes = None
90                     result_id = l.search(base, scope, filter, retrieve_attributes)
91                     timeout = 60
92                     result_type, result_data = l.result(result_id, timeout)
93                     if not result_data:
94                         continue
95                     if result_type == ldap.RES_SEARCH_RESULT and len(result_data) == 1:
96                         dn = result_data[0][0]
97                         logger.debug(dn)
98                         name = result_data[0][1]['cn'][0]
99                         if l.bind_s(dn, password):
100                             l.unbind()
101                             cr.execute("SELECT id FROM res_users WHERE login=%s",(tools.ustr(login),))
102                             res = cr.fetchone()
103                             logger.debug(res)
104                             if res:
105                                 cr.close()
106                                 return res[0]
107                             if not res_company_ldap['create_user']:
108                                 continue
109                             action_id = action_obj.search(cr, 1, [('usage', '=', 'menu')])[0]
110                             if res_company_ldap['user']:
111                                 res = self.copy(cr, 1, res_company_ldap['user'],
112                                         default={'active': True})
113                                 self.write(cr, 1, res, {
114                                     'name': name,
115                                     'login': login.encode('utf-8'),
116                                     'company_id': res_company_ldap['company'],
117                                     })
118                             else:
119                                 res = self.create(cr, 1, {
120                                     'name': name,
121                                     'login': login.encode('utf-8'),
122                                     'company_id': res_company_ldap['company'],
123                                     'action_id': action_id,
124                                     'menu_id': action_id,
125                                     })
126                             cr.commit()
127                             cr.close()
128                             return res
129                     l.unbind()
130             except Exception, e:
131                 logger.warning("Cannot auth", exc_info=True)
132                 continue
133         cr.close()
134         return False
135
136     def check(self, db, uid, passwd):
137         try:
138             return super(users,self).check(db, uid, passwd)
139         except security.ExceptionNoTb: # AccessDenied
140             pass
141         cr = pooler.get_db(db).cursor()
142         user = self.browse(cr, 1, uid)
143         logger = logging.getLogger('orm.ldap')
144         if user and user.company_id.ldaps:
145             for res_company_ldap in user.company_id.ldaps:
146                 try:
147                     l = ldap.open(res_company_ldap.ldap_server, res_company_ldap.ldap_server_port)
148                     if l.simple_bind_s(res_company_ldap.ldap_binddn,
149                             res_company_ldap.ldap_password):
150                         base = res_company_ldap.ldap_base
151                         scope = ldap.SCOPE_SUBTREE
152                         filter = filter_format(res_company_ldap.ldap_filter, (user.login,))
153                         retrieve_attributes = None
154                         result_id = l.search(base, scope, filter, retrieve_attributes)
155                         timeout = 60
156                         result_type, result_data = l.result(result_id, timeout)
157                         if result_data and result_type == ldap.RES_SEARCH_RESULT and len(result_data) == 1:
158                             dn = result_data[0][0]
159                             if l.bind_s(dn, passwd):
160                                 l.unbind()
161                                 self._uid_cache.setdefault(db, {})[uid] = passwd
162                                 cr.close()
163                                 return True
164                         l.unbind()
165                 except Exception, e:
166                     logger.warning('cannot check', exc_info=True)
167                     pass
168         cr.close()
169         raise security.ExceptionNoTb('AccessDenied')
170         
171 users()
172 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
173