Passed
Push — develop ( 73b673...d6f831 )
by Nikolay
05:32
created

SessionController::endAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
/*
3
 * MikoPBX - free phone system for small business
4
 * Copyright (C) 2017-2020 Alexey Portnov and Nikolay Beketov
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with this program.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
namespace MikoPBX\AdminCabinet\Controllers;
21
22
use MikoPBX\AdminCabinet\Forms\LoginForm;
23
use MikoPBX\Common\Models\AuthTokens;
24
use MikoPBX\Common\Models\PbxSettings;
25
use MikoPBX\Common\Providers\PBXConfModulesProvider;
26
use MikoPBX\Modules\Config\WebUIConfigInterface;
27
28
/**
29
 * SessionController
30
 *
31
 * Allows to authenticate users
32
 */
33
class SessionController extends BaseController
34
{
35
    public function indexAction(): void
36
    {
37
        $this->view->NameFromSettings
38
            = PbxSettings::getValueByKey('Name');
39
        $this->view->DescriptionFromSettings
40
            = PbxSettings::getValueByKey('Description');
41
        $this->view->form = new LoginForm();
42
    }
43
44
    /**
45
     * This action authenticate and logs an user into the application
46
     *
47
     */
48
    public function startAction(): void
49
    {
50
        if (!$this->request->isPost()) {
51
            $this->forward('session/index');
52
        }
53
        $loginFromUser = $this->request->getPost('login');
54
        $passFromUser = $this->request->getPost('password');
55
        $this->flash->clear();
56
        $login = PbxSettings::getValueByKey('WebAdminLogin');
57
        $password = PbxSettings::getValueByKey('WebAdminPassword');
58
59
        $userLoggedIn = false;
60
        $sessionParams = [];
61
        if ($password === $passFromUser && $login === $loginFromUser) {
62
            $sessionParams = [
63
                'role' => 'admins',
64
                'homePage'=>'extensions/index'
65
            ];
66
            $userLoggedIn = true;
67
        } else {
68
            // Try to authenticate user over additional module
69
            $additionalModules = PBXConfModulesProvider::hookModulesMethodWithArrayResult(WebUIConfigInterface::AUTHENTICATE_USER, [$loginFromUser, $passFromUser]);
70
            foreach ($additionalModules as $moduleUniqueId => $sessionData) {
71
                if (!empty($sessionData)) {
72
                    $this->loggerAuth->info("User $login was authenticated over module $moduleUniqueId");
73
                    $sessionParams = $sessionData;
74
                    $userLoggedIn = true;
75
                    break;
76
                }
77
            }
78
        }
79
80
        if ($userLoggedIn) {
81
            $this->_registerSession($sessionParams);
82
            $this->updateSystemLanguage();
83
            $this->view->success = true;
84
            $backUri = $this->request->getPost('backUri');
85
            if (!empty($backUri)) {
86
                $this->view->reload = $backUri;
87
            } else {
88
                $this->view->reload = 'index/index';
89
            }
90
        } else {
91
            $this->view->success = false;
92
            $this->flash->error($this->translation->_('auth_WrongLoginPassword'));
93
            $remoteAddress = $this->request->getClientAddress(true);
94
            $userAgent = $this->request->getUserAgent();
95
            $this->loggerAuth->warning("From: {$remoteAddress} UserAgent:{$userAgent} Cause: Wrong password");
96
            $this->clearAuthCookies();
97
        }
98
99
    }
100
101
    /**
102
     * Register an authenticated user into session data
103
     *
104
     */
105
    private function _registerSession(array $sessionParams): void
106
    {
107
        $this->session->set('auth', $sessionParams);
108
109
        if ($this->request->getPost('rememberMeCheckBox') === 'on') {
110
            $this->updateRememberMeCookies($sessionParams);
111
        } else {
112
            $this->clearAuthCookies();
113
        }
114
    }
115
116
    /**
117
     * Setups random password and selector to browser cookie storage to remember me facility
118
     *
119
     * @param array $sessionParams
120
     */
121
    private function updateRememberMeCookies(array $sessionParams): void
122
    {
123
        $cookieExpirationTime = time() + (30 * 24 * 60 * 60);  // for 1 month
124
125
        $randomPassword = $this->security->getSaltBytes(32);
126
        $this->cookies->set("random_token", $randomPassword, $cookieExpirationTime);
127
128
        $randomPasswordHash = $this->security->hash($randomPassword);
129
130
        $expiryDate = date("Y-m-d H:i:s", $cookieExpirationTime);
131
132
        // Get token for username
133
        $parameters = [
134
            'conditions' => 'tokenHash = :tokenHash:',
135
            'binds' => [
136
                'tokenHash' => $randomPasswordHash,
137
            ],
138
        ];
139
        $userToken = AuthTokens::findFirst($parameters);
140
        if ($userToken === null) {
141
            $userToken = new AuthTokens();
142
        }
143
        // Insert new token
144
        $userToken->tokenHash = $randomPasswordHash;
145
        $userToken->expiryDate = $expiryDate;
146
        $userToken->sessionParams = json_encode($sessionParams);
147
        $userToken->save();
148
    }
149
150
    /**
151
     * Clears remember me cookies
152
     */
153
    private function clearAuthCookies(): void
154
    {
155
        if ($this->cookies->has('random_token')) {
156
            $cookie = $this->cookies->get('random_token');
157
            $value = $cookie->getValue();
158
            $userTokens = AuthTokens::find();
159
            foreach ($userTokens as $userToken) {
160
                if ($this->security->checkHash($value, $userToken->tokenHash)) {
161
                    $userToken->delete();
162
                }
163
            }
164
            $cookie->delete();
165
        }
166
    }
167
168
    /**
169
     * Updates system settings for language
170
     *
171
     */
172
    private function updateSystemLanguage(): void
173
    {
174
        $newLanguage = $this->session->get('WebAdminLanguage');
175
        if (!isset($newLanguage)) {
176
            return;
177
        }
178
        $languageSettings = PbxSettings::findFirstByKey('WebAdminLanguage');
179
        if ($languageSettings === null) {
180
            $languageSettings = new PbxSettings();
181
            $languageSettings->key = 'WebAdminLanguage';
182
            $languageSettings->value = PbxSettings::getDefaultArrayValues()['WebAdminLanguage'];
183
        }
184
        if ($newLanguage !== $languageSettings->value) {
185
            $languageSettings->value = $newLanguage;
186
            $languageSettings->save();
187
        }
188
    }
189
190
    /**
191
     * Process language change
192
     */
193
    public function changeLanguageAction(): void
194
    {
195
        $newLanguage = $this->request->getPost('newLanguage', 'string');
196
        if (array_key_exists($newLanguage, $this->elements->getAvailableWebAdminLanguages())) {
197
            $this->session->set('WebAdminLanguage', $newLanguage);
198
            if ($this->session->has('auth')) {
199
                $this->updateSystemLanguage();
200
            }
201
            $this->view->success = true;
202
        } else {
203
            $this->view->success = false;
204
        }
205
    }
206
207
    /**
208
     * Finishes the active session redirecting to the index
209
     *
210
     */
211
    public function endAction(): void
212
    {
213
        $this->session->remove('auth');
214
        $this->session->destroy();
215
        $this->clearAuthCookies();
216
    }
217
}
218