diff --git a/application/config/navigation.php b/application/config/navigation.php index 11fd1a3a6..fa7f630b5 100644 --- a/application/config/navigation.php +++ b/application/config/navigation.php @@ -1,11 +1,27 @@ . + */ -if(defined('CIS4') && CIS4) { - $root = APP_ROOT; -} else { - $root = CIS_ROOT; -} +$root = CIS_ROOT; + +if (defined('CIS4') && CIS4) $root = APP_ROOT; + +// -------------------------------------------------------------------------------------------------------------------- +// Head menu $config['navigation_header'] = array( '*' => array( @@ -195,13 +211,20 @@ $config['navigation_header'] = array( 'sort' => 20, 'requiredPermissions' => 'system/developer:r' ), - 'anrechnungen' => array( - 'link' => site_url('lehre/anrechnung/AdminAnrechnung'), - 'description' => 'Anrechnungen', - 'expand' => true, - 'sort' => 30, - 'requiredPermissions' => 'lehre/anrechnungszeitfenster:rw' - ) + 'anrechnungen' => array( + 'link' => site_url('lehre/anrechnung/AdminAnrechnung'), + 'description' => 'Anrechnungen', + 'expand' => true, + 'sort' => 30, + 'requiredPermissions' => 'lehre/anrechnungszeitfenster:rw' + ), + 'loginas' => array( + 'link' => site_url('system/Login/loginAs'), + 'description' => 'Login as', + 'expand' => true, + 'sort' => 40, + 'requiredPermissions' => 'admin:rw' + ) ) ) ) @@ -222,12 +245,12 @@ $config['navigation_menu']['Vilesci/index'] = array( ); $config['navigation_menu']['Vilesci/index'] = array( - 'dashboard' => array( - 'link' => '#', - 'description' => 'Dashboard', - 'icon' => 'dashboard', - 'sort' => 1 - ) + 'dashboard' => array( + 'link' => '#', + 'description' => 'Dashboard', + 'icon' => 'dashboard', + 'sort' => 1 + ) ); $config['navigation_menu']['organisation/Reihungstest/index'] = array( @@ -336,3 +359,4 @@ $config['navigation_menu']['system/issues/Issues/*'] = array( 'requiredPermissions' => array('admin:rw') ), ); + diff --git a/application/controllers/api/frontend/v1/Login.php b/application/controllers/api/frontend/v1/Login.php new file mode 100644 index 000000000..5a2de4ed7 --- /dev/null +++ b/application/controllers/api/frontend/v1/Login.php @@ -0,0 +1,135 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * + */ +class Login extends FHCAPI_Controller +{ + /** + * Object initialization + */ + public function __construct() + { + parent::__construct(array( + 'loginLDAP' => self::PERM_ANONYMOUS, + 'loginASByUid' => 'admin:rw', + 'loginASByPersonId' => 'admin:rw', + 'whoAmI' => self::PERM_ANONYMOUS, + 'searchUser' => 'admin:rw' + )); + } + + /** + * Called with HTTP POST via ajax to login using the LDAP authentication + */ + public function loginLDAP() + { + $username = $this->input->post('username'); + $password = $this->input->post('password'); + + $this->load->library('AuthLib', array(false)); // without authentication otherwise loooooop! + + $login = $this->authlib->loginLDAP($username, $password); + + // If login is success then retrieves the desired page + if (isSuccess($login)) $this->terminateWithSuccess($this->authlib->getLandingPage()); + + $this->terminateWithError(getError($login)); // returns the error code + } + + /** + * Called with HTTP POST via ajax to login as another user specified by uid + */ + public function loginASByUid() + { + $uid = $this->input->post('uid'); + + // With authentication -> you must be already logged to gain another identity + $this->load->library('AuthLib'); + + $loginAS = $this->authlib->loginASByUID($uid); + + // Got it! + if (isSuccess($loginAS)) $this->terminateWithSuccess(true); + + // Returns the error code + $this->terminateWithError(getError($loginAS)); + } + + /** + * Called with HTTP POST via ajax to login as another user specified by person id + */ + public function loginASByPersonId() + { + $person_id = $this->input->post('person_id'); + + // With authentication -> you must be already logged to gain another identity + $this->load->library('AuthLib'); + + $loginAS = $this->authlib->loginASByPersonId($person_id); + + // Got it! + if (isSuccess($loginAS)) $this->terminateWithSuccess(true); + + // Returns the error code + $this->terminateWithError(getError($loginAS)); + } + + /** + * Called with HTTP GET via ajax to show which login cretentials are in use + */ + public function whoAmI() + { + // With authentication -> you must be already logged to gain another identity + $this->load->library('AuthLib'); + + $this->terminateWithSuccess($this->authlib->getAuthObj()); + } + + /** + * Search for a user in database checking the name, surname or uid + */ + public function searchUser() + { + $query = strtolower('%'.$this->input->get('query').'%'); + + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + + $dataset = $this->BenutzerModel->execReadOnlyQuery(' + SELECT p.person_id, + b.uid, + p.nachname, + p.vorname, + b.uid || \' - \' || p.nachname || \' \' || p.vorname AS label + FROM public.tbl_person p + LEFT JOIN public.tbl_benutzer b ON(b.person_id = p.person_id) + WHERE b.aktiv = TRUE + AND (p.nachname LIKE ? OR p.vorname = ? OR b.uid LIKE ?) + ', + array($query, $query, $query) + ); + + if (isError($dataset)) $this->terminateWithError(getError($dataset)); + + $this->terminateWithSuccess($dataset); + } +} + diff --git a/application/controllers/system/Login.php b/application/controllers/system/Login.php index 293a25552..42fb54d77 100644 --- a/application/controllers/system/Login.php +++ b/application/controllers/system/Login.php @@ -1,4 +1,20 @@ . + */ if (!defined('BASEPATH')) exit('No direct script access allowed'); @@ -8,12 +24,14 @@ if (!defined('BASEPATH')) exit('No direct script access allowed'); class Login extends FHC_Controller { /** - * + * Object initialization */ public function __construct() - { - parent::__construct(); - } + { + parent::__construct(array( + 'loginAs' => 'admin:rw' + )); + } /** * Displays a login page with username and password @@ -24,72 +42,11 @@ class Login extends FHC_Controller } /** - * Called with HTTP POST via ajax to login using the LDAP authentication + * Displays a login page with username and password */ - public function loginLDAP() - { - $username = $this->input->post('username'); - $password = $this->input->post('password'); - - $this->load->library('AuthLib', array(false)); // without authentication otherwise loooooop! - - $login = $this->authlib->loginLDAP($username, $password); - if (isSuccess($login)) - { - $this->outputJsonSuccess($this->authlib->getLandingPage()); // if login is success then retrieves the desired page - } - else - { - $this->outputJsonError(getCode($login)); // returns the error code - } - } - - /** - * Called with HTTP POST via ajax to login as another user specified by uid - */ - public function loginASByUid() - { - $uid = $this->input->get('uid'); - - // With authentication -> you must be already logged to gain another identity - $this->load->library('AuthLib'); - - $loginAS = $this->authlib->loginASByUID($uid); - $this->outputJson($loginAS); // returns the error code - } - - /** - * Called with HTTP POST via ajax to login as another user specified by person id - */ - public function loginASByPersonId() - { - $person_id = $this->input->get('person_id'); - - // With authentication -> you must be already logged to gain another identity - $this->load->library('AuthLib'); - - $loginAS = $this->authlib->loginASByPersonId($person_id); - if (isSuccess($loginAS)) - { - $this->outputJsonSuccess(true); // obtained! - } - else - { - $this->outputJsonSuccess(getCode($loginAS)); // returns the error code - }; - } - - /** - * To login into the system with email and code as credentials - */ - public function emailCode() - { - } - - /** - * To login into the system using SSO - */ - public function sso() + public function loginAs() { + $this->load->view('system/login/loginAs'); } } + diff --git a/application/views/system/login/loginAs.php b/application/views/system/login/loginAs.php new file mode 100644 index 000000000..46304311c --- /dev/null +++ b/application/views/system/login/loginAs.php @@ -0,0 +1,39 @@ +. + */ + +$includesArray = array( + 'title' => 'Login', + 'axios027' => true, + 'bootstrap5' => true, + 'fontawesome6' => true, + 'vue3' => true, + 'filtercomponent' => true, + 'navigationcomponent' => true, + 'tabulator5' => true, + 'primevue3' => true, + 'phrases' => array('uid', 'global'), + 'customJSModules' => array('public/js/LoginAs.js'), +); + +$this->load->view('templates/FHC-Header', $includesArray); +?> + +
+ +load->view('templates/FHC-Footer', $includesArray); ?> + diff --git a/application/views/system/login/usernamePassword.php b/application/views/system/login/usernamePassword.php index d695089b4..f750504f1 100644 --- a/application/views/system/login/usernamePassword.php +++ b/application/views/system/login/usernamePassword.php @@ -1,44 +1,39 @@ load->view( - 'templates/FHC-Header', - array( - 'title' => 'Login', - 'jquery3' => true, - 'jqueryui1' => true, - 'bootstrap3' => true, - 'fontawesome4' => true, - 'sbadmintemplate3' => true, - 'ajaxlib' => true, - 'dialoglib' => true, - 'customCSSs' => 'public/css/Login.css', - 'customJSs' => 'public/js/Login.js' - ) - ); +/** + * Copyright (C) 2025 fhcomplete.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +$includesArray = array( + 'title' => 'Login', + 'axios027' => true, + 'bootstrap5' => true, + 'fontawesome6' => true, + 'vue3' => true, + 'filtercomponent' => true, + 'navigationcomponent' => true, + 'tabulator5' => true, + 'primevue3' => true, + 'phrases' => array('uid', 'global'), + 'customJSModules' => array('public/js/Login.js'), +); + +$this->load->view('templates/FHC-Header', $includesArray); ?> +
-
+load->view('templates/FHC-Footer', $includesArray); ?> -

- -

- -
- -
- -
- -
- -
- -
- -
- -

Forgot Password?

- -
- -load->view('templates/FHC-Footer'); ?> diff --git a/public/js/Login.js b/public/js/Login.js index 0cc7faf8d..24695da3d 100644 --- a/public/js/Login.js +++ b/public/js/Login.js @@ -1,55 +1,79 @@ - /** - * To login via LDAP + * Copyright (C) 2025 fhcomplete.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ -function loginLDAP() -{ - // Ajax call to login with LDAP - FHC_AjaxClient.ajaxCallPost( - "system/Login/loginLDAP", - { - username: $("#username").val(), - password: $("#password").val() - }, - { - successCallback: function(data, textStatus, jqXHR) { - if (FHC_AjaxClient.isError(data)) - { - if (FHC_AjaxClient.getError(data) == 10) +import PluginsPhrasen from '../js/plugins/Phrasen.js'; +import ApiLogin from '../js/api/factory/login.js'; + +const loginApp = Vue.createApp({ + data: function() { + return { + username: '', + password: '' + }; + }, + components: { + }, + methods: { + loginLDAP: function() { + this.$api + .call(ApiLogin.loginLDAP({ + username: this.username, + password: this.password + })) + .then((response) => { + // If property data exists + if (Object.hasOwn(response, 'data')) { - FHC_DialogLib.alertError("Username not foud"); + // If property data is a string + if (typeof response.data === 'string' || response.data instanceof String) + { + // If property data is a valid URL + try { + let url = new URL(response.data); + // If here the URL contained in response.data is fine + // and can be used to switch to the landing page + document.location.href = response.data; + } catch (_) {} + } } - if (FHC_AjaxClient.getError(data) == 2) - { - FHC_DialogLib.alertError("Wrong password"); - } - } - else - { - $(location).attr("href", FHC_AjaxClient.getData(data)); - } - }, - errorCallback: function(jqXHR, textStatus, errorThrown) { - FHC_DialogLib.alertError(textStatus); - } - } - ); -} - -/** - * When JQuery is up - */ -$(document).ready(function() { - - $("#btnLogin").click(loginLDAP); - - $("#username").keydown(function(e) { - if (e.keyCode == 13) loginLDAP(); - }) - - $("#password").keydown(function(e) { - if (e.keyCode == 13) loginLDAP(); - }) - + }) + .catch((error) => { + console.error(error); + }); + } +}, + template: ` +
+
+
+ + +
+
+ + +
+
+ +
+
+
+ ` }); + +loginApp.use(PluginsPhrasen).mount('#main'); + diff --git a/public/js/LoginAs.js b/public/js/LoginAs.js new file mode 100644 index 000000000..2ce7e152b --- /dev/null +++ b/public/js/LoginAs.js @@ -0,0 +1,168 @@ +/** + * Copyright (C) 2025 fhcomplete.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import PluginsPhrasen from '../js/plugins/Phrasen.js'; +import ApiLogin from '../js/api/factory/login.js'; + +import {CoreNavigationCmpt} from '../js/components/navigation/Navigation.js'; +import PvAutoComplete from "../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js"; + +const loginAsApp = Vue.createApp({ + data: function() { + return { + person_id: '', + username: '', + surname: '', + name: '', + selectedUser: null, + filteredUsers: [], + appSideMenuEntries: {} + }; + }, + components: { + CoreNavigationCmpt, + PvAutoComplete + }, + methods: { + loginAs: function() { + if (this.selectedUser != null) + { + this.$api + .call(ApiLogin.loginASByPersonId({ + person_id: this.selectedUser.person_id + })) + .then((response) => { + location.reload(); + }) + .catch((error) => { + console.error(error); + }); + } + }, + logout: function() { + this.$api + .call(ApiLogin.logout()) + .then((response) => { + location.reload(); + }) + .catch((error) => { + console.error(error); + }); + }, + searchUser: function(event) { + if (event.query.length >= 3) + { + this.$api + .call(ApiLogin.searchUser(event.query)) + .then(result => { + this.filteredUsers = result.data.retval; + }) + .catch((error) => { + console.error(error); + }); + } + } + }, + mounted: function() { + this.$api + .call(ApiLogin.whoAmI()) + .then((response) => { + // If property data exists + if (Object.hasOwn(response, 'data')) + { + if (response.data != null && Object.hasOwn(response.data, 'person_id')) + { + this.person_id = response.data.person_id; + this.username = response.data.username; + this.surname = response.data.surname; + this.name = response.data.name; + } + else + { + this.person_id = 'Not logged'; + this.username = 'Not logged'; + this.surname = 'Not logged'; + this.name = 'Not logged'; + } + } + }) + .catch((error) => { + console.error(error); + }); + }, + template: ` + + +
+
+
+ Who am I? +
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+ +
+
+
+
+ Who I want to be? +
+
+
+ +
+
+
+ +
+
+
+ ` +}); + +loginAsApp. + use(PluginsPhrasen). + use(primevue.config.default, { + zIndex: { + overlay: 1100 + } + }). + mount('#main'); + diff --git a/public/js/api/factory/login.js b/public/js/api/factory/login.js new file mode 100644 index 000000000..d8a37078f --- /dev/null +++ b/public/js/api/factory/login.js @@ -0,0 +1,59 @@ +/** + * Copyright (C) 2025 fhcomplete.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +export default { + loginLDAP(params) { + return { + method: 'post', + url: '/api/frontend/v1/Login/loginLDAP', + params + }; + }, + loginASByUid(params) { + return { + method: 'post', + url: '/api/frontend/v1/Login/loginASByUid', + params + }; + }, + loginASByPersonId(params) { + return { + method: 'post', + url: '/api/frontend/v1/Login/loginASByPersonId', + params + }; + }, + whoAmI() { + return { + method: 'get', + url: '/api/frontend/v1/Login/whoAmI' + }; + }, + logout() { + return { + method: 'get', + url: '/system/Logout' + }; + }, + searchUser(query) { + return { + method: 'get', + url: '/api/frontend/v1/Login/searchUser?query=' + encodeURIComponent(query) + }; + } +}; +