Subversion Repositories oidplus

Rev

Rev 454 | Rev 457 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
5
 * Copyright 2019 Daniel Marschall, ViaThinkSoft
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
20
class OIDplusAuthUtils {
21
 
14 daniel-mar 22
        // RA authentication functions
2 daniel-mar 23
 
24
        public static function raLogin($email) {
25
                if (strpos($email, '|') !== false) return;
26
 
42 daniel-mar 27
                $ses = OIDplus::sesHandler();
2 daniel-mar 28
                $list = $ses->getValue('oidplus_logged_in');
29
                if (is_null($list)) $list = '';
30
 
31
                $ary = ($list == '') ? array() : explode('|', $list);
32
                if (!in_array($email, $ary)) $ary[] = $email;
33
                $list = implode('|', $ary);
34
 
35
                $ses->setValue('oidplus_logged_in', $list);
36
        }
37
 
38
        public static function raLogout($email) {
42 daniel-mar 39
                $ses = OIDplus::sesHandler();
2 daniel-mar 40
                $list = $ses->getValue('oidplus_logged_in');
41
                if (is_null($list)) $list = '';
42
 
43
                $ary = ($list == '') ? array() : explode('|', $list);
44
                $key = array_search($email, $ary);
45
                if ($key !== false) unset($ary[$key]);
46
                $list = implode('|', $ary);
47
 
48
                $ses->setValue('oidplus_logged_in', $list);
85 daniel-mar 49
 
179 daniel-mar 50
                if (($list == '') && (!self::isAdminLoggedIn())) {
85 daniel-mar 51
                        // Nobody logged in anymore. Destroy session cookie to make GDPR people happy
52
                        $ses->destroySession();
53
                }
2 daniel-mar 54
        }
55
 
329 daniel-mar 56
        public static function raCheckPassword($ra_email, $password) {
57
                $ra = new OIDplusRA($ra_email);
453 daniel-mar 58
 
59
                list($salt, $authkey) = $ra->getAuthInfo();
60
 
61
                $plugins = OIDplus::getAuthPlugins();
62
                if (count($plugins) == 0) {
63
                        throw new OIDplusException(_L('No RA authentication plugins found'));
64
                }
65
                foreach ($plugins as $plugin) {
66
                        if ($plugin->verify($authkey, $salt, $password)) return true;
67
                }
68
 
69
                return false;
329 daniel-mar 70
        }
71
 
85 daniel-mar 72
        public static function raNumLoggedIn() {
329 daniel-mar 73
                return count(self::loggedInRaList());
85 daniel-mar 74
        }
75
 
2 daniel-mar 76
        public static function raLogoutAll() {
42 daniel-mar 77
                $ses = OIDplus::sesHandler();
2 daniel-mar 78
                $ses->setValue('oidplus_logged_in', '');
79
        }
80
 
81
        public static function loggedInRaList() {
329 daniel-mar 82
                if (self::forceAllLoggedOut()) {
282 daniel-mar 83
                        return array();
84
                }
329 daniel-mar 85
 
42 daniel-mar 86
                $ses = OIDplus::sesHandler();
2 daniel-mar 87
                $list = $ses->getValue('oidplus_logged_in');
88
                if (is_null($list)) $list = '';
115 daniel-mar 89
 
90
                $res = array();
329 daniel-mar 91
                foreach (array_unique(explode('|',$list)) as $ra_email) {
115 daniel-mar 92
                        if ($ra_email == '') continue;
93
                        $res[] = new OIDplusRA($ra_email);
94
                }
95
                return $res;
2 daniel-mar 96
        }
97
 
98
        public static function isRaLoggedIn($email) {
115 daniel-mar 99
                foreach (self::loggedInRaList() as $ra) {
100
                        if ($email == $ra->raEmail()) return true;
101
                }
102
                return false;
2 daniel-mar 103
        }
104
 
14 daniel-mar 105
        // Admin authentication functions
2 daniel-mar 106
 
107
        public static function adminLogin() {
42 daniel-mar 108
                $ses = OIDplus::sesHandler();
2 daniel-mar 109
                $ses->setValue('oidplus_admin_logged_in', '1');
110
        }
111
 
112
        public static function adminLogout() {
42 daniel-mar 113
                $ses = OIDplus::sesHandler();
85 daniel-mar 114
                $ses->setValue('oidplus_admin_logged_in', '0');
115
 
116
                if (self::raNumLoggedIn() == 0) {
117
                        // Nobody logged in anymore. Destroy session cookie to make GDPR people happy
118
                        $ses->destroySession();
119
                }
2 daniel-mar 120
        }
121
 
122
        public static function adminCheckPassword($password) {
421 daniel-mar 123
                $passwordData = OIDplus::baseConfig()->getValue('ADMIN_PASSWORD', '');
124
                if (empty($passwordData)) {
360 daniel-mar 125
                        throw new OIDplusException(_L('No admin password set in %1','userdata/baseconfig/config.inc.php'));
261 daniel-mar 126
                }
456 daniel-mar 127
 
421 daniel-mar 128
                if (strpos($passwordData, '$') !== false) {
456 daniel-mar 129
                        if ($passwordData[0] == '$') {
130
                                // Version 3: BCrypt
131
                                return password_verify($password, $passwordData);
132
                        } else {
133
                                // Version 2: SHA3-512 without salt
134
                                list($s_salt, $hash) = explode('$', $passwordData, 2);
135
                        }
421 daniel-mar 136
                } else {
456 daniel-mar 137
                        // Version 1: SHA3-512 without salt
421 daniel-mar 138
                        $s_salt = '';
139
                        $hash = $passwordData;
140
                }
141
                return strcmp(sha3_512($s_salt.$password, true), base64_decode($hash)) === 0;
2 daniel-mar 142
        }
143
 
144
        public static function isAdminLoggedIn() {
329 daniel-mar 145
                if (self::forceAllLoggedOut()) {
282 daniel-mar 146
                        return false;
147
                }
42 daniel-mar 148
                $ses = OIDplus::sesHandler();
2 daniel-mar 149
                return $ses->getValue('oidplus_admin_logged_in') == '1';
150
        }
151
 
310 daniel-mar 152
        // Authentication keys for validating arguments (e.g. sent by mail)
2 daniel-mar 153
 
154
        public static function makeAuthKey($data) {
424 daniel-mar 155
                $data = OIDplus::baseConfig()->getValue('SERVER_SECRET') . '/AUTHKEY/' . $data;
421 daniel-mar 156
                $calc_authkey = sha3_512($data, false);
2 daniel-mar 157
                return $calc_authkey;
158
        }
159
 
160
        public static function validateAuthKey($data, $auth_key) {
421 daniel-mar 161
                return strcmp(self::makeAuthKey($data), $auth_key) === 0;
2 daniel-mar 162
        }
163
 
329 daniel-mar 164
        // "Veto" functions to force logout state
165
 
166
        public static function forceAllLoggedOut() {
167
                if (isset($_SERVER['SCRIPT_FILENAME']) && (basename($_SERVER['SCRIPT_FILENAME']) == 'sitemap.php')) {
168
                        // The sitemap may not contain any confidential information,
169
                        // even if the user is logged in, because the admin could
170
                        // accidentally copy-paste the sitemap to a
171
                        // search engine control panel while they are logged in
172
                        return true;
173
                } else {
174
                        return false;
175
                }
176
        }
427 daniel-mar 177
 
424 daniel-mar 178
        // CSRF functions
427 daniel-mar 179
 
424 daniel-mar 180
        private $enable_csrf = true;
427 daniel-mar 181
 
424 daniel-mar 182
        public function enableCSRF() {
183
                $this->enable_csrf = true;
184
        }
427 daniel-mar 185
 
424 daniel-mar 186
        public function disableCSRF() {
187
                $this->enable_csrf = false;
188
        }
427 daniel-mar 189
 
424 daniel-mar 190
        public function genCSRFToken() {
191
                return uniqid(mt_rand(), true);
192
        }
427 daniel-mar 193
 
424 daniel-mar 194
        public function checkCSRF() {
427 daniel-mar 195
                if (!$this->enable_csrf) return;
424 daniel-mar 196
                if (!isset($_REQUEST['csrf_token']) || !isset($_COOKIE['csrf_token']) || ($_REQUEST['csrf_token'] != $_COOKIE['csrf_token'])) {
197
                        throw new Exception(_L('Wrong CSRF Token'));
198
                }
199
        }
329 daniel-mar 200
 
421 daniel-mar 201
        // Generate RA passwords
202
 
203
        public static function raGeneratePassword($password) {
453 daniel-mar 204
                $def_method = OIDplus::config()->getValue('default_ra_auth_method');
205
 
206
                $plugins = OIDplus::getAuthPlugins();
207
                foreach ($plugins as $plugin) {
208
                        if (basename($plugin->getPluginDirectory()) === $def_method) {
209
                                return $plugin->generate($password);
210
                        }
211
                }
212
                throw new OIDplusException(_L('Default RA auth method/plugin "%1" not found',$def_method));
421 daniel-mar 213
        }
214
 
215
        // Generate admin password
216
 
217
        /* Nothing here; the admin password will be generated in setup_base.js */
218
 
219
}