1: <?php
2: /*
3: * SimpleID
4: *
5: * Copyright (C) Kelvin Mo 2014
6: *
7: * This program is free software; you can redistribute it and/or
8: * modify it under the terms of the GNU General Public
9: * License as published by the Free Software Foundation; either
10: * version 2 of the License, or (at your option) any later version.
11: *
12: * This program is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15: * General Public License for more details.
16: *
17: * You should have received a copy of the GNU General Public
18: * License along with this program; if not, write to the Free
19: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20: *
21: */
22: include_once 'version.inc.php';
23: $class_loader = include_once('vendor/autoload.php');
24:
25: // 1. Constants
26: const SIMPLEID_INSTANT_TOKEN_EXPIRES_IN = 60;
27: const SIMPLEID_SHORT_TOKEN_EXPIRES_IN = 3600;
28: const SIMPLEID_HUMAN_TOKEN_EXPIRES_IN = 43200;
29: const SIMPLEID_LONG_TOKEN_EXPIRES_IN = 1209600;
30: const SIMPLEID_LONG_TOKEN_EXPIRES_BUFFER = 300;
31: // SIMPLEID_ETERNAL_TOKEN_EXPIRES_IN is set to 400 days, which is the
32: // browser-imposed maximum limit for long life cookies
33: const SIMPLEID_ETERNAL_TOKEN_EXPIRES_IN = 34560000;
34:
35:
36: // 2. Load configuration
37: $f3 = \Base::instance();
38:
39: $default_config = [
40: 'allow_plaintext' => false,
41: 'openid_verify_return_url' => true,
42: 'openid_strict_realm_check' => true,
43: 'webfinger_access_control_allow_origin' => '*',
44: 'locale' => 'en',
45: 'debug' => 0,
46: 'logger' => 'SimpleID\Util\DefaultLogger',
47: 'log_file' => '',
48: 'log_level' => 'info',
49: 'log_location' => false,
50: 'date_time_format' => 'Y-m-d H:i:s T',
51: 'acr' => 1,
52: 'required_modules' => [
53: 'SimpleID\Base\IndexModule',
54: 'SimpleID\Store\DefaultStoreModule',
55: 'SimpleID\Auth\AuthModule',
56: 'SimpleID\Base\UserModule',
57: ],
58: 'modules' => [
59: 'SimpleID\Base\MyModule',
60: 'SimpleID\Auth\PasswordAuthSchemeModule',
61: 'SimpleID\Auth\RememberMeAuthSchemeModule',
62: 'SimpleID\Auth\OTPAuthSchemeModule',
63: 'SimpleID\Protocols\OpenID\OpenIDModule',
64: 'SimpleID\Protocols\OpenID\Extensions\SRegOpenIDExtensionModule',
65: 'SimpleID\Protocols\WebFinger\WebFingerModule',
66: ],
67: ];
68:
69: // Check if the configuration file has been defined
70: if (file_exists('conf/config.php')) {
71: $config_file = 'conf/config.php';
72: } elseif (file_exists('config.php')) {
73: $config_file = 'config.php';
74: } else {
75: die('No configuration file found. See <http://simpleid.org/docs/2/installing/> for instructions on how to set up a configuration file.');
76: }
77:
78: $config = include_once($config_file);
79: $config = array_replace_recursive($default_config, $config);
80: if (!isset($config['canonical_base_path'])) {
81: $port = $f3->get('PORT');
82: $config['canonical_base_path'] = $f3->get('SCHEME') .'://'. $_SERVER['SERVER_NAME']
83: . ($port && $port != 80 && $port != 443 ? (':' . $port) : '') . $f3->get('BASE');
84: }
85:
86: if (isset($config['secure_secret']) && ($config['secure_secret'] != '') && !isset($_ENV['SIMPLEID_SECURE_SECRET'])) {
87: $_ENV['SIMPLEID_SECURE_SECRET'] = $config['secure_secret'];
88: $f3->sync('ENV');
89: } elseif (isset($config['secure_secret_file']) && ($config['secure_secret_file'] != '') && !isset($_ENV['SIMPLEID_SECURE_SECRET_FILE'])) {
90: $_ENV['SIMPLEID_SECURE_SECRET_FILE'] = $config['secure_secret_file'];
91: $f3->sync('ENV');
92: }
93:
94: date_default_timezone_set(@date_default_timezone_get());
95:
96: $f3->mset([
97: 'CASELESS' => false,
98: 'CORS.origin' => '*',
99: 'JAR.domain' => '',
100: 'JAR.secure' => false,
101: 'JAR.samesite' => 'Strict',
102: 'PACKAGE' => 'SimpleID/' . SIMPLEID_VERSION,
103: 'TEMP' => $config['temp_dir'] . '/',
104: 'UI' => 'html/',
105: 'PREFIX' => 'intl.'
106: ]);
107: // These need to be set after PREFIX
108: $f3->mset([
109: 'FALLBACK' => 'en',
110: 'LOCALES' => 'locale/'
111: ]);
112: $f3->set('version', SIMPLEID_VERSION);
113: $f3->set('base_path', $f3->get('BASE') . '/');
114: $f3->set('config', $config);
115: $f3->set('class_loader', $class_loader);
116:
117: // 3. Temp directory
118: if (!is_dir($f3->get('TEMP')) || !is_writable($f3->get('TEMP'))) {
119: die('Temp directory not found or not writeable. Make sure temp_dir is set up properly in config.php.');
120: }
121:
122: // 4. Cache
123: if (preg_match('/^folder\h*=\h*(.+)/', $config['cache']) && substr($config['cache'], -1) != '/') {
124: $config['cache'] .= '/';
125: }
126: $f3->set('CACHE', $config['cache']);
127: $cache = \Cache::instance();
128: //$cache->reset(null, SIMPLEID_LONG_TOKEN_EXPIRES_IN);
129:
130: // 5. Logging
131: if (!isset($config['logger']) || ($config['logger'] == '') || ($config['log_file'] == '')) {
132: $config['logger'] = 'Psr\Log\NullLogger';
133: }
134: if (is_subclass_of($config['logger'], '\Log', true)) $f3->set('LOGS', dirname($config['log_file']) . '/');
135: $logger = new $config['logger']($config);
136: $f3->set('logger', $logger);
137:
138: if ($config['debug']) {
139: Tracy\Debugger::enable('127.0.0.1');
140: if (is_int($config['debug'])) $f3->set('DEBUG', $config['debug']);
141: }
142:
143: // 6. Fix up HTTP request
144: fix_http_request($f3);
145:
146: // For SimpleID 1.x compatibility
147: if (isset($_GET['q'])) {
148: $f3->set('PATH', '/' . $_GET['q']);
149: unset($_GET['q']);
150: }
151:
152: // 7. Check for other configuration errors
153: if ((@ini_get('register_globals') === 1) || (@ini_get('register_globals') === '1') || (strtolower(@ini_get('register_globals')) == 'on')) {
154: $f3->get('logger')->log(\Psr\Log\LogLevel::CRITICAL, 'register_globals is enabled in PHP configuration.');
155: $f3->error(500, $f3->get('intl.bootstrap.register_globals', 'http://simpleid.org/docs/2/system-requirements/'));
156: }
157:
158: if (!isset($_ENV['SIMPLEID_SECURE_SECRET']) && !isset($_ENV['SIMPLEID_SECURE_SECRET_FILE'])) {
159: $f3->get('logger')->log(\Psr\Log\LogLevel::CRITICAL, 'secure_secret or secure_secret_file not set.');
160: $f3->error(500, $f3->get('intl.bootstrap.secure_secret'));
161: }
162:
163: if (!\SimpleID\Crypt\BigNum::loaded()) {
164: $f3->get('logger')->log(\Psr\Log\LogLevel::CRITICAL, 'gmp/bcmath PHP extension not loaded.');
165: $f3->error(500, $f3->get('intl.bootstrap.extension', [ 'gmp/bcmath', 'http://simpleid.org/docs/2/system-requirements/' ]));
166: }
167: if (!function_exists('preg_match')) {
168: $f3->get('logger')->log(\Psr\Log\LogLevel::CRITICAL, 'pcre PHP extension not loaded.');
169: $f3->error(500, $f3->get('intl.bootstrap.extension', [ 'pcre', 'http://simpleid.org/docs/2/system-requirements/' ]));
170: }
171: if (!function_exists('session_start')) {
172: $f3->get('logger')->log(\Psr\Log\LogLevel::CRITICAL, 'session PHP extension not loaded.');
173: $f3->error(500, $f3->get('intl.bootstrap.extension', [ 'session', 'http://simpleid.org/docs/2/system-requirements/' ]));
174: }
175: if (!function_exists('xml_parser_create_ns')) {
176: $f3->get('logger')->log(\Psr\Log\LogLevel::CRITICAL, 'xml PHP extension not loaded.');
177: $f3->error(500, $f3->get('intl.bootstrap.extension', [ 'xml', 'http://simpleid.org/docs/2/system-requirements/' ]));
178: }
179: if (!function_exists('hash')) {
180: $f3->get('logger')->log(\Psr\Log\LogLevel::CRITICAL, 'hash PHP extension not loaded.');
181: $f3->error(500, $f3->get('intl.bootstrap.extension', [ 'hash', 'http://simpleid.org/docs/2/system-requirements/' ]));
182: }
183: if (!function_exists('openssl_sign')) {
184: $f3->get('logger')->log(\Psr\Log\LogLevel::CRITICAL, 'openssl PHP extension not loaded.');
185: $f3->error(500, $f3->get('intl.bootstrap.extension', [ 'openssl', 'http://simpleid.org/docs/2/system-requirements/' ]));
186: }
187: if (!function_exists('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt')) {
188: $f3->get('logger')->log(\Psr\Log\LogLevel::CRITICAL, 'sodium PHP extension not loaded.');
189: $f3->error(500, $f3->get('intl.bootstrap.extension', [ 'sodium', 'http://simpleid.org/docs/2/system-requirements/' ]));
190: }
191: if (is_numeric(@ini_get('suhosin.get.max_value_length')) && (@ini_get('suhosin.get.max_value_length') < 1024)) {
192: $f3->get('logger')->log(\Psr\Log\LogLevel::CRITICAL, 'suhosin.get.max_value_length < 1024');
193: $f3->error(500, $f3->get('intl.bootstrap.suhosin', 'http://simpleid.org/docs/2/system-requirements/'));
194: }
195:
196: /* ------------------------------------------------------------------------- */
197:
198: /**
199: * Fix PHP's handling of request data. PHP changes dots in all request parameters
200: * to underscores when creating the $_GET, $_POST and $_REQUEST arrays.
201: *
202: * This function scans the original query string and POST parameters and fixes
203: * them.
204: */
205: function fix_http_request($f3) {
206: // Fix GET parameters
207: if (isset($_SERVER['QUERY_STRING'])) {
208: $get = parse_http_query($_SERVER['QUERY_STRING']);
209:
210: foreach ($get as $key => $value) {
211: // We strip out array-like identifiers - PHP uses special processing for these
212: if ((strpos($key, '[') !== FALSE) && (strpos($key, ']') !== FALSE)) $key = substr($key, 0, strpos($key, '['));
213:
214: // Replace special characters with underscore as per PHP processing
215: $php_key = preg_replace('/[ .[\x80-\x9F]/', '_', $key);
216:
217: // See if the PHP key is present; if so, copy and delete
218: if (($key != $php_key) && isset($_GET[$php_key])) {
219: $_GET[$key] = $_GET[$php_key];
220: $_REQUEST[$key] = $_REQUEST[$php_key];
221: unset($_GET[$php_key]);
222: unset($_REQUEST[$php_key]);
223: }
224: }
225: }
226:
227: // Fix POST parameters
228: if ($f3->get('VERB') != 'POST') return;
229: if ($f3->get('SERVER.CONTENT_TYPE') != 'application/x-www-form-urlencoded') return;
230:
231: $input = file_get_contents('php://input');
232: if ($input !== FALSE) {
233: $post = parse_http_query($input);
234:
235: foreach ($post as $key => $value) {
236: // We strip out array-like identifiers - PHP uses special processing for these
237: if ((strpos($key, '[') !== FALSE) && (strpos($key, ']') !== FALSE)) $key = substr($key, 0, strpos($key, '['));
238:
239: // Replace special characters with underscore as per PHP processing
240: $php_key = preg_replace('/[ .[\x80-\x9F]/', '_', $key);
241:
242: // See if the PHP key is present; if so, copy and delete
243: if (($key != $php_key) && isset($_POST[$php_key])) {
244: $_POST[$key] = $_POST[$php_key];
245: $_REQUEST[$key] = $_REQUEST[$php_key];
246: unset($_POST[$php_key]);
247: unset($_REQUEST[$php_key]);
248: }
249: }
250: }
251: }
252:
253: /**
254: * Parses a query string.
255: *
256: * @param string $query the query string to parse
257: * @return array an array containing the parsed key-value pairs
258: *
259: * @since 0.7
260: */
261: function parse_http_query($query) {
262: $data = [];
263:
264: if ($query === NULL) return [];
265: if ($query === '') return [];
266:
267: $pairs = explode('&', $query);
268:
269: foreach ($pairs as $pair) {
270: list ($key, $value) = explode('=', $pair, 2);
271: $data[$key] = urldecode($value);
272: }
273:
274: return $data;
275: }
276:
277: ?>
278: