mirror of
https://github.com/catalyst/moodle-auth_outage.git
synced 2026-05-17 05:48:43 +02:00
Merge branch 'master' into issue-115_outage-body-class
This commit is contained in:
16
.travis.yml
16
.travis.yml
@@ -13,29 +13,13 @@ cache:
|
||||
|
||||
php:
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
|
||||
env:
|
||||
- DB=pgsql MOODLE_BRANCH=MOODLE_30_STABLE
|
||||
- DB=pgsql MOODLE_BRANCH=MOODLE_31_STABLE
|
||||
- DB=pgsql MOODLE_BRANCH=MOODLE_32_STABLE
|
||||
- DB=pgsql MOODLE_BRANCH=master
|
||||
- DB=mysqli MOODLE_BRANCH=MOODLE_30_STABLE
|
||||
- DB=mysqli MOODLE_BRANCH=MOODLE_31_STABLE
|
||||
- DB=mysqli MOODLE_BRANCH=MOODLE_32_STABLE
|
||||
- DB=mysqli MOODLE_BRANCH=master
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- php: 5.5
|
||||
env: DB=pgsql MOODLE_BRANCH=MOODLE_32_STABLE
|
||||
- php: 5.5
|
||||
env: DB=pgsql MOODLE_BRANCH=master
|
||||
- php: 5.5
|
||||
env: DB=mysqli MOODLE_BRANCH=MOODLE_32_STABLE
|
||||
- php: 5.5
|
||||
env: DB=mysqli MOODLE_BRANCH=master
|
||||
|
||||
before_install:
|
||||
- phpenv config-rm xdebug.ini
|
||||
|
||||
@@ -33,7 +33,7 @@ and testers letting them know what is about to happen and why.
|
||||
Moodle Requirements
|
||||
-------------------
|
||||
|
||||
This plugin will work out-of-the-box with Moodle 3+.
|
||||
This plugin will work out-of-the-box with Moodle 3.0 and Moodle 3.1.
|
||||
|
||||
If you have an older version of Moodle you can still make it work but you will
|
||||
need to manually add one extra plugin, please check:
|
||||
@@ -74,7 +74,7 @@ https://github.com/catalyst/moodle-auth_outage/issues
|
||||
enable the `Outage manager` plugin and place it on the top.
|
||||
|
||||
4. If you need to use the IP Blocking, please add the following lines into your `config.php`
|
||||
after your `$CFG->dataroot` is set:
|
||||
before the `require('/lib/setup.php')` call:
|
||||
|
||||
```
|
||||
// Insert this after $CFG->dataroot is defined.
|
||||
|
||||
@@ -37,12 +37,36 @@ if (!isset($CFG->dataroot)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1) Check and run the hook.
|
||||
// 1) Make sure we replace the configurations for behat as we have not ran 'lib/setup.php' yet.
|
||||
if (!empty($CFG->behat_wwwroot) or !empty($CFG->behat_dataroot) or !empty($CFG->behat_prefix)) {
|
||||
require_once(__DIR__.'/../../lib/behat/lib.php');
|
||||
behat_update_vars_for_process();
|
||||
if (behat_is_test_site()) {
|
||||
$beforebehatcfg = $CFG;
|
||||
$CFG = clone($CFG);
|
||||
clearstatcache();
|
||||
behat_check_config_vars();
|
||||
behat_clean_init_config();
|
||||
$CFG->wwwroot = $CFG->behat_wwwroot;
|
||||
$CFG->dataroot = $CFG->behat_dataroot;
|
||||
// We should not access database in bootstrap.
|
||||
$CFG->dbtype = null;
|
||||
$CFG->dblibrary = null;
|
||||
$CFG->dbhost = null;
|
||||
$CFG->dbname = null;
|
||||
$CFG->dbuser = null;
|
||||
$CFG->dbpass = null;
|
||||
$CFG->prefix = null;
|
||||
$CFG->dboptions = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Check and run the hook.
|
||||
if (is_callable('auth_outage_bootstrap_callback')) {
|
||||
call_user_func('auth_outage_bootstrap_callback');
|
||||
}
|
||||
|
||||
// 2) Check for allowed scripts or IPs during outages.
|
||||
// 3) Check for allowed scripts or IPs during outages.
|
||||
$allowed = !file_exists($CFG->dataroot.'/climaintenance.php') // Not in maintenance mode.
|
||||
|| (defined('ABORT_AFTER_CONFIG') && ABORT_AFTER_CONFIG) // Only config requested.
|
||||
|| (defined('CLI_SCRIPT') && CLI_SCRIPT); // Allow CLI scripts.
|
||||
@@ -52,5 +76,10 @@ if (!$allowed) {
|
||||
require($CFG->dataroot.'/climaintenance.php'); // This call may terminate the script here or not.
|
||||
}
|
||||
|
||||
// 3) Set flag this file was loaded.
|
||||
// 4) Set flag this file was loaded.
|
||||
$CFG->auth_outage_bootstrap_loaded = true;
|
||||
|
||||
// 5) Restore behat config as needed (let setup.php execute which is more complex than our quick-check).
|
||||
if (isset($beforebehatcfg)) {
|
||||
$CFG = $beforebehatcfg;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,8 @@ class outagelib {
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, 5); // Feching local files should be very fast.
|
||||
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 1); // It is localhost, time to connect is enough.
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, 5); // It is localhost, time to fetch index is enough.
|
||||
$contents = curl_exec($curl);
|
||||
$mime = curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
|
||||
curl_close($curl);
|
||||
|
||||
17
file.php
17
file.php
@@ -60,23 +60,16 @@ header('Accept-Ranges: none');
|
||||
* @SupressWarnings(PHPMD)
|
||||
*/
|
||||
function auth_outage_bootstrap_callback() {
|
||||
global $CFG;
|
||||
|
||||
// We are not using any external libraries or references in this file (cli maintenance is active).
|
||||
// If you change the path below maybe you need to change maintenance_static_page::get_resources_folder() as well.
|
||||
$resourcedir = rtrim($CFG->dataroot, '/'); // In case the configuration has a trailing slash.
|
||||
$resourcedir = $resourcedir.'/auth_outage/climaintenance';
|
||||
|
||||
// Protect against path traversal attacks.
|
||||
$file = $resourcedir.'/'.$_GET['file'];
|
||||
if (realpath($file) !== $file) {
|
||||
// Not using classes as classloader has not been initialized yet. Keep it minimalist.
|
||||
require_once(__DIR__.'/lib.php');
|
||||
$file = auth_outage_get_climaintenance_resource_file($_GET['file']);
|
||||
if (is_null($file)) {
|
||||
// @codingStandardsIgnoreStart
|
||||
error_log('Invalid file: '.$_GET['file']);
|
||||
// @codingStandardsIgnoreEnd
|
||||
http_response_code(404);
|
||||
die('Not found.');
|
||||
die('File not found.');
|
||||
}
|
||||
|
||||
readfile($file);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
31
lib.php
31
lib.php
@@ -56,3 +56,34 @@ function auth_outage_extend_navigation_user() {
|
||||
function auth_outage_outagelib_prepare_next_outage() {
|
||||
outagelib::prepare_next_outage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by file.php to fetch a file from sitedata, protecting it from path traversal attacks.
|
||||
*
|
||||
* To keep it minimalist it was not added to the outagelib.php class.
|
||||
*
|
||||
* @param $file string Filename to fetch from sitedata
|
||||
* @return string|null Full path to the sitedata file or null if file is not valid.
|
||||
*/
|
||||
function auth_outage_get_climaintenance_resource_file($file) {
|
||||
global $CFG;
|
||||
|
||||
// We are not using any external libraries or references in this file (we have not gully loaded config.php yet).
|
||||
// If you change the path below maybe you need to change maintenance_static_page::get_resources_folder() as well.
|
||||
$resourcedir = rtrim($CFG->dataroot, '/'); // In case the configuration has a trailing slash.
|
||||
$resourcedir = $resourcedir.'/auth_outage/climaintenance';
|
||||
|
||||
// Protect against path traversal attacks.
|
||||
$basename = basename($file);
|
||||
if ($basename !== $file) {
|
||||
// @codingStandardsIgnoreStart
|
||||
if (!PHPUNIT_TEST) {
|
||||
error_log('Possible attempt for Path Traversal Attack (only filename expected): '.$file);
|
||||
}
|
||||
// @codingStandardsIgnoreEnd
|
||||
return null;
|
||||
}
|
||||
|
||||
$realpath = realpath($resourcedir.'/'.$file);
|
||||
return ($realpath == false) ? null : $realpath;
|
||||
}
|
||||
|
||||
114
tests/phpunit/lib_test.php
Normal file
114
tests/phpunit/lib_test.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* tests for lib.php
|
||||
*
|
||||
* @package auth_outage
|
||||
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
|
||||
* @copyright 2017 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once(__DIR__.'/base_testcase.php');
|
||||
require_once(__DIR__.'/../../lib.php');
|
||||
|
||||
/**
|
||||
* tests for lib.php
|
||||
*
|
||||
* @package auth_outage
|
||||
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
|
||||
* @copyright 2017 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @SuppressWarnings(public) Allow as many methods as needed.
|
||||
*/
|
||||
class lib_test extends auth_outage_base_testcase {
|
||||
public function test_auth_outage_get_climaintenance_resource_file_resolves_a_file() {
|
||||
global $CFG;
|
||||
$dir = $CFG->dataroot.'/auth_outage/climaintenance';
|
||||
mkdir($dir, 0777, true);
|
||||
|
||||
// Create a file.
|
||||
$expected = $dir.'/example.txt';
|
||||
file_put_contents($expected, 'Outage Unit Test Message');
|
||||
|
||||
// Get that file.
|
||||
$actual = auth_outage_get_climaintenance_resource_file('example.txt');
|
||||
|
||||
// Clean up.
|
||||
unlink($expected);
|
||||
rmdir($dir);
|
||||
|
||||
self::assertSame($expected, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression test for issue #104.
|
||||
*/
|
||||
public function test_auth_outage_get_climaintenance_resource_file_resolves_a_file_with_symlink() {
|
||||
global $CFG;
|
||||
|
||||
// Create a file.
|
||||
$realdir = $CFG->dataroot.'/auth_outage/climaintenance_real';
|
||||
mkdir($realdir, 0777, true);
|
||||
$realfile = $realdir.'/example.txt';
|
||||
file_put_contents($realfile, 'Outage Unit Test Message');
|
||||
|
||||
// Create a symlink
|
||||
$symdir = $CFG->dataroot.'/auth_outage/climaintenance';
|
||||
if (!symlink($realdir, $symdir)) {
|
||||
unlink($realfile);
|
||||
rmdir($realdir);
|
||||
$this->markTestSkipped('Canont create symlinks, maybe OS does not support.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get that file.
|
||||
$actual = auth_outage_get_climaintenance_resource_file('example.txt');
|
||||
|
||||
// Clean up.
|
||||
unlink($symdir);
|
||||
unlink($realfile);
|
||||
rmdir($realdir);
|
||||
|
||||
self::assertSame($realfile, $actual);
|
||||
}
|
||||
|
||||
public function test_auth_outage_get_climaintenance_resource_file_prevent_path_traversal() {
|
||||
global $CFG;
|
||||
|
||||
$dir = $CFG->dataroot.'/auth_outage/climaintenance';
|
||||
mkdir($dir, 0777, true);
|
||||
|
||||
// Create a file.
|
||||
$expected = $dir.'/example.txt';
|
||||
file_put_contents($expected, 'Outage Unit Test Message');
|
||||
|
||||
// Create a sensitive file.
|
||||
$sensitivefile = $CFG->dataroot.'/auth_outage/nuclear_silo_passwords.txt';
|
||||
file_put_contents($sensitivefile, 'The password to launch the ICBM: 123456');
|
||||
|
||||
// Path Traversal Attack.
|
||||
$actual = auth_outage_get_climaintenance_resource_file('../n\\uclear_silo_passwords.txt');
|
||||
|
||||
// Clean up.
|
||||
unlink($expected);
|
||||
rmdir($dir);
|
||||
|
||||
self::assertNull($actual);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user