mirror of
https://github.com/snipe/snipe-it.git
synced 2024-12-26 06:04:08 -08:00
e27065fe16
Signed-off-by: snipe <snipe@snipe.net> # Conflicts: # .all-contributorsrc # README.md # app/Console/Commands/ResetDemoSettings.php # app/Helpers/Helper.php # app/Http/Controllers/Api/AccessoriesController.php # app/Http/Controllers/Api/AssetsController.php # app/Http/Controllers/Api/CategoriesController.php # app/Http/Controllers/Api/ComponentsController.php # app/Http/Controllers/Api/ConsumablesController.php # app/Http/Controllers/Api/LocationsController.php # app/Http/Controllers/Api/StatuslabelsController.php # app/Http/Controllers/Api/SuppliersController.php # app/Http/Controllers/AssetMaintenancesController.php # app/Http/Controllers/Auth/ForgotPasswordController.php # app/Http/Controllers/DepreciationsController.php # app/Http/Controllers/ReportsController.php # app/Http/Controllers/SettingsController.php # app/Http/Requests/ImageUploadRequest.php # app/Http/Transformers/ActionlogsTransformer.php # app/Http/Transformers/DepreciationsTransformer.php # app/Listeners/CheckoutableListener.php # app/Models/Accessory.php # app/Models/Asset.php # app/Models/Company.php # app/Models/Ldap.php # app/Models/User.php # app/Presenters/AssetPresenter.php # app/Presenters/CategoryPresenter.php # composer.json # composer.lock # config/version.php # database/factories/AssetModelFactory.php # database/migrations/2020_10_22_233743_move_accessory_checkout_note_to_join_table.php # database/seeds/AssetModelSeeder.php # package-lock.json # public/css/build/AdminLTE.css # public/css/build/app.css # public/css/build/overrides.css # public/css/dist/all.css # public/css/dist/bootstrap-table.css # public/css/dist/skins/skin-black-dark.css # public/css/dist/skins/skin-black-dark.min.css # public/css/dist/skins/skin-black.css # public/css/dist/skins/skin-black.min.css # public/css/dist/skins/skin-blue-dark.css # public/css/dist/skins/skin-blue-dark.min.css # public/css/dist/skins/skin-blue.css # public/css/dist/skins/skin-blue.min.css # public/css/dist/skins/skin-contrast.css # public/css/dist/skins/skin-contrast.min.css # public/css/dist/skins/skin-green-dark.css # public/css/dist/skins/skin-green-dark.min.css # public/css/dist/skins/skin-green.css # public/css/dist/skins/skin-green.min.css # public/css/dist/skins/skin-orange-dark.css # public/css/dist/skins/skin-orange-dark.min.css # public/css/dist/skins/skin-orange.css # public/css/dist/skins/skin-orange.min.css # public/css/dist/skins/skin-purple-dark.css # public/css/dist/skins/skin-purple-dark.min.css # public/css/dist/skins/skin-purple.css # public/css/dist/skins/skin-purple.min.css # public/css/dist/skins/skin-red-dark.css # public/css/dist/skins/skin-red-dark.min.css # public/css/dist/skins/skin-red.css # public/css/dist/skins/skin-red.min.css # public/css/dist/skins/skin-yellow-dark.css # public/css/dist/skins/skin-yellow-dark.min.css # public/css/dist/skins/skin-yellow.css # public/css/dist/skins/skin-yellow.min.css # public/js/build/app.js # public/js/build/vendor.js # public/js/dist/all.js # public/js/dist/bootstrap-table.js # public/mix-manifest.json # resources/assets/js/vue.js # resources/lang/af/validation.php # resources/lang/ar/admin/settings/general.php # resources/lang/ar/validation.php # resources/lang/bg/admin/settings/general.php # resources/lang/bg/validation.php # resources/lang/cs/admin/settings/general.php # resources/lang/cs/validation.php # resources/lang/cy/help.php # resources/lang/cy/validation.php # resources/lang/da/admin/settings/general.php # resources/lang/da/validation.php # resources/lang/de/admin/settings/general.php # resources/lang/de/validation.php # resources/lang/el/validation.php # resources/lang/en-GB/admin/settings/general.php # resources/lang/en-GB/validation.php # resources/lang/en-ID/admin/hardware/table.php # resources/lang/en-ID/admin/settings/general.php # resources/lang/en-ID/validation.php # resources/lang/es-CO/admin/settings/general.php # resources/lang/es-CO/auth/message.php # resources/lang/es-CO/button.php # resources/lang/es-CO/help.php # resources/lang/es-CO/validation.php # resources/lang/es-ES/admin/settings/general.php # resources/lang/es-ES/auth/message.php # resources/lang/es-ES/button.php # resources/lang/es-ES/help.php # resources/lang/es-ES/validation.php # resources/lang/es-MX/admin/settings/general.php # resources/lang/es-MX/validation.php # resources/lang/es-VE/admin/settings/general.php # resources/lang/es-VE/auth/message.php # resources/lang/es-VE/button.php # resources/lang/es-VE/help.php # resources/lang/es-VE/validation.php # resources/lang/et/validation.php # resources/lang/fa/validation.php # resources/lang/fi/admin/settings/general.php # resources/lang/fi/validation.php # resources/lang/fil/validation.php # resources/lang/fr/admin/settings/general.php # resources/lang/fr/validation.php # resources/lang/ga-IE/validation.php # resources/lang/he/admin/settings/general.php # resources/lang/he/general.php # resources/lang/he/validation.php # resources/lang/hr/validation.php # resources/lang/hu/validation.php # resources/lang/id/validation.php # resources/lang/is/admin/categories/general.php # resources/lang/is/admin/companies/message.php # resources/lang/is/admin/companies/table.php # resources/lang/is/admin/components/general.php # resources/lang/is/admin/components/table.php # resources/lang/is/admin/consumables/table.php # resources/lang/is/admin/depreciations/general.php # resources/lang/is/admin/depreciations/message.php # resources/lang/is/admin/hardware/form.php # resources/lang/is/admin/hardware/general.php # resources/lang/is/admin/hardware/message.php # resources/lang/is/admin/hardware/table.php # resources/lang/is/admin/kits/general.php # resources/lang/is/admin/licenses/form.php # resources/lang/is/admin/licenses/general.php # resources/lang/is/admin/locations/table.php # resources/lang/is/admin/manufacturers/table.php # resources/lang/is/admin/reports/message.php # resources/lang/is/admin/settings/general.php # resources/lang/is/admin/settings/message.php # resources/lang/is/admin/statuslabels/message.php # resources/lang/is/admin/suppliers/message.php # resources/lang/is/admin/suppliers/table.php # resources/lang/is/admin/users/table.php # resources/lang/is/mail.php # resources/lang/is/validation.php # resources/lang/it/admin/settings/general.php # resources/lang/it/validation.php # resources/lang/iu/validation.php # resources/lang/ja/mail.php # resources/lang/ja/validation.php # resources/lang/ko/validation.php # resources/lang/lt/validation.php # resources/lang/lv/validation.php # resources/lang/mi/validation.php # resources/lang/mk/validation.php # resources/lang/ml-IN/validation.php # resources/lang/mn/validation.php # resources/lang/ms/validation.php # resources/lang/nl/admin/settings/general.php # resources/lang/nl/validation.php # resources/lang/no/validation.php # resources/lang/pl/admin/settings/general.php # resources/lang/pl/validation.php # resources/lang/pt-BR/admin/settings/general.php # resources/lang/pt-BR/mail.php # resources/lang/pt-BR/validation.php # resources/lang/pt-PT/validation.php # resources/lang/ro/validation.php # resources/lang/ru/validation.php # resources/lang/sl/validation.php # resources/lang/sr-CS/admin/settings/general.php # resources/lang/sr-CS/validation.php # resources/lang/sv-SE/admin/settings/general.php # resources/lang/sv-SE/auth/message.php # resources/lang/sv-SE/button.php # resources/lang/sv-SE/mail.php # resources/lang/sv-SE/validation.php # resources/lang/ta/validation.php # resources/lang/th/validation.php # resources/lang/tl/validation.php # resources/lang/tr/mail.php # resources/lang/tr/validation.php # resources/lang/uk/admin/accessories/table.php # resources/lang/uk/admin/asset_maintenances/message.php # resources/lang/uk/admin/asset_maintenances/table.php # resources/lang/uk/validation.php # resources/lang/ur-PK/validation.php # resources/lang/vi/admin/settings/general.php # resources/lang/vi/validation.php # resources/lang/zh-CN/admin/settings/general.php # resources/lang/zh-CN/validation.php # resources/lang/zh-HK/validation.php # resources/lang/zh-TW/validation.php # resources/lang/zu/validation.php # resources/views/partials/bootstrap-table.blade.php # resources/views/partials/forms/edit/company-select.blade.php # routes/api.php
297 lines
12 KiB
PHP
297 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Models\Setting;
|
|
use App\Models\User;
|
|
use Exception;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Input;
|
|
use Log;
|
|
|
|
class Ldap extends Model
|
|
{
|
|
/**
|
|
* Makes a connection to LDAP using the settings in Admin > Settings.
|
|
*
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
* @since [v3.0]
|
|
* @return connection
|
|
*/
|
|
public static function connectToLdap()
|
|
{
|
|
$ldap_host = Setting::getSettings()->ldap_server;
|
|
$ldap_version = Setting::getSettings()->ldap_version;
|
|
$ldap_server_cert_ignore = Setting::getSettings()->ldap_server_cert_ignore;
|
|
$ldap_use_tls = Setting::getSettings()->ldap_tls;
|
|
|
|
// If we are ignoring the SSL cert we need to setup the environment variable
|
|
// before we create the connection
|
|
if ($ldap_server_cert_ignore == '1') {
|
|
putenv('LDAPTLS_REQCERT=never');
|
|
}
|
|
|
|
// If the user specifies where CA Certs are, make sure to use them
|
|
if (env('LDAPTLS_CACERT')) {
|
|
putenv('LDAPTLS_CACERT='.env('LDAPTLS_CACERT'));
|
|
}
|
|
|
|
$connection = @ldap_connect($ldap_host);
|
|
|
|
if (! $connection) {
|
|
throw new Exception('Could not connect to LDAP server at '.$ldap_host.'. Please check your LDAP server name and port number in your settings.');
|
|
}
|
|
|
|
// Needed for AD
|
|
ldap_set_option($connection, LDAP_OPT_REFERRALS, 0);
|
|
ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, $ldap_version);
|
|
ldap_set_option($connection, LDAP_OPT_NETWORK_TIMEOUT, 20);
|
|
|
|
if (Setting::getSettings()->ldap_client_tls_cert && Setting::getSettings()->ldap_client_tls_key) {
|
|
ldap_set_option($connection, LDAP_OPT_X_TLS_CERTFILE, Setting::get_client_side_cert_path());
|
|
ldap_set_option($connection, LDAP_OPT_X_TLS_KEYFILE, Setting::get_client_side_key_path());
|
|
}
|
|
|
|
if ($ldap_use_tls=='1') {
|
|
ldap_start_tls($connection);
|
|
}
|
|
|
|
|
|
return $connection;
|
|
}
|
|
|
|
|
|
/**
|
|
* Binds/authenticates the user to LDAP, and returns their attributes.
|
|
*
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
* @since [v3.0]
|
|
* @param $username
|
|
* @param $password
|
|
* @param bool|false $user
|
|
* @return bool true if the username and/or password provided are valid
|
|
* false if the username and/or password provided are invalid
|
|
* array of ldap_attributes if $user is true
|
|
*/
|
|
public static function findAndBindUserLdap($username, $password)
|
|
{
|
|
$settings = Setting::getSettings();
|
|
$connection = self::connectToLdap();
|
|
$ldap_username_field = $settings->ldap_username_field;
|
|
$baseDn = $settings->ldap_basedn;
|
|
$userDn = $ldap_username_field.'='.$username.','.$settings->ldap_basedn;
|
|
|
|
if ($settings->is_ad == '1') {
|
|
// Check if they are using the userprincipalname for the username field.
|
|
// If they are, we can skip building the UPN to authenticate against AD
|
|
if ($ldap_username_field == 'userprincipalname') {
|
|
$userDn = $username;
|
|
} else {
|
|
// In case they haven't added an AD domain
|
|
$userDn = ($settings->ad_domain != '') ? $username.'@'.$settings->ad_domain : $username.'@'.$settings->email_domain;
|
|
}
|
|
}
|
|
|
|
\Log::debug('Attempting to login using distinguished name:'.$userDn);
|
|
|
|
$filterQuery = $settings->ldap_auth_filter_query.$username;
|
|
$filter = Setting::getSettings()->ldap_filter;
|
|
$filterQuery = "({$filter}({$filterQuery}))";
|
|
|
|
\Log::debug('Filter query: '.$filterQuery);
|
|
|
|
if (! $ldapbind = @ldap_bind($connection, $userDn, $password)) {
|
|
if (! $ldapbind = self::bindAdminToLdap($connection)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (! $results = ldap_search($connection, $baseDn, $filterQuery)) {
|
|
throw new Exception('Could not search LDAP: ');
|
|
}
|
|
|
|
if (! $entry = ldap_first_entry($connection, $results)) {
|
|
return false;
|
|
}
|
|
|
|
if (! $user = ldap_get_attributes($connection, $entry)) {
|
|
return false;
|
|
}
|
|
|
|
return array_change_key_case($user);
|
|
}
|
|
|
|
/**
|
|
* Binds/authenticates an admin to LDAP for LDAP searching/syncing.
|
|
* Here we also return a better error if the app key is donked.
|
|
*
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
* @since [v3.0]
|
|
* @param bool|false $user
|
|
* @return bool true if the username and/or password provided are valid
|
|
* false if the username and/or password provided are invalid
|
|
*/
|
|
public static function bindAdminToLdap($connection)
|
|
{
|
|
$ldap_username = Setting::getSettings()->ldap_uname;
|
|
|
|
$ldap_username = Setting::getSettings()->ldap_uname;
|
|
|
|
// Lets return some nicer messages for users who donked their app key, and disable LDAP
|
|
try {
|
|
$ldap_pass = \Crypt::decrypt(Setting::getSettings()->ldap_pword);
|
|
} catch (Exception $e) {
|
|
throw new Exception('Your app key has changed! Could not decrypt LDAP password using your current app key, so LDAP authentication has been disabled. Login with a local account, update the LDAP password and re-enable it in Admin > Settings.');
|
|
}
|
|
|
|
if (! $ldapbind = @ldap_bind($connection, $ldap_username, $ldap_pass)) {
|
|
throw new Exception('Could not bind to LDAP: '.ldap_error($connection));
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Parse and map LDAP attributes based on settings
|
|
*
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
* @since [v3.0]
|
|
*
|
|
* @param $ldapatttibutes
|
|
* @return array|bool
|
|
*/
|
|
public static function parseAndMapLdapAttributes($ldapattributes)
|
|
{
|
|
//Get LDAP attribute config
|
|
$ldap_result_username = Setting::getSettings()->ldap_username_field;
|
|
$ldap_result_emp_num = Setting::getSettings()->ldap_emp_num;
|
|
$ldap_result_last_name = Setting::getSettings()->ldap_lname_field;
|
|
$ldap_result_first_name = Setting::getSettings()->ldap_fname_field;
|
|
$ldap_result_email = Setting::getSettings()->ldap_email;
|
|
$ldap_result_phone = Setting::getSettings()->ldap_phone;
|
|
$ldap_result_jobtitle = Setting::getSettings()->ldap_jobtitle;
|
|
$ldap_result_country = Setting::getSettings()->ldap_country;
|
|
$ldap_result_dept = Setting::getSettings()->ldap_dept;
|
|
// Get LDAP user data
|
|
$item = [];
|
|
$item['username'] = isset($ldapattributes[$ldap_result_username][0]) ? $ldapattributes[$ldap_result_username][0] : '';
|
|
$item['employee_number'] = isset($ldapattributes[$ldap_result_emp_num][0]) ? $ldapattributes[$ldap_result_emp_num][0] : '';
|
|
$item['lastname'] = isset($ldapattributes[$ldap_result_last_name][0]) ? $ldapattributes[$ldap_result_last_name][0] : '';
|
|
$item['firstname'] = isset($ldapattributes[$ldap_result_first_name][0]) ? $ldapattributes[$ldap_result_first_name][0] : '';
|
|
$item['email'] = isset($ldapattributes[$ldap_result_email][0]) ? $ldapattributes[$ldap_result_email][0] : '';
|
|
$item['telephone'] = isset($ldapattributes[$ldap_result_phone][0]) ? $ldapattributes[$ldap_result_phone][0] : '';
|
|
$item['jobtitle'] = isset($ldapattributes[$ldap_result_jobtitle][0]) ? $ldapattributes[$ldap_result_jobtitle][0] : '';
|
|
$item['country'] = isset($ldapattributes[$ldap_result_country][0]) ? $ldapattributes[$ldap_result_country][0] : '';
|
|
$item['department'] = isset($ldapattributes[$ldap_result_dept][0]) ? $ldapattributes[$ldap_result_dept][0] : '';
|
|
|
|
return $item;
|
|
}
|
|
|
|
/**
|
|
* Create user from LDAP attributes
|
|
*
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
* @since [v3.0]
|
|
* @param $ldapatttibutes
|
|
* @return array|bool
|
|
*/
|
|
public static function createUserFromLdap($ldapatttibutes)
|
|
{
|
|
$item = self::parseAndMapLdapAttributes($ldapatttibutes);
|
|
|
|
// Create user from LDAP data
|
|
if (! empty($item['username'])) {
|
|
$user = new User;
|
|
$user->first_name = $item['firstname'];
|
|
$user->last_name = $item['lastname'];
|
|
$user->username = $item['username'];
|
|
$user->email = $item['email'];
|
|
|
|
if (Setting::getSettings()->ldap_pw_sync == '1') {
|
|
$user->password = bcrypt(Input::get('password'));
|
|
} else {
|
|
$pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 25);
|
|
$user->password = bcrypt($pass);
|
|
}
|
|
|
|
$user->activated = 1;
|
|
$user->ldap_import = 1;
|
|
$user->notes = 'Imported on first login from LDAP';
|
|
|
|
if ($user->save()) {
|
|
return $user;
|
|
} else {
|
|
LOG::debug('Could not create user.'.$user->getErrors());
|
|
throw new Exception('Could not create user: '.$user->getErrors());
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Searches LDAP
|
|
*
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
* @since [v3.0]
|
|
* @param $ldapatttibutes
|
|
* @param $base_dn
|
|
* @return array|bool
|
|
*/
|
|
public static function findLdapUsers($base_dn = null)
|
|
{
|
|
$ldapconn = self::connectToLdap();
|
|
$ldap_bind = self::bindAdminToLdap($ldapconn);
|
|
// Default to global base DN if nothing else is provided.
|
|
if (is_null($base_dn)) {
|
|
$base_dn = Setting::getSettings()->ldap_basedn;
|
|
}
|
|
$filter = Setting::getSettings()->ldap_filter;
|
|
|
|
// Set up LDAP pagination for very large databases
|
|
$page_size = 500;
|
|
$cookie = '';
|
|
$result_set = [];
|
|
$global_count = 0;
|
|
|
|
// Perform the search
|
|
do {
|
|
|
|
// Paginate (non-critical, if not supported by server)
|
|
if (! $ldap_paging = @ldap_control_paged_result($ldapconn, $page_size, false, $cookie)) {
|
|
throw new Exception('Problem with your LDAP connection. Try checking the Use TLS setting in Admin > Settings. ');
|
|
}
|
|
|
|
if ($filter != '' && substr($filter, 0, 1) != '(') { // wrap parens around NON-EMPTY filters that DON'T have them, for back-compatibility with AdLdap2-based filters
|
|
$filter = "($filter)";
|
|
} elseif ($filter == '') {
|
|
$filter = '(cn=*)';
|
|
}
|
|
|
|
$search_results = ldap_search($ldapconn, $base_dn, $filter);
|
|
|
|
if (! $search_results) {
|
|
return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_search').ldap_error($ldapconn)); // FIXME this is never called in any routed context - only from the Artisan command. So this redirect will never work.
|
|
}
|
|
|
|
// Get results from page
|
|
$results = ldap_get_entries($ldapconn, $search_results);
|
|
if (! $results) {
|
|
return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_get_entries').ldap_error($ldapconn)); // FIXME this is never called in any routed context - only from the Artisan command. So this redirect will never work.
|
|
}
|
|
|
|
// Add results to result set
|
|
$global_count += $results['count'];
|
|
$result_set = array_merge($result_set, $results);
|
|
|
|
@ldap_control_paged_result_response($ldapconn, $search_results, $cookie);
|
|
} while ($cookie !== null && $cookie != '');
|
|
|
|
// Clean up after search
|
|
$result_set['count'] = $global_count;
|
|
$results = $result_set;
|
|
@ldap_control_paged_result($ldapconn, 0);
|
|
|
|
return $results;
|
|
}
|
|
}
|