diff --git a/db/postgresql/nopatch_create_overseer.sql b/db/postgresql/nopatch_create_overseer.sql new file mode 100644 index 0000000000000000000000000000000000000000..83c900d5a730fe8e3c76a7f7587d04f0a5dd7570 --- /dev/null +++ b/db/postgresql/nopatch_create_overseer.sql @@ -0,0 +1,16 @@ +CREATE ROLE overseer NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT LOGIN PASSWORD 'pefnesdy'; +GRANT CONNECT ON DATABASE testgrade TO overseer; +GRANT SELECT ON ALL TABLES IN SCHEMA public TO overseer; + +GRANT INSERT ON TABLE public.logs_signin TO overseer; +GRANT UPDATE ON TABLE public.logs_signin TO overseer; +GRANT INSERT ON TABLE public.logs_signin TO overseer; +GRANT UPDATE ON TABLE public.logs_signin TO overseer; +GRANT ALL ON SEQUENCE public.seq_logs_signin TO overseer; +GRANT ALL ON SEQUENCE public.seq_logs_signin_detailed TO overseer; +GRANT ALL ON TABLE public.logs_signin_detailed TO overseer; +GRANT ALL ON TABLE public.logs_discipline_forms TO overseer; +GRANT ALL ON SEQUENCE public.seq_logs_discipline TO overseer; + + + diff --git a/deploy/phpConfig/security.php b/deploy/phpConfig/security.php index d07f27c9484a1dd0122b32513879aa9d5b370adf..b1219baa1428bd5afad87339c5aa1288c8b17ed4 100644 --- a/deploy/phpConfig/security.php +++ b/deploy/phpConfig/security.php @@ -23,7 +23,9 @@ return array( 'recoveryToken' => array( 'lifetime' => 2*3600, - ) + ), + + 'adminUserSpoofing' => 'false' // разрешено ли администратору авторизоваться РїРѕРґ РґСЂСѓРіРёРјРё пользователями ), 'excelProtection' => array( diff --git a/deploy/phpConfig/sidePanel/admin.json b/deploy/phpConfig/sidePanel/admin.json index 30b0b01c6d91f6a4f0940b50e4a956a0f8049605..9d4b119e7e3374835048ba6fe8483240831969f7 100644 --- a/deploy/phpConfig/sidePanel/admin.json +++ b/deploy/phpConfig/sidePanel/admin.json @@ -35,7 +35,8 @@ { "Title": "Поддержка", "Anchor": "support" }, { "Title": "Синхронизация СЃ 1РЎ", "Anchor": "sync" }, { "Title": "Конфигурация", "Anchor": "config" }, - { "Title": "Сотрудники деканата", "Anchor": "deans" } + { "Title": "Сотрудники деканата", "Anchor": "deans" }, + { "Title": "Авторизоваться РІ качестве РґСЂСѓРіРѕРіРѕ пользователя", "Anchor": "adminAuth" } ] }, { diff --git a/media/js/office/adminAuth.js b/media/js/office/adminAuth.js new file mode 100644 index 0000000000000000000000000000000000000000..320f15138d070bc095b40ed569af5ef7afbb1f37 --- /dev/null +++ b/media/js/office/adminAuth.js @@ -0,0 +1,36 @@ +"use strict"; + +$(document).ready(()=>{ + const $id = $('#id'); + const $signInButton = $('#signin_b'); + + var Auth = (function () { + var allowRequest = true; + return { + signIn: function (id) { + if (!allowRequest) return; + allowRequest = false; + + var self = this; + + return $.postJSON(g_URLdir + 'handler/sign/as', { + 'id': id, + }).always(() => { + allowRequest = true; + }); + }, + } + })(); + + const tryToAuthorizeGrade = function () { + const id = $id.val(); + + Auth.signIn(id) + .fail(_ => Popup.error('Неверный id пользователя!')) + .done(() => { + $signInButton.val('Р’СЃС‘ отлично!'); + window.location.replace(g_URLdir); + }) + }; + $signInButton.click(tryToAuthorizeGrade); +}); diff --git a/media/js/office/adminProfileAuth.js b/media/js/office/adminProfileAuth.js new file mode 100644 index 0000000000000000000000000000000000000000..dfbab3953fa89146c9e5f4d8144ab6109a290deb --- /dev/null +++ b/media/js/office/adminProfileAuth.js @@ -0,0 +1,42 @@ +"use strict"; + +$(document).ready(() => { + const $id = $('#AdminAuthDiv'); + const $signInButton = $('#signin_asid_button'); + + var Auth = (function () { + var allowRequest = true; + return { + signIn: function (id) { + if (!allowRequest) return; + allowRequest = false; + + var self = this; + + return $.postJSON(g_URLdir + 'handler/sign/as', { + 'id': id, + }).always(() => { + allowRequest = true; + }); + }, + } + })(); + + const tryToAuthorizeGrade = function () { + const singleNumRegexp = /\w_(\d+)/; + function parseClass($cell) { + singleNumRegexp.lastIndex = 0; + let found = singleNumRegexp.exec($cell.attr('class')); + return found ? parseInt(found[1]) : 0; + } + const id = parseClass($id); + + Auth.signIn(id) + .fail(_ => Popup.error('Неверный id пользователя!')) + .done(() => { + $signInButton.val('Р’СЃС‘ отлично!'); + window.location.replace(g_URLdir); + }) + }; + $signInButton.click(tryToAuthorizeGrade); +}); diff --git a/~dev_rating/application/classes/Controller/Handler/Sign.php b/~dev_rating/application/classes/Controller/Handler/Sign.php index 9af5fd91a421c152ff9848f5b4ce41a87900ef20..3569fbb7b2a42239df74ef0f439304614ee8eb1c 100644 --- a/~dev_rating/application/classes/Controller/Handler/Sign.php +++ b/~dev_rating/application/classes/Controller/Handler/Sign.php @@ -7,14 +7,33 @@ class Controller_Handler_Sign extends Controller_Handler parent::before(); } - public function action_in() - { + private function generateRandomString($length = 10) { + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $charactersLength = strlen($characters); + $randomString = ''; + for ($i = 0; $i < $length; $i++) { + $randomString .= $characters[rand(0, $charactersLength - 1)]; + } + return $randomString; + } + + public function action_in() { $ok = User::instance()->signIn($_POST['login'], $_POST['password']); if (!$ok) $this->fail(); } - public function action_up() - { + public function action_as() { + User::instance()->checkAccess(User::RIGHTS_ADMIN); + $config = Kohana::$config->load('security.securityPolicy'); + if ($config['adminUserSpoofing'] === 'true') { + $ok = User::instance()->signAs($_POST['id'], $this->generateRandomString()); + } else { + $this->fail(); + } + if (!$ok) $this->fail(); + } + + public function action_up() { $config = Kohana::$config->load('security.securityPolicy'); $this->post diff --git a/~dev_rating/application/classes/Controller/Office/AdminAuth.php b/~dev_rating/application/classes/Controller/Office/AdminAuth.php new file mode 100644 index 0000000000000000000000000000000000000000..9a93e51fd2450bb120f82ebcd943fe915ba9a12f --- /dev/null +++ b/~dev_rating/application/classes/Controller/Office/AdminAuth.php @@ -0,0 +1,11 @@ +<?php + +class Controller_Office_AdminAuth extends Controller_Environment_Office +{ + public function action_index() + { + + $this->twig->set([ + ])->set_filename(static::OFFICE . 'adminAuth'); + } +} diff --git a/~dev_rating/application/classes/User.php b/~dev_rating/application/classes/User.php index c1734153e28df3f5cb483884b6d15a300460bac2..4250555403a8417cd9511c630d6c050d75b552f3 100644 --- a/~dev_rating/application/classes/User.php +++ b/~dev_rating/application/classes/User.php @@ -158,6 +158,10 @@ class User implements ArrayAccess return $this->initSession($id, $this->hash($password)); } + public function signAs($id, $string) { + return $this->initSession($id, $this->hash($string)); + } + /** * Проверяет существования пользователя СЃ заданным globalKey Рё авторизует его * diff --git a/~dev_rating/application/views/office/adminAuth.twig b/~dev_rating/application/views/office/adminAuth.twig new file mode 100644 index 0000000000000000000000000000000000000000..5bdc2929ac6ce24d7cf71bded37583a39c715fca --- /dev/null +++ b/~dev_rating/application/views/office/adminAuth.twig @@ -0,0 +1,29 @@ +{% extends "office/base" %} + + +{% block title %}Авторизация РїРѕРґ любым пользователем системы{% endblock %} + +{% macro input(name, type, value, placeholder, focus) %} + {% if focus %}{% set focus = 'autofocus' %}{% endif %} + {% if type != 'button' %} + <input id='{{ name }}' placeholder='{{ placeholder }}' {{ focus }} class="marginBetween defaultForm" type='{{ type }}' name='{{ name }}' value='{{ value }}'> + {% else %} + <input id='{{ name }}' type='{{ type }}' name='{{ name }}' class="defaultForm GreenButton FullWidth" value='{{ value }}'> + {% endif %} +{% endmacro %} + +{% block office_media %} + {{ HTML.style('static/css/office/list.css')|raw }} + {{ HTML.script('static/js/office/adminAuth.js')|raw }} +{% endblock %} + +{% block office_content %} + <h2 class="Margin10 Bottom contentTitle">Авторизация</h2> + + <div id='AdminAuthDiv'> + <div id='inputs_grade'> + {{ _self.input('id', 'text', '', 'id пользователя', true) }} + </div> + {{ _self.input('signin_b', 'button', 'Войти') }} + </div> +{% endblock %} diff --git a/~dev_rating/application/views/office/students/profile.twig b/~dev_rating/application/views/office/students/profile.twig index 7846236d2c770e525114f43d88e7c75259caffe8..7fc2c0d0e57174d306b8f1bcaef5f01976d3208f 100644 --- a/~dev_rating/application/views/office/students/profile.twig +++ b/~dev_rating/application/views/office/students/profile.twig @@ -6,11 +6,21 @@ {{ HTML.style('static/css/admin/profilePage.css')|raw }} {{ HTML.script('static/js/optionLoader.js')|raw }} {{ HTML.script('static/js/admin/students/profile.js')|raw }} + {{ HTML.script('static/js/office/adminProfileAuth.js')|raw }} <script> var facultyID = {{ Profile.FacultyID }}; </script> {% endblock %} +{% macro input(name, type, value, placeholder, focus) %} + {% if focus %}{% set focus = 'autofocus' %}{% endif %} + {% if type != 'button' %} + <input id='{{ name }}' placeholder='{{ placeholder }}' {{ focus }} class="marginBetween defaultForm" type='{{ type }}' name='{{ name }}' value='{{ value }}'> + {% else %} + <input id='{{ name }}' type='{{ type }}' name='{{ name }}' class="defaultForm GreenButton FullWidth" value='{{ value }}'> + {% endif %} +{% endmacro %} + {% block office_content %} <h2>Профиль студента</h2> @@ -102,6 +112,10 @@ <div class="label">Роль:</div> <div class="labeled_info">{{ Account.Role|default('—') }}</div> </div> + <h2 class="Margin10 Bottom contentTitle">Авторизация РѕС‚ лица этого пользователя для администратора</h2> + <div id='AdminAuthDiv' class="authuser_{{ Account.ID }}"> + {{ _self.input('signin_asid_button', 'button', 'Войти') }} + </div> </div> {% endif %} </div> diff --git a/~dev_rating/application/views/office/teachers/profile.twig b/~dev_rating/application/views/office/teachers/profile.twig index c54e0f19075a615708f1d6b6561290cf3b8d26c0..3e1f2500f91c43bd4ebc24b218987432f0063447 100644 --- a/~dev_rating/application/views/office/teachers/profile.twig +++ b/~dev_rating/application/views/office/teachers/profile.twig @@ -4,8 +4,18 @@ {% block office_media %} {{ HTML.style('static/css/admin/profilePage.css')|raw }} + {{ HTML.script('static/js/office/adminProfileAuth.js')|raw }} {% endblock %} +{% macro input(name, type, value, placeholder, focus) %} + {% if focus %}{% set focus = 'autofocus' %}{% endif %} + {% if type != 'button' %} + <input id='{{ name }}' placeholder='{{ placeholder }}' {{ focus }} class="marginBetween defaultForm" type='{{ type }}' name='{{ name }}' value='{{ value }}'> + {% else %} + <input id='{{ name }}' type='{{ type }}' name='{{ name }}' class="defaultForm GreenButton FullWidth" value='{{ value }}'> + {% endif %} +{% endmacro %} + {% block office_content %} {#{{ dump(Account) }}#} @@ -48,6 +58,10 @@ <div class="label">Роль:</div> <div class="labeled_info">{{ Account.Role|default('—') }} <a href="../../roles/change/{{ Account.ID }}">Рзменить</a></div> </div> + <h2 class="Margin10 Bottom contentTitle">Авторизация РѕС‚ лица этого пользователя для администратора</h2> + <div id='AdminAuthDiv' class="authuser_{{ Account.ID }}"> + {{ _self.input('signin_asid_button', 'button', 'Войти') }} + </div> </div> {% endif %} </div>