Skip to content

Commit

Permalink
MDL-60365 tool_mobile: Extra configuration checks
Browse files Browse the repository at this point in the history
  • Loading branch information
jleyva committed Oct 12, 2017
1 parent 23ab0d7 commit 66a159f
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 8 deletions.
83 changes: 83 additions & 0 deletions admin/tool/mobile/classes/api.php
Expand Up @@ -30,6 +30,7 @@
use moodle_url;
use moodle_exception;
use lang_string;
use curl;

/**
* API exposed by tool_mobile, to be used mostly by external functions and the plugin settings.
Expand Down Expand Up @@ -356,4 +357,86 @@ public static function get_features_list() {

return $features;
}

/**
* This function check the current site for potential configuration issues that may prevent the mobile app to work.
*
* @return array list of potential issues
* @since Moodle 3.4
*/
public static function get_potential_config_issues() {
global $CFG;
require_once($CFG->dirroot . "/lib/filelib.php");
require_once($CFG->dirroot . '/message/lib.php');

$warnings = array();

$curl = new curl();
// Return certificate information and verify the certificate.
$curl->setopt(array('CURLOPT_CERTINFO' => 1, 'CURLOPT_SSL_VERIFYPEER' => true));
$httpswwwroot = str_replace('http:', 'https:', $CFG->wwwroot); // Force https url.
$curl->head($httpswwwroot . "/login/index.php");
$info = $curl->get_info();

// First of all, check the server certificate (if any).
if (empty($info['http_code']) or ($info['http_code'] >= 400)) {
$warnings[] = ['nohttpsformobilewarning', 'admin'];
} else {
// Check the certificate is not self-signed or has an untrusted-root.
// This may be weak in some scenarios (when the curl SSL verifier is outdated).
if (empty($info['certinfo'])) {
$warnings[] = ['selfsignedoruntrustedcertificatewarning', 'tool_mobile'];
} else {
$timenow = time();
$expectedissuer = null;
foreach ($info['certinfo'] as $cert) {
// Check if the signature algorithm is weak (Android won't work with SHA-1).
if ($cert['Signature Algorithm'] == 'sha1WithRSAEncryption' || $cert['Signature Algorithm'] == 'sha1WithRSA') {
$warnings[] = ['insecurealgorithmwarning', 'tool_mobile'];
}
// Check certificate start date.
if (strtotime($cert['Start date']) > $timenow) {
$warnings[] = ['invalidcertificatestartdatewarning', 'tool_mobile'];
}
// Check certificate end date.
if (strtotime($cert['Expire date']) < $timenow) {
$warnings[] = ['invalidcertificateexpiredatewarning', 'tool_mobile'];
}
// Check the chain.
if ($expectedissuer !== null) {
if ($expectedissuer !== $cert['Subject'] || $cert['Subject'] === $cert['Issuer']) {
$warnings[] = ['invalidcertificatechainwarning', 'tool_mobile'];
}
}
$expectedissuer = $cert['Issuer'];
}
}
}
// Now check typical configuration problems.
if ((int) $CFG->userquota === PHP_INT_MAX) {
// In old Moodle version was a text so was possible to have numeric values > PHP_INT_MAX.
$warnings[] = ['invaliduserquotawarning', 'tool_mobile'];
}
// Check ADOdb debug enabled.
if (get_config('auth_db', 'debugauthdb') || get_config('enrol_database', 'debugdb')) {
$warnings[] = ['adodbdebugwarning', 'tool_mobile'];
}
// Check display errors on.
if (!empty($CFG->debugdisplay)) {
$warnings[] = ['displayerrorswarning', 'tool_mobile'];
}
// Check mobile notifications.
$processors = get_message_processors();
$enabled = false;
foreach ($processors as $processor => $status) {
if ($processor == 'airnotifier' && $status->enabled) {
$enabled = true;
}
}
if (!$enabled) {
$warnings[] = ['mobilenotificationsdisabledwarning', 'tool_mobile'];
}

return $warnings;
}
}
9 changes: 9 additions & 0 deletions admin/tool/mobile/lang/en/tool_mobile.php
Expand Up @@ -22,6 +22,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

$string['adodbdebugwarning'] = 'ADOdb debugging is enabled. It should be disabled in the external database authentication or external database enrolment plugin settings.';
$string['androidappid'] = 'Android app\'s unique identifier';
$string['androidappid_desc'] = 'This setting may be left as default unless you have a custom Android app.';
$string['autologinkeygenerationlockout'] = 'Auto-login key generation is blocked because of too many requests within an hour.';
Expand Down Expand Up @@ -49,14 +50,20 @@
</pre>';
$string['disabledfeatures'] = 'Disabled features';
$string['disabledfeatures_desc'] = 'Select here the features you want to disable in the Mobile app for your site. Please note that some features listed here could be already disabled via other site settings. You will have to log out and log in again in the app to see the changes.';
$string['displayerrorswarning'] = 'Display debug messages (debugdisplay) is enabled. It should be disabled.';
$string['enablesmartappbanners'] = 'Enable App Banners';
$string['enablesmartappbanners_desc'] = 'If enabled, a banner promoting the mobile app will be displayed when accessing the site using a mobile browser.';
$string['forcedurlscheme'] = 'If you want to allow only your custom branded app to be opened via a browser window, then specify its URL scheme here; otherwise leave the field empty.';
$string['forcedurlscheme_key'] = 'URL scheme';
$string['forcelogout'] = 'Force log out';
$string['forcelogout_desc'] = 'If enabled, the app option \'Change site\' is replaced by \'Log out\'. This results in the user being completely logged out. They must then re-enter their password the next time they wish to access the site.';
$string['httpsrequired'] = 'HTTPS required';
$string['insecurealgorithmwarning'] = 'It seems that the HTTPS certificate uses an insecure algorithm for signing (SHA-1). Please try updating the certificate.';
$string['invalidcertificatechainwarning'] = 'It seems that the certificate chain is invalid.';
$string['invalidcertificateexpiredatewarning'] = 'It seems that the HTTPS certificate for the site has expired.';
$string['invalidcertificatestartdatewarning'] = 'It seems that the HTTPS certificate for the site is not yet valid (with a start date in the future).';
$string['invalidprivatetoken'] = 'Invalid private token. Token should not be empty or passed via GET parameter.';
$string['invaliduserquotawarning'] = 'The user quota (userquota) is set to an invalid number. It should be set to a valid number (an integer value) in Site policies.';
$string['iosappid'] = 'iOS app\'s unique identifier';
$string['iosappid_desc'] = 'This setting may be left as default unless you have a custom iOS app.';
$string['loginintheapp'] = 'Via the app';
Expand All @@ -70,8 +77,10 @@
$string['mobileauthentication'] = 'Mobile authentication';
$string['mobilecssurl'] = 'CSS';
$string['mobilefeatures'] = 'Mobile features';
$string['mobilenotificationsdisabledwarning'] = 'Mobile notifications are not enabled. They should be enabled in Manage message outputs.';
$string['mobilesettings'] = 'Mobile settings';
$string['pluginname'] = 'Moodle Mobile tools';
$string['selfsignedoruntrustedcertificatewarning'] = 'It seems that the HTTPS certificate is self-signed or not trusted. The mobile app will only work with trusted sites.';
$string['setuplink'] = 'App download page';
$string['setuplink_desc'] = 'URL of page with links to download the mobile app from the App Store and Google Play.';
$string['smartappbanners'] = 'App Banners';
Expand Down
31 changes: 31 additions & 0 deletions admin/tool/mobile/tests/api_test.php
Expand Up @@ -63,4 +63,35 @@ public function test_get_autologin_key() {
$this->assertTimeCurrent($key->validuntil - api::LOGIN_KEY_TTL);
$this->assertEquals('0.0.0.0', $key->iprestriction);
}

/**
* Test get_potential_config_issues.
*/
public function test_get_potential_config_issues() {
global $CFG;
require_once($CFG->dirroot . '/message/lib.php');

$this->resetAfterTest(true);
$this->setAdminUser();

$CFG->userquota = '73289234723498234723423489273423497234234';
$CFG->debugdisplay = 1;
set_config('debugauthdb', 1, 'auth_db');
set_config('debugdb', 1, 'enrol_database');
$expectedissues = array('nohttpsformobilewarning', 'invaliduserquotawarning', 'adodbdebugwarning', 'displayerrorswarning',
'mobilenotificationsdisabledwarning');

$processors = get_message_processors();
foreach ($processors as $processor => $status) {
if ($processor == 'airnotifier' && $status->enabled) {
unset($expectedissues['mobilenotificationsdisabledwarning']);
}
}

$issues = api::get_potential_config_issues();
$this->assertCount(count($expectedissues), $issues);
foreach ($issues as $issue) {
$this->assertTrue(in_array($issue[0], $expectedissues));
}
}
}
13 changes: 5 additions & 8 deletions lib/adminlib.php
Expand Up @@ -8746,17 +8746,14 @@ private function set_protocol_cap($status) {
* @return string XHTML
*/
public function output_html($data, $query='') {
global $CFG, $OUTPUT;
global $OUTPUT;
$html = parent::output_html($data, $query);

if ((string)$data === $this->yes) {
require_once($CFG->dirroot . "/lib/filelib.php");
$curl = new curl();
$httpswwwroot = str_replace('http:', 'https:', $CFG->wwwroot); //force https url
$curl->head($httpswwwroot . "/login/index.php");
$info = $curl->get_info();
if (empty($info['http_code']) or ($info['http_code'] >= 400)) {
$html .= $OUTPUT->notification(get_string('nohttpsformobilewarning', 'admin'));
$notifications = tool_mobile\api::get_potential_config_issues(); // Safe to call, plugin available if we reach here.
foreach ($notifications as $notification) {
$message = get_string($notification[0], $notification[1]);
$html .= $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING);
}
}

Expand Down

0 comments on commit 66a159f

Please sign in to comment.