add group ldap settings

This commit is contained in:
cameron 2019-07-15 19:02:57 +08:00
parent 4e87357152
commit 98bdb12755
7 changed files with 339 additions and 620 deletions

View file

@ -0,0 +1,38 @@
{
"creation": "2019-05-29 01:24:29.585060",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"ldap_group",
"erpnext_role"
],
"fields": [
{
"fieldname": "ldap_group",
"fieldtype": "Data",
"in_list_view": 1,
"label": "LDAP Group",
"reqd": 1
},
{
"fieldname": "erpnext_role",
"fieldtype": "Link",
"in_list_view": 1,
"label": "ERPNext Role",
"options": "Role",
"reqd": 1
}
],
"istable": 1,
"modified": "2019-07-15 06:46:38.050408",
"modified_by": "Administrator",
"module": "Integrations",
"name": "LDAP Group Mapping",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "ASC",
"track_changes": 1
}

View file

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class LDAPGroupMapping(Document):
pass

View file

@ -1,594 +1,215 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2016-09-22 04:16:48.829658",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "System",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"enabled",
"ldap_server_url",
"column_break_4",
"base_dn",
"password",
"section_break_5",
"organizational_unit",
"default_role",
"ldap_search_string",
"ldap_email_field",
"ldap_username_field",
"column_break_11",
"ldap_first_name_field",
"ldap_middle_name_field",
"ldap_last_name_field",
"ldap_phone_field",
"ldap_mobile_field",
"ldap_security",
"ssl_tls_mode",
"require_trusted_certificate",
"column_break_17",
"local_private_key_file",
"local_server_certificate_file",
"local_ca_certs_file",
"ldap_group_mappings_section",
"ldap_group_field",
"ldap_groups"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"default": "0",
"fieldname": "enabled",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Enabled",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Enabled"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "ldap_server_url",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "LDAP Server Url",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "organizational_unit",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Organizational Unit",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_dn",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Base Distinguished Name (DN)",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "password",
"fieldtype": "Password",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Password for Base DN",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_5",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "LDAP User Creation and Mapping"
},
{
"fieldname": "organizational_unit",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Organizational Unit for Users",
"reqd": 1
},
{
"fieldname": "default_role",
"fieldtype": "Link",
"label": "Default Role on Creation",
"options": "Role",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "ldap_search_string",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "LDAP Search String",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "ldap_first_name_field",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "LDAP First Name Field",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "ldap_email_field",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "LDAP Email Field",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "ldap_username_field",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "LDAP Username Field",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"fieldname": "column_break_11",
"fieldtype": "Column Break"
},
{
"fieldname": "ldap_first_name_field",
"fieldtype": "Data",
"label": "LDAP First Name Field",
"reqd": 1
},
{
"fieldname": "ldap_middle_name_field",
"fieldtype": "Data",
"label": "LDAP Middle Name Field"
},
{
"fieldname": "ldap_last_name_field",
"fieldtype": "Data",
"label": "LDAP Last Name Field"
},
{
"fieldname": "ldap_phone_field",
"fieldtype": "Data",
"label": "LDAP Phone Field"
},
{
"fieldname": "ldap_mobile_field",
"fieldtype": "Data",
"label": "LDAP Mobile Field"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "ldap_security",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "LDAP Security",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "LDAP Security"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Off",
"description": "",
"fetch_if_empty": 0,
"fieldname": "ssl_tls_mode",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "SSL/TLS Mode",
"length": 0,
"no_copy": 0,
"options": "Off\nStartTLS",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"options": "Off\nStartTLS"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "No",
"fetch_if_empty": 0,
"fieldname": "require_trusted_certificate",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Require Trusted Certificate",
"length": 0,
"no_copy": 0,
"options": "No\nYes",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"fieldname": "column_break_17",
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "local_private_key_file",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Path to private Key File",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Path to private Key File"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "local_server_certificate_file",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Path to Server Certificate",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Path to Server Certificate"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "local_ca_certs_file",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Path to CA Certs File",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Path to CA Certs File"
},
{
"fieldname": "ldap_group_mappings_section",
"fieldtype": "Section Break",
"label": "LDAP Group Mappings"
},
{
"fieldname": "ldap_group_field",
"fieldtype": "Data",
"label": "LDAP Group Field"
},
{
"fieldname": "ldap_groups",
"fieldtype": "Table",
"label": "LDAP Group Mappings",
"options": "LDAP Group Mapping"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 1,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2019-04-29 10:56:42.322696",
"modified": "2019-07-15 06:48:16.562109",
"modified_by": "Administrator",
"module": "Integrations",
"name": "LDAP Settings",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 1,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
"track_changes": 1
}

View file

@ -15,155 +15,195 @@ class LDAPSettings(Document):
if not self.flags.ignore_mandatory:
if self.ldap_search_string and self.ldap_search_string.endswith("={0}"):
connect_to_ldap(server_url=self.ldap_server_url,
base_dn=self.base_dn,
password=self.get_password(raise_exception=False),
ssl_tls_mode=self.ssl_tls_mode,
trusted_cert=self.require_trusted_certificate,
private_key_file=self.local_private_key_file,
server_cert_file=self.local_server_certificate_file,
ca_certs_file=self.local_ca_certs_file
)
self.connect_to_ldap(base_dn=self.base_dn, password=self.get_password(raise_exception=False))
else:
frappe.throw(_("LDAP Search String needs to end with a placeholder, eg sAMAccountName={0}"))
def connect_to_ldap(self, base_dn, password):
try:
import ldap3
import ssl
def get_ldap_client_settings():
#return the settings to be used on the client side.
result = {
"enabled": False
}
settings = frappe.get_doc("LDAP Settings")
if self.require_trusted_certificate == 'Yes':
tls_configuration = ldap3.Tls(validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1)
else:
tls_configuration = ldap3.Tls(validate=ssl.CERT_NONE, version=ssl.PROTOCOL_TLSv1)
if settings and settings.enabled:
result["enabled"] = True
result["method"] = "frappe.integrations.doctype.ldap_settings.ldap_settings.login"
return result
if self.local_private_key_file:
tls_configuration.private_key_file = self.local_private_key_file
if self.local_server_certificate_file:
tls_configuration.certificate_file = self.local_server_certificate_file
if self.local_ca_certs_file:
tls_configuration.ca_certs_file = self.local_ca_certs_file
server = ldap3.Server(host=self.ldap_server_url, tls=tls_configuration)
bind_type = ldap3.AUTO_BIND_TLS_BEFORE_BIND if self.ssl_tls_mode == "StartTLS" else True
def connect_to_ldap(server_url,
base_dn,
password,
ssl_tls_mode,
trusted_cert,
private_key_file,
server_cert_file,
ca_certs_file):
try:
import ldap3
import ssl
conn = ldap3.Connection(
server=server,
user=base_dn,
password=password,
auto_bind=bind_type,
read_only=True,
raise_exceptions=True)
if trusted_cert == 'Yes':
tls_configuration = ldap3.Tls(validate=ssl.CERT_REQUIRED,
version=ssl.PROTOCOL_TLSv1)
return conn
except ImportError:
msg = _("Please Install the ldap3 library via pip to use ldap functionality.")
frappe.throw(msg, title=_("LDAP Not Installed"))
except ldap3.core.exceptions.LDAPInvalidCredentialsResult:
frappe.throw(_("Invalid username or password"))
except Exception as ex:
frappe.throw(_(str(ex)))
@staticmethod
def get_ldap_client_settings():
# return the settings to be used on the client side.
result = {
"enabled": False
}
ldap = frappe.get_doc("LDAP Settings")
if ldap.enabled:
result["enabled"] = True
result["method"] = "frappe.integrations.doctype.ldap_settings.ldap_settings.login"
return result
@classmethod
def update_user_fields(cls, user, user_data):
updatable_data = {key: value for key, value in user_data.items() if key != 'email'}
for key, value in updatable_data.items():
setattr(user, key, value)
user.save(ignore_permissions=True)
def sync_roles(self, user, additional_groups=None):
current_roles = set([d.role for d in user.get("roles")])
needed_roles = set()
needed_roles.add(self.default_role)
lower_groups = [g.lower() for g in additional_groups or []]
all_mapped_roles = {r.erpnext_role for r in self.ldap_groups}
matched_roles = {r.erpnext_role for r in self.ldap_groups if r.ldap_group.lower() in lower_groups}
unmatched_roles = all_mapped_roles.difference(matched_roles)
needed_roles.update(matched_roles)
roles_to_remove = current_roles.intersection(unmatched_roles)
if not needed_roles.issubset(current_roles):
missing_roles = needed_roles.difference(current_roles)
user.add_roles(*missing_roles)
user.remove_roles(*roles_to_remove)
def create_or_update_user(self, user_data, groups=None):
user = None
if frappe.db.exists("User", user_data['email']):
user = frappe.get_doc("User", user_data['email'])
LDAPSettings.update_user_fields(user=user, user_data=user_data)
else:
tls_configuration = ldap3.Tls(validate=ssl.CERT_NONE,
version=ssl.PROTOCOL_TLSv1)
doc = user_data
doc.update({
"doctype": "User",
"send_welcome_email": 0,
"language": "",
"user_type": "System User",
# "roles": [{
# "role": self.default_role
# }]
})
user = frappe.get_doc(doc)
user.insert(ignore_permissions=True)
# always add default role.
user.add_roles(self.default_role)
if self.ldap_group_field:
self.sync_roles(user, groups)
return user
if private_key_file:
tls_configuration.private_key_file = private_key_file
if server_cert_file:
tls_configuration.certificate_file = server_cert_file
if ca_certs_file:
tls_configuration.ca_certs_file = ca_certs_file
def get_ldap_attributes(self):
ldap_attributes = [self.ldap_email_field, self.ldap_username_field, self.ldap_first_name_field]
server = ldap3.Server(host=server_url,
tls=tls_configuration)
bind_type = ldap3.AUTO_BIND_TLS_BEFORE_BIND if ssl_tls_mode == "StartTLS" else True
if self.ldap_group_field:
ldap_attributes.append(self.ldap_group_field)
conn = ldap3.Connection(server=server,
user=base_dn,
password=password,
auto_bind=bind_type,
read_only=True,
raise_exceptions=True)
if self.ldap_middle_name_field:
ldap_attributes.append(self.ldap_middle_name_field)
return conn
if self.ldap_last_name_field:
ldap_attributes.append(self.ldap_last_name_field)
except ImportError:
msg = _("Please Install the ldap3 library via pip to use ldap functionality.")
frappe.throw(msg, title=_("LDAP Not Installed"))
except ldap3.core.exceptions.LDAPInvalidCredentialsResult:
frappe.throw(_("Invalid Credentials"))
except Exception as ex:
frappe.throw(_(str(ex)))
if self.ldap_phone_field:
ldap_attributes.append(self.ldap_phone_field)
if self.ldap_mobile_field:
ldap_attributes.append(self.ldap_mobile_field)
return ldap_attributes
def authenticate(self, username, password):
if not self.enabled:
frappe.throw(_("LDAP is not enabled."))
user_filter = self.ldap_search_string.format(username)
ldap_attributes = self.get_ldap_attributes()
conn = self.connect_to_ldap(self.base_dn, self.get_password(raise_exception=False))
conn.search(
search_base=self.organizational_unit,
search_filter="({0})".format(user_filter),
attributes=ldap_attributes)
if len(conn.entries) == 1 and conn.entries[0]:
user = conn.entries[0]
# only try and connect as the user, once we have their fqdn entry.
self.connect_to_ldap(base_dn=user.entry_dn, password=password)
groups = None
if self.ldap_group_field:
groups = getattr(user, self.ldap_group_field).values
return self.create_or_update_user(self.convert_ldap_entry_to_dict(user), groups=groups)
else:
frappe.throw(_("Invalid username or password"))
def convert_ldap_entry_to_dict(self, user_entry):
data = {
'username': user_entry[self.ldap_username_field].value,
'email': user_entry[self.ldap_email_field].value,
'first_name': user_entry[self.ldap_first_name_field].value
}
# optional fields
if self.ldap_middle_name_field:
data['middle_name'] = user_entry[self.ldap_middle_name_field].value
if self.ldap_last_name_field:
data['last_name'] = user_entry[self.ldap_last_name_field].value
if self.ldap_phone_field:
data['phone'] = user_entry[self.ldap_phone_field].value
if self.ldap_mobile_field:
data['mobile_no'] = user_entry[self.ldap_mobile_field].value
return data
@frappe.whitelist(allow_guest=True)
def login():
# LDAP LOGIN LOGIC
args = frappe.form_dict
user = authenticate_ldap_user(frappe.as_unicode(args.usr), frappe.as_unicode(args.pwd))
ldap = frappe.get_doc("LDAP Settings")
user = ldap.authenticate(frappe.as_unicode(args.usr), frappe.as_unicode(args.pwd))
frappe.local.login_manager.user = user.name
frappe.local.login_manager.post_login()
# because of a GET request!
frappe.db.commit()
def authenticate_ldap_user(user=None,
password=None):
params = {}
settings = frappe.get_doc("LDAP Settings")
if settings and settings.enabled:
conn = connect_to_ldap(server_url=settings.ldap_server_url,
base_dn=settings.base_dn,
password=settings.get_password(raise_exception=False),
ssl_tls_mode=settings.ssl_tls_mode,
trusted_cert=settings.require_trusted_certificate,
private_key_file=settings.local_private_key_file,
server_cert_file=settings.local_server_certificate_file,
ca_certs_file=settings.local_ca_certs_file)
user_filter = settings.ldap_search_string.format(user)
conn.search(search_base=settings.organizational_unit,
search_filter="({0})".format(user_filter),
attributes=[settings.ldap_email_field,
settings.ldap_username_field,
settings.ldap_first_name_field])
if len(conn.entries) > 0 and conn.entries[0]:
user = conn.entries[0]
params["email"] = str(user[settings.ldap_email_field])
params["username"] = str(user[settings.ldap_username_field])
params["first_name"] = str(user[settings.ldap_first_name_field])
connect_to_ldap(server_url=settings.ldap_server_url,
base_dn=user.entry_dn,
password=frappe.as_unicode(password),
ssl_tls_mode=settings.ssl_tls_mode,
trusted_cert=settings.require_trusted_certificate,
private_key_file=settings.local_private_key_file,
server_cert_file=settings.local_server_certificate_file,
ca_certs_file=settings.local_ca_certs_file
)
return create_user(params)
else:
frappe.throw(_("Not a valid LDAP user"))
else:
frappe.throw(_("LDAP is not enabled."))
def create_user(params):
if frappe.db.exists("User", params["email"]):
user = frappe.get_doc("User", params["email"])
user.first_name = params["first_name"]
user.username = params["username"]
user.save(ignore_permissions=True)
return user
else:
params.update({
"doctype": "User",
"send_welcome_email": 0,
"language": "",
"user_type": "System User",
"roles": [{
"role": _("Customer")
}]
})
user = frappe.get_doc(params).insert(ignore_permissions=True)
return user

View file

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals
# import frappe
import unittest
class TestLDAPSettings(unittest.TestCase):
pass

View file

@ -8,7 +8,7 @@ from frappe.utils.oauth import get_oauth2_authorize_url, get_oauth_keys, login_v
import json
from frappe import _
from frappe.auth import LoginManager
from frappe.integrations.doctype.ldap_settings.ldap_settings import get_ldap_client_settings
from frappe.integrations.doctype.ldap_settings.ldap_settings import LDAPSettings
from frappe.utils.password import get_decrypted_password
from frappe.utils.html_utils import get_icon_html
@ -38,7 +38,7 @@ def get_context(context):
"icon": icon
})
context["social_login"] = True
ldap_settings = get_ldap_client_settings()
ldap_settings = LDAPSettings.get_ldap_client_settings()
context["ldap_settings"] = ldap_settings
login_name_placeholder = [_("Email address")]