Skip to content

Added #15506: Explicitly request used LDAP attributes #15507

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 58 additions & 47 deletions app/Console/Commands/LdapSync.php
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,22 @@ public function handle()

ini_set('max_execution_time', env('LDAP_TIME_LIM', 600)); //600 seconds = 10 minutes
ini_set('memory_limit', env('LDAP_MEM_LIM', '500M'));
$ldap_result_username = Setting::getSettings()->ldap_username_field;
$ldap_result_last_name = Setting::getSettings()->ldap_lname_field;
$ldap_result_first_name = Setting::getSettings()->ldap_fname_field;
$ldap_result_active_flag = Setting::getSettings()->ldap_active_flag;
$ldap_result_emp_num = Setting::getSettings()->ldap_emp_num;
$ldap_result_email = Setting::getSettings()->ldap_email;
$ldap_result_phone = Setting::getSettings()->ldap_phone_field;
$ldap_result_jobtitle = Setting::getSettings()->ldap_jobtitle;
$ldap_result_country = Setting::getSettings()->ldap_country;
$ldap_result_location = Setting::getSettings()->ldap_location;
$ldap_result_dept = Setting::getSettings()->ldap_dept;
$ldap_result_manager = Setting::getSettings()->ldap_manager;

$ldap_map = [
"username" => Setting::getSettings()->ldap_username_field,
"last_name" => Setting::getSettings()->ldap_lname_field,
"first_name" => Setting::getSettings()->ldap_fname_field,
"active_flag" => Setting::getSettings()->ldap_active_flag,
"emp_num" => Setting::getSettings()->ldap_emp_num,
"email" => Setting::getSettings()->ldap_email,
"phone" => Setting::getSettings()->ldap_phone_field,
"jobtitle" => Setting::getSettings()->ldap_jobtitle,
"country" => Setting::getSettings()->ldap_country,
"location" => Setting::getSettings()->ldap_location,
"dept" => Setting::getSettings()->ldap_dept,
"manager" => Setting::getSettings()->ldap_manager,
];

$ldap_default_group = Setting::getSettings()->ldap_default_group;
$search_base = Setting::getSettings()->ldap_base_dn;

Expand Down Expand Up @@ -107,14 +111,21 @@ public function handle()
}

/**
* If a filter has been specified, use that
* If a filter has been specified, use that, otherwise default to null
*/
if ($this->option('filter') != '') {
$results = Ldap::findLdapUsers($search_base, -1, $this->option('filter'));
$filter = $this->option('filter');
} else {
$results = Ldap::findLdapUsers($search_base);
$filter = null;
}


/**
* We only need to request the LDAP attributes that we process
*/
$attributes = array_values(array_filter($ldap_map));

$results = Ldap::findLdapUsers($search_base, -1, $filter, $attributes);

} catch (\Exception $e) {
if ($this->option('json_summary')) {
$json_summary = ['error' => true, 'error_message' => $e->getMessage(), 'summary' => []];
Expand Down Expand Up @@ -183,17 +194,17 @@ public function handle()
}
$usernames = [];
for ($i = 0; $i < $location_users['count']; $i++) {
if (array_key_exists($ldap_result_username, $location_users[$i])) {
if (array_key_exists($ldap_map["username"], $location_users[$i])) {
$location_users[$i]['ldap_location_override'] = true;
$location_users[$i]['location_id'] = $ldap_loc['id'];
$usernames[] = $location_users[$i][$ldap_result_username][0];
$usernames[] = $location_users[$i][$ldap_map["username"]][0];
}
}

// Delete located users from the general group.
foreach ($results as $key => $generic_entry) {
if ((is_array($generic_entry)) && (array_key_exists($ldap_result_username, $generic_entry))) {
if (in_array($generic_entry[$ldap_result_username][0], $usernames)) {
if ((is_array($generic_entry)) && (array_key_exists($ldap_map["username"], $generic_entry))) {
if (in_array($generic_entry[$ldap_map["username"]][0], $usernames)) {
unset($results[$key]);
}
}
Expand All @@ -219,22 +230,22 @@ public function handle()

for ($i = 0; $i < $results['count']; $i++) {
$item = [];
$item['username'] = $results[$i][$ldap_result_username][0] ?? '';
$item['employee_number'] = $results[$i][$ldap_result_emp_num][0] ?? '';
$item['lastname'] = $results[$i][$ldap_result_last_name][0] ?? '';
$item['firstname'] = $results[$i][$ldap_result_first_name][0] ?? '';
$item['email'] = $results[$i][$ldap_result_email][0] ?? '';
$item['username'] = $results[$i][$ldap_map["username"]][0] ?? '';
$item['employee_number'] = $results[$i][$ldap_map["emp_num"]][0] ?? '';
$item['lastname'] = $results[$i][$ldap_map["last_name"]][0] ?? '';
$item['firstname'] = $results[$i][$ldap_map["first_name"]][0] ?? '';
$item['email'] = $results[$i][$ldap_map["email"]][0] ?? '';
$item['ldap_location_override'] = $results[$i]['ldap_location_override'] ?? '';
$item['location_id'] = $results[$i]['location_id'] ?? '';
$item['telephone'] = $results[$i][$ldap_result_phone][0] ?? '';
$item['jobtitle'] = $results[$i][$ldap_result_jobtitle][0] ?? '';
$item['country'] = $results[$i][$ldap_result_country][0] ?? '';
$item['department'] = $results[$i][$ldap_result_dept][0] ?? '';
$item['manager'] = $results[$i][$ldap_result_manager][0] ?? '';
$item['location'] = $results[$i][$ldap_result_location][0] ?? '';
$item['telephone'] = $results[$i][$ldap_map["phone"]][0] ?? '';
$item['jobtitle'] = $results[$i][$ldap_map["jobtitle"]][0] ?? '';
$item['country'] = $results[$i][$ldap_map["country"]][0] ?? '';
$item['department'] = $results[$i][$ldap_map["dept"]][0] ?? '';
$item['manager'] = $results[$i][$ldap_map["manager"]][0] ?? '';
$item['location'] = $results[$i][$ldap_map["location"]][0] ?? '';

// ONLY if you are using the "ldap_location" option *AND* you have an actual result
if ($ldap_result_location && $item['location']) {
if ($ldap_map["location"] && $item['location']) {
$location = Location::firstOrCreate([
'name' => $item['location'],
]);
Expand All @@ -257,38 +268,38 @@ public function handle()
}

//If a sync option is not filled in on the LDAP settings don't populate the user field
if($ldap_result_username != null){
if($ldap_map["username"] != null){
$user->username = $item['username'];
}
if($ldap_result_last_name != null){
if($ldap_map["last_name"] != null){
$user->last_name = $item['lastname'];
}
if($ldap_result_first_name != null){
if($ldap_map["first_name"] != null){
$user->first_name = $item['firstname'];
}
if($ldap_result_emp_num != null){
if($ldap_map["emp_num"] != null){
$user->employee_num = e($item['employee_number']);
}
if($ldap_result_email != null){
if($ldap_map["email"] != null){
$user->email = $item['email'];
}
if($ldap_result_phone != null){
if($ldap_map["phone"] != null){
$user->phone = $item['telephone'];
}
if($ldap_result_jobtitle != null){
if($ldap_map["jobtitle"] != null){
$user->jobtitle = $item['jobtitle'];
}
if($ldap_result_country != null){
if($ldap_map["country"] != null){
$user->country = $item['country'];
}
if($ldap_result_dept != null){
if($ldap_map["dept"] != null){
$user->department_id = $department->id;
}
if($ldap_result_location != null){
if($ldap_map["location"] != null){
$user->location_id = $location ? $location->id : null;
}

if($ldap_result_manager != null){
if($ldap_map["manager"] != null){
if($item['manager'] != null) {
// Check Cache first
if (isset($manager_cache[$item['manager']])) {
Expand All @@ -305,7 +316,7 @@ public function handle()
$ldap_manager = [
"count" => 1,
0 => [
$ldap_result_username => [$item['manager']]
$ldap_map["username"] => [$item['manager']]
]
];
}
Expand All @@ -314,7 +325,7 @@ public function handle()

// Get the Manager's username
// PHP LDAP returns every LDAP attribute as an array, and 90% of the time it's an array of just one item. But, hey, it's an array.
$ldapManagerUsername = $ldap_manager[0][$ldap_result_username][0];
$ldapManagerUsername = $ldap_manager[0][$ldap_map["username"]][0];

// Get User from Manager username.
$ldap_manager = User::where('username', $ldapManagerUsername)->first();
Expand All @@ -331,10 +342,10 @@ public function handle()
}

// Sync activated state for Active Directory.
if ( !empty($ldap_result_active_flag)) { // IF we have an 'active' flag set....
if ( !empty($ldap_map["active_flag"])) { // IF we have an 'active' flag set....
// ....then *most* things that are truthy will activate the user. Anything falsey will deactivate them.
// (Specifically, we don't handle a value of '0.0' correctly)
$raw_value = @$results[$i][$ldap_result_active_flag][0];
$raw_value = @$results[$i][$ldap_map["active_flag"]][0];
$filter_var = filter_var($raw_value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
$boolean_cast = (bool)$raw_value;

Expand Down
7 changes: 4 additions & 3 deletions app/Models/Ldap.php
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,10 @@ public static function createUserFromLdap($ldapatttibutes, $password)
* @param $base_dn
* @param $count
* @param $filter
* @param $attributes
* @return array|bool
*/
public static function findLdapUsers($base_dn = null, $count = -1, $filter = null)
public static function findLdapUsers($base_dn = null, $count = -1, $filter = null, $attributes = [])
{
$ldapconn = self::connectToLdap();
self::bindAdminToLdap($ldapconn);
Expand Down Expand Up @@ -319,7 +320,7 @@ public static function findLdapUsers($base_dn = null, $count = -1, $filter = nul
//if($count == -1) { //count is -1 means we have to employ paging to query the entire directory
$ldap_controls = [['oid' => LDAP_CONTROL_PAGEDRESULTS, 'iscritical' => false, 'value' => ['size'=> $count == -1||$count>$page_size ? $page_size : $count, 'cookie' => $cookie]]];
//}
$search_results = ldap_search($ldapconn, $base_dn, $filter, [], 0, /* $page_size */ -1, -1, LDAP_DEREF_NEVER, $ldap_controls); // TODO - I hate the @, and I hate that we get a full page even if we ask for 10 records. Can we use an ldap_control?
$search_results = ldap_search($ldapconn, $base_dn, $filter, $attributes, 0, /* $page_size */ -1, -1, LDAP_DEREF_NEVER, $ldap_controls); // TODO - I hate the @, and I hate that we get a full page even if we ask for 10 records. Can we use an ldap_control?
Log::debug("LDAP search executed successfully.");
if (! $search_results) {
return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_search').ldap_error($ldapconn)); // TODO this is never called in any routed context - only from the Artisan command. So this redirect will never work.
Expand All @@ -340,7 +341,7 @@ public static function findLdapUsers($base_dn = null, $count = -1, $filter = nul
$cookie = '';
}
// Empty cookie means last page

// Get results from page
$results = ldap_get_entries($ldapconn, $search_results);
if (! $results) {
Expand Down
Loading