You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
6.8 KiB

  1. # -*- coding: utf-8 -*-
  2. ##############################################################################
  3. #
  4. # This module copyright (C) 2015 Therp BV (<http://therp.nl>).
  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. from openerp import _, models, fields, api, exceptions
  21. import logging
  22. _logger = logging.getLogger(__name__)
  23. try:
  24. import ldap
  25. import ldap.modlist
  26. except ImportError:
  27. _logger.debug('Can not `from ldap.filter import filter_format`.')
  28. class ResUsers(models.Model):
  29. _inherit = 'res.users'
  30. ldap_entry_dn = fields.Char('LDAP DN', readonly=True)
  31. is_ldap_user = fields.Boolean(
  32. 'LDAP user', compute='_compute_is_ldap_user', default=True)
  33. @api.model
  34. @api.returns('self', lambda record: record.id)
  35. def create(self, values):
  36. result = super(ResUsers, self).create(values)
  37. result.push_to_ldap(values)
  38. return result
  39. @api.multi
  40. def write(self, values):
  41. result = super(ResUsers, self).write(values)
  42. self.push_to_ldap(values)
  43. return result
  44. @api.multi
  45. def _push_to_ldap_possible(self, values):
  46. return bool(self._get_ldap_configuration())
  47. @api.multi
  48. def _get_ldap_configuration(self):
  49. self.ensure_one()
  50. return self.sudo().company_id.ldaps.filtered('create_ldap_entry')[:1]
  51. @api.multi
  52. def _get_ldap_values(self, values):
  53. self.ensure_one()
  54. conf = self._get_ldap_configuration()
  55. result = {}
  56. for mapping in conf.create_ldap_entry_field_mappings:
  57. field_name = mapping.field_id.name
  58. if field_name not in values or not values[field_name]:
  59. continue
  60. result[mapping.attribute] = [str(values[field_name])]
  61. if result:
  62. result['objectClass'] = conf.create_ldap_entry_objectclass\
  63. .encode('utf-8').split(',')
  64. return result
  65. @api.multi
  66. def _get_ldap_dn(self, values):
  67. self.ensure_one()
  68. conf = self._get_ldap_configuration()
  69. dn = conf.create_ldap_entry_field_mappings.filtered('use_for_dn')
  70. assert dn, 'No DN attribute mapping given!'
  71. assert self[dn.field_id.name], 'DN attribute empty!'
  72. return '%s=%s,%s' % (
  73. dn.attribute,
  74. ldap.dn.escape_dn_chars(self[dn.field_id.name].encode('utf-8')),
  75. conf.create_ldap_entry_base or conf.ldap_base)
  76. @api.multi
  77. def push_to_ldap(self, values):
  78. for this in self:
  79. if not values.get('is_ldap_user') and not this.is_ldap_user:
  80. continue
  81. if not this._push_to_ldap_possible(values):
  82. continue
  83. ldap_values = this._get_ldap_values(values)
  84. if not ldap_values:
  85. continue
  86. ldap_configuration = this._get_ldap_configuration()
  87. ldap_connection = ldap_configuration.connect(
  88. ldap_configuration.read()[0])
  89. ldap_connection.simple_bind_s(
  90. (ldap_configuration.ldap_binddn or '').encode('utf-8'),
  91. (ldap_configuration.ldap_password or '').encode('utf-8'))
  92. try:
  93. if not this.ldap_entry_dn:
  94. this._push_to_ldap_create(
  95. ldap_connection, ldap_configuration, values,
  96. ldap_values)
  97. if this.ldap_entry_dn:
  98. this._push_to_ldap_write(
  99. ldap_connection, ldap_configuration, values,
  100. ldap_values)
  101. except ldap.LDAPError as e:
  102. _logger.exception(e)
  103. raise exceptions.Warning(_('Error'), e.message)
  104. finally:
  105. ldap_connection.unbind_s()
  106. @api.multi
  107. def _push_to_ldap_create(self, ldap_connection, ldap_configuration, values,
  108. ldap_values):
  109. self.ensure_one()
  110. dn = self._get_ldap_dn(values)
  111. ldap_connection.add_s(
  112. dn,
  113. ldap.modlist.addModlist(ldap_values))
  114. self.write({'ldap_entry_dn': dn})
  115. @api.multi
  116. def _push_to_ldap_write(self, ldap_connection, ldap_configuration, values,
  117. ldap_values):
  118. self.ensure_one()
  119. dn = self.ldap_entry_dn.encode('utf-8')
  120. dn_mapping = ldap_configuration.create_ldap_entry_field_mappings\
  121. .filtered('use_for_dn')
  122. if dn_mapping.attribute in ldap_values:
  123. ldap_values.pop(dn_mapping.attribute)
  124. ldap_entry = ldap_connection.search_s(
  125. dn, ldap.SCOPE_BASE, '(objectClass=*)',
  126. map(lambda x: x.encode('utf-8'), ldap_values.keys()))
  127. assert ldap_entry, '%s not found!' % self.ldap_entry_dn
  128. ldap_entry = ldap_entry[0][1]
  129. ldap_connection.modify_s(
  130. dn,
  131. ldap.modlist.modifyModlist(ldap_entry, ldap_values))
  132. @api.one
  133. @api.depends('ldap_entry_dn')
  134. def _compute_is_ldap_user(self):
  135. self.is_ldap_user = bool(self.ldap_entry_dn)
  136. @api.one
  137. def _change_ldap_password(self, new_passwd, auth_dn=None,
  138. auth_passwd=None):
  139. ldap_configuration = self.env.user.sudo()._get_ldap_configuration()
  140. ldap_connection = ldap_configuration.connect(
  141. ldap_configuration.read()[0])
  142. dn = auth_dn or ldap_configuration.ldap_binddn
  143. old_passwd = auth_passwd or ldap_configuration.ldap_password
  144. ldap_connection.simple_bind_s(
  145. dn.encode('utf-8'), old_passwd.encode('utf-8'))
  146. self.env['ir.model.access'].check('res.users', 'write')
  147. self.env.user.check_access_rule('write')
  148. try:
  149. ldap_connection.passwd_s(
  150. self.ldap_entry_dn, None, new_passwd.encode('utf-8'))
  151. except ldap.LDAPError, e:
  152. raise exceptions.Warning(_('Error'), e.message)
  153. finally:
  154. ldap_connection.unbind_s()
  155. return True
  156. @api.model
  157. def change_password(self, old_passwd, new_passwd):
  158. if self.env.user.is_ldap_user:
  159. return self.env.user._change_ldap_password(
  160. new_passwd, auth_dn=self.env.user.ldap_entry_dn,
  161. auth_passwd=old_passwd)
  162. return super(ResUsers, self).change_password(old_passwd, new_passwd)