1 ##############################################################################
3 # OpenERP, Open Source Management Solution
4 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
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.
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.
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/>.
19 ##############################################################################
21 from osv import fields, osv
25 from service import security
27 from ldap.filter import filter_format
30 class CompanyLDAP(osv.osv):
31 _name = 'res.company.ldap'
33 _rec_name = 'ldap_server'
35 'sequence': fields.integer('Sequence'),
36 'company': fields.many2one('res.company', 'Company', required=True,
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"),
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,
59 class res_company(osv.osv):
60 _inherit = "res.company"
62 'ldaps': fields.one2many('res.company.ldap', 'company', 'LDAP Parameters'),
67 _inherit = "res.users"
68 def login(self, db, login, password):
71 # empty passwords are disallowed for obvious security reasons
74 ret = super(users,self).login(db, login, password)
77 logger = logging.getLogger('orm.ldap')
78 pool = pooler.get_pool(db)
79 cr = pooler.get_db(db).cursor()
80 action_obj = pool.get('ir.actions.actions')
82 SELECT id, company, ldap_server, ldap_server_port, ldap_binddn, ldap_password,
83 ldap_filter, ldap_base, "user", create_user
85 WHERE ldap_server != '' and ldap_binddn != '' ORDER BY sequence""")
86 for res_company_ldap in cr.dictfetchall():
87 logger.debug(res_company_ldap)
89 l = ldap.open(res_company_ldap['ldap_server'], res_company_ldap['ldap_server_port'])
90 if l.simple_bind_s(res_company_ldap['ldap_binddn'], res_company_ldap['ldap_password']):
91 base = res_company_ldap['ldap_base']
92 scope = ldap.SCOPE_SUBTREE
93 filter = filter_format(res_company_ldap['ldap_filter'], (login,))
94 retrieve_attributes = None
95 result_id = l.search(base, scope, filter, retrieve_attributes)
97 result_type, result_data = l.result(result_id, timeout)
100 if result_type == ldap.RES_SEARCH_RESULT and len(result_data) == 1:
101 dn = result_data[0][0]
103 name = result_data[0][1]['cn'][0]
104 if l.bind_s(dn, password):
106 cr.execute("SELECT id FROM res_users WHERE login=%s",(tools.ustr(login),))
112 if not res_company_ldap['create_user']:
114 action_id = action_obj.search(cr, 1, [('usage', '=', 'menu')])[0]
115 if res_company_ldap['user']:
116 res = self.copy(cr, 1, res_company_ldap['user'],
117 default={'active': True})
118 self.write(cr, 1, res, {
120 'login': login.encode('utf-8'),
121 'company_id': res_company_ldap['company'],
124 res = self.create(cr, 1, {
126 'login': login.encode('utf-8'),
127 'company_id': res_company_ldap['company'],
128 'action_id': action_id,
129 'menu_id': action_id,
136 logger.warning("Cannot auth", exc_info=True)
141 def check(self, db, uid, passwd):
143 return super(users,self).check(db, uid, passwd)
144 except security.ExceptionNoTb: # AccessDenied
148 # empty passwords disallowed for obvious security reasons
149 raise security.ExceptionNoTb('AccessDenied')
151 cr = pooler.get_db(db).cursor()
152 user = self.browse(cr, 1, uid)
153 logger = logging.getLogger('orm.ldap')
154 if user and user.company_id.ldaps:
155 for res_company_ldap in user.company_id.ldaps:
157 l = ldap.open(res_company_ldap.ldap_server, res_company_ldap.ldap_server_port)
158 if l.simple_bind_s(res_company_ldap.ldap_binddn,
159 res_company_ldap.ldap_password):
160 base = res_company_ldap.ldap_base
161 scope = ldap.SCOPE_SUBTREE
162 filter = filter_format(res_company_ldap.ldap_filter, (user.login,))
163 retrieve_attributes = None
164 result_id = l.search(base, scope, filter, retrieve_attributes)
166 result_type, result_data = l.result(result_id, timeout)
167 if result_data and result_type == ldap.RES_SEARCH_RESULT and len(result_data) == 1:
168 dn = result_data[0][0]
169 # some LDAP servers allow anonymous binding with blank passwords,
170 # but these have been rejected above, so we're safe to use bind()
171 if l.bind_s(dn, passwd):
173 self._uid_cache.setdefault(db, {})[uid] = passwd
178 logger.warning('cannot check', exc_info=True)
181 raise security.ExceptionNoTb('AccessDenied')
184 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: