diff --git a/_ide_helper.php b/_ide_helper.php index 146c0b128..4d6bba4fd 100644 --- a/_ide_helper.php +++ b/_ide_helper.php @@ -4,7 +4,7 @@ /** * A helper file for Laravel, to provide autocomplete information to your IDE - * Generated for Laravel 8.83.16. + * Generated for Laravel 8.83.27. * * This file should not be included in your code, only analyzed by your IDE! * @@ -2167,6 +2167,17 @@ { /** @var \Illuminate\Auth\SessionGuard $instance */ return $instance->setRequest($request); + } + /** + * Get the timebox instance used by the guard. + * + * @return \Illuminate\Support\Timebox + * @static + */ + public static function getTimebox() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getTimebox(); } /** * Determine if the current user is authenticated. If not, throw an exception. @@ -16109,6 +16120,16 @@ { /** @var \Facade\FlareClient\Flare $instance */ return $instance->filterExceptionsUsing($filterExceptionsCallable); + } + /** + * + * + * @static + */ + public static function filterReportsUsing($filterReportsCallable) + { + /** @var \Facade\FlareClient\Flare $instance */ + return $instance->filterReportsUsing($filterReportsCallable); } /** * diff --git a/app/Http/Controllers/Api/SystemController.php b/app/Http/Controllers/Api/SystemController.php index 0b4c3b7e6..aff427f01 100755 --- a/app/Http/Controllers/Api/SystemController.php +++ b/app/Http/Controllers/Api/SystemController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api; +use App\Ldap\LdapUser; use App\Models\Setting; use App\Models\User; use App\Models\UserCheckinRecord; @@ -10,8 +11,13 @@ use App\Module\BillExport; use App\Module\BillMultipleExport; use Arr; use Carbon\Carbon; +use Config; use Guanguans\Notify\Factory; use Guanguans\Notify\Messages\EmailMessage; +use LdapRecord\Auth\PasswordRequiredException; +use LdapRecord\Auth\UsernameRequiredException; +use LdapRecord\Container; +use LdapRecord\LdapRecordException; use Madzipper; use Request; use Response; @@ -311,6 +317,74 @@ class SystemController extends AbstractController return Base::retSuccess('success', $setting ?: json_decode('{}')); } + /** + * @api {get} api/system/setting/thirdaccess 04. 第三方帐号(限管理员) + * + * @apiVersion 1.0.0 + * @apiGroup system + * @apiName setting__thirdaccess + * + * @apiParam {String} type + * - get: 获取(默认) + * - save: 保存设置(参数:['ldap_open', 'ldap_host', 'ldap_port', 'ldap_password', 'ldap_cn', 'ldap_dn']) + * - testldap: 测试ldap连接 + * @apiSuccess {Number} ret 返回状态码(1正确、0错误) + * @apiSuccess {String} msg 返回信息(错误描述) + * @apiSuccess {Object} data 返回数据 + */ + public function setting__thirdaccess() + { + User::auth('admin'); + // + $type = trim(Request::input('type')); + if ($type == 'testldap') { + $all = Base::newTrim(Request::input()); + $connection = Container::getDefaultConnection(); + try { + $connection->setConfiguration([ + "hosts" => [$all['ldap_host']], + "port" => intval($all['ldap_port']), + "password" => $all['ldap_password'], + "username" => $all['ldap_cn'], + "base_dn" => $all['ldap_dn'], + ]); + if ($connection->auth()->attempt($all['ldap_cn'], $all['ldap_password'])) { + return Base::retSuccess('验证通过'); + } else { + return Base::retError('验证失败'); + } + } catch (LdapRecordException $e) { + return Base::retError($e->getMessage() ?: "验证失败:未知错误", config("ldap.connections.default")); + } + } elseif ($type == 'save') { + if (env("SYSTEM_SETTING") == 'disabled') { + return Base::retError('当前环境禁止修改'); + } + $all = Base::newTrim(Request::input()); + foreach ($all as $key => $value) { + if (!in_array($key, [ + 'ldap_open', + 'ldap_host', + 'ldap_port', + 'ldap_password', + 'ldap_cn', + 'ldap_dn' + ])) { + unset($all[$key]); + } + } + $all['ldap_port'] = intval($all['ldap_port']) ?: 389; + $setting = Base::setting('thirdAccessSetting', Base::newTrim($all)); + } else { + $setting = Base::setting('thirdAccessSetting'); + } + // + $setting['ldap_open'] = $setting['ldap_open'] ?: 'close'; + $setting['ldap_port'] = intval($setting['ldap_port']) ?: 389; + // + return Base::retSuccess('success', $setting ?: json_decode('{}')); + } + /** * @api {get} api/system/demo 05. 获取演示帐号 * diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index e4bd881a4..248d44677 100755 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api; +use App\Ldap\LdapUser; use App\Models\AbstractModel; use App\Models\Meeting; use App\Models\Project; @@ -49,6 +50,8 @@ class UsersController extends AbstractController * @apiSuccess {Number} ret 返回状态码(1正确、0错误) * @apiSuccess {String} msg 返回信息(错误描述) * @apiSuccess {Object} data 返回数据(同"获取我的信息"接口) + * + * @throws \LdapRecord\Configuration\ConfigurationException */ public function login() { @@ -89,11 +92,22 @@ class UsersController extends AbstractController $needData = ['code' => $needCode ? 'need' : 'no']; return Base::retError($msg, $needData); }; + // $user = User::whereEmail($email)->first(); + $checkPassword = true; + if (LdapUser::isOpen() && (empty($user) || in_array('ldap', $user->identity))) { + $user = LdapUser::userLogin($email, $password, $user); + if ($user) { + $identity = array_merge(array_diff($user->identity, ['ldap']), ['ldap']); + $user->identity = "," . implode(",", $identity) . ","; + $user->save(); + } + $checkPassword = false; + } if (empty($user)) { return $retError('帐号或密码错误'); } - if ($user->password != Base::md52($password, $user->encrypt)) { + if ($checkPassword && $user->password != Base::md52($password, $user->encrypt)) { return $retError('帐号或密码错误'); } // diff --git a/app/Ldap/LdapUser.php b/app/Ldap/LdapUser.php new file mode 100644 index 000000000..ddff75c3e --- /dev/null +++ b/app/Ldap/LdapUser.php @@ -0,0 +1,162 @@ +setConfiguration([ + "hosts" => [$setting['ldap_host']], + "port" => intval($setting['ldap_port']), + "password" => $setting['ldap_password'], + "username" => $setting['ldap_cn'], + "base_dn" => $setting['ldap_dn'], + ]); + } + + /** + * 登录 + * @param $username + * @param $password + * @param User|null $user + * @return User|mixed|null + * @throws \LdapRecord\Configuration\ConfigurationException + */ + public static function userLogin($username, $password, $user = null) + { + self::initConfig(); + $row = self::static() + ->where([ + 'cn' => $username, + 'userPassword' => $password + ])->first(); + if (!$row) { + return null; + } + if ($user) { + return $user; + } + return User::reg($username, Base::generatePassword(32)); + } + + /** + * 添加 + * @param $userid + * @param $username + * @param $password + * @param $description + * @return void + * @throws \LdapRecord\Configuration\ConfigurationException + */ + public static function userReg($userid, $username, $password, $description = '') + { + self::initConfig(); + try { + self::static()->create([ + 'cn' => $username, + 'gidNumber' => 0, + 'homeDirectory' => '/home/ldap/dootask/' . env("APP_NAME"), + 'sn' => $username, + 'uid' => $username, + 'uidNumber' => $userid, + 'userPassword' => $password, + 'description' => $description, + ]); + } catch (LdapRecordException $e) { + throw new ApiException("reg ldap fail: " . $e->getMessage()); + } + } + + /** + * 更新 + * @param $username + * @param $array + * @return void + * @throws \LdapRecord\Configuration\ConfigurationException + */ + public static function userUpdate($username, $array) + { + self::initConfig(); + $row = self::static() + ->where([ + 'cn' => $username, + ])->first(); + try { + $row?->update($array); + } catch (LdapRecordException $e) { + throw new ApiException("update ldap fail: " . $e->getMessage()); + } + } + + /** + * 删除 + * @param $username + * @return void + * @throws \LdapRecord\Configuration\ConfigurationException + */ + public static function userDelete($username) + { + self::initConfig(); + $row = self::static() + ->where([ + 'cn' => $username, + ])->first(); + try { + $row?->delete(); + } catch (LdapRecordException $e) { + throw new ApiException("delete ldap fail: " . $e->getMessage()); + } + } +} diff --git a/composer.json b/composer.json index 8420b71ac..ea846c57d 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,7 @@ "ext-json": "*", "ext-libxml": "*", "ext-simplexml": "*", + "directorytree/ldaprecord-laravel": "^2.7", "fideloper/proxy": "^4.4.1", "fruitcake/laravel-cors": "^2.0.4", "guanguans/notify": "^1.21.1", diff --git a/config/ldap.php b/config/ldap.php new file mode 100644 index 000000000..fd94d32e7 --- /dev/null +++ b/config/ldap.php @@ -0,0 +1,73 @@ + env('LDAP_CONNECTION', 'default'), + + /* + |-------------------------------------------------------------------------- + | LDAP Connections + |-------------------------------------------------------------------------- + | + | Below you may configure each LDAP connection your application requires + | access to. Be sure to include a valid base DN - otherwise you may + | not receive any results when performing LDAP search operations. + | + */ + + 'connections' => [ + + 'default' => [ + 'hosts' => [env('LDAP_HOST', '127.0.0.1')], + 'username' => env('LDAP_USERNAME', 'cn=user,dc=local,dc=com'), + 'password' => env('LDAP_PASSWORD', 'secret'), + 'port' => env('LDAP_PORT', 389), + 'base_dn' => env('LDAP_BASE_DN', 'dc=local,dc=com'), + 'timeout' => env('LDAP_TIMEOUT', 5), + 'use_ssl' => env('LDAP_SSL', false), + 'use_tls' => env('LDAP_TLS', false), + ], + + ], + + /* + |-------------------------------------------------------------------------- + | LDAP Logging + |-------------------------------------------------------------------------- + | + | When LDAP logging is enabled, all LDAP search and authentication + | operations are logged using the default application logging + | driver. This can assist in debugging issues and more. + | + */ + + 'logging' => env('LDAP_LOGGING', true), + + /* + |-------------------------------------------------------------------------- + | LDAP Cache + |-------------------------------------------------------------------------- + | + | LDAP caching enables the ability of caching search results using the + | query builder. This is great for running expensive operations that + | may take many seconds to complete, such as a pagination request. + | + */ + + 'cache' => [ + 'enabled' => env('LDAP_CACHE', false), + 'driver' => env('CACHE_DRIVER', 'file'), + ], + +]; diff --git a/resources/assets/js/pages/manage/components/TeamManagement.vue b/resources/assets/js/pages/manage/components/TeamManagement.vue index 4a166a294..46e469318 100644 --- a/resources/assets/js/pages/manage/components/TeamManagement.vue +++ b/resources/assets/js/pages/manage/components/TeamManagement.vue @@ -338,6 +338,13 @@ export default { } })) } + if (identity.includes("ldap")) { + arr.push(h('Tag', { + props: { + color: 'orange' + } + }, this.$L('LDAP'))) + } if (identity.includes("admin")) { arr.push(h('Tag', { props: { diff --git a/resources/assets/js/pages/manage/setting/components/SystemAppPush.vue b/resources/assets/js/pages/manage/setting/components/SystemAppPush.vue index 4a807b3a1..17d1752f2 100644 --- a/resources/assets/js/pages/manage/setting/components/SystemAppPush.vue +++ b/resources/assets/js/pages/manage/setting/components/SystemAppPush.vue @@ -87,16 +87,6 @@ export default { this.loadIng--; }); }, - - hoursChange(e, key) { - let newNum = e * 10; - if (newNum % 5 !== 0) { - setTimeout(() => { - this.$set(this.formData, key, Math.round(e)) - }) - $A.messageError('任务提醒只能是0.5的倍数'); - } - }, } } diff --git a/resources/assets/js/pages/manage/setting/components/SystemEmailSetting.vue b/resources/assets/js/pages/manage/setting/components/SystemEmailSetting.vue index 12ef1d1a0..5eb0cbac3 100644 --- a/resources/assets/js/pages/manage/setting/components/SystemEmailSetting.vue +++ b/resources/assets/js/pages/manage/setting/components/SystemEmailSetting.vue @@ -133,16 +133,6 @@ export default { }); }, - hoursChange(e, key) { - let newNum = e * 10; - if (newNum % 5 !== 0) { - setTimeout(() => { - this.$set(this.formData, key, Math.round(e)) - }) - $A.messageError('任务提醒只能是0.5的倍数'); - } - }, - checkEmailSend() { $A.modalInput({ title: "测试邮件", diff --git a/resources/assets/js/pages/manage/setting/components/SystemThirdAccess.vue b/resources/assets/js/pages/manage/setting/components/SystemThirdAccess.vue new file mode 100644 index 000000000..87a0e605f --- /dev/null +++ b/resources/assets/js/pages/manage/setting/components/SystemThirdAccess.vue @@ -0,0 +1,112 @@ + + + diff --git a/resources/assets/js/pages/manage/setting/system.vue b/resources/assets/js/pages/manage/setting/system.vue index fc0d2293c..ef86ba849 100644 --- a/resources/assets/js/pages/manage/setting/system.vue +++ b/resources/assets/js/pages/manage/setting/system.vue @@ -19,6 +19,9 @@ + + + @@ -34,9 +37,11 @@ import SystemEmailSetting from "./components/SystemEmailSetting"; import SystemAppPush from "./components/SystemAppPush"; import SystemMeeting from "./components/SystemMeeting"; import SystemCheckin from "./components/SystemCheckin"; +import SystemThirdAccess from "./components/SystemThirdAccess"; export default { components: { + SystemThirdAccess, SystemCheckin, SystemMeeting, SystemAppPush, SystemColumnTemplate, SystemTaskPriority, SystemSetting, SystemEmailSetting},