Skip to content

Commit

Permalink
new approach to openroaming tests during profile save
Browse files Browse the repository at this point in the history
  • Loading branch information
twoln committed Apr 3, 2024
1 parent 2511447 commit ec87e04
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 7 deletions.
140 changes: 140 additions & 0 deletions core/AbstractProfile.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,22 @@ abstract class AbstractProfile extends EntityWithDBProperties
const OVERALL_OPENROAMING_LEVEL_WARN = 1;
const OVERALL_OPENROAMING_LEVEL_ERROR = 0;


const OPENROAMING_ALL_GOOD = 24;
const OPENROAMING_NO_REALM = 17; //n
const OPENROAMING_BAD_SRV = 16; //n
const OPENROAMING_BAD_NAPTR = 10; // w
const OPENROAMING_SOME_BAD_CONNECTIONS = 8; //w
const OPENROAMING_NO_DNSSEC = 8; //w
const OPENROAMING_NO_NAPTR = 3; //e
const OPENROAMING_BAD_NAPTR_RESOLVE = 2; //e
const OPENROAMING_BAD_SRV_RESOLVE = 1; //e
const OPENROAMING_BAD_CONNECTION = 0; //e





/**
* generates a detailed log of which installer was downloaded
*
Expand Down Expand Up @@ -205,6 +221,130 @@ public static function significantChanges($old, $new)
return $retval;
}

/**
* Tests OpenRoaming aspects of the profile like DNS settings and server reachibility
*
* @return array of arrays of the form [['level' => $level, 'explanation' => $explanation, 'reason' => $reason]];
*/
public function openroamingRedinessTest() {
// do OpenRoaming initial diagnostic checks
// numbers correspond to RFC7585Tests::OVERALL_LEVEL
$results = [];
$resultLevel = $this::OVERALL_OPENROAMING_LEVEL_GOOD; // assume all is well, degrade if we have concrete findings to suggest otherwise
$tag = "aaa+auth:radius.tls.tcp";
// do we know the realm at all? Notice if not.
if (!isset($this->getAttributes("internal:realm")[0]['value'])) {
$explanation = _("The profile information does not include the realm, so no DNS checks for OpenRoaming can be executed.");
$level = $this::OVERALL_OPENROAMING_LEVEL_NOTE;
$reason = $this::OPENROAMING_NO_REALM;
$results[] = ['level' => $level, 'explanation' => $explanation, 'reason' => $reason];
$resultLevel = min([$resultLevel, $level]);
} else {
$dnsChecks = new \core\diag\RFC7585Tests($this->getAttributes("internal:realm")[0]['value'], $tag);
$relevantNaptrRecords = $dnsChecks->relevantNAPTR();
if ($relevantNaptrRecords <= 0) {
$explanation = _("There is no relevant DNS NAPTR record ($tag) for this realm. OpenRoaming will not work.");
$reason = $this::OPENROAMING_NO_NAPTR;
$level = $this::OVERALL_OPENROAMING_LEVEL_ERROR;
$results[] = ['level' => $level, 'explanation' => $explanation, 'reason' => $reason];
$resultLevel = min([$resultLevel, $level]);
} else {
$recordCompliance = $dnsChecks->relevantNAPTRcompliance();
if ($recordCompliance != \core\diag\AbstractTest::RETVAL_OK) {
$explanation = _("The DNS NAPTR record ($tag) for this realm is not syntax conform. OpenRoaming will likely not work.");
$reason = $this::OPENROAMING_BAD_NAPTR;
$level = $this::OVERALL_OPENROAMING_LEVEL_WARN;
$results[] = ['level' => $level, 'explanation' => $explanation, 'reason' => $reason];
$resultLevel = min([$resultLevel, $level]);
}
// check if target is the expected one, if set by NRO
foreach ($this->fedAttributes as $attr) {
if ($attr['name'] === 'fed:openroaming_customtarget') {
$customText = $attr['value'];
} else {
$customText = '';
}
}
if ($customText !== '') {
foreach ($dnsChecks->NAPTR_records as $orpointer) {
if ($orpointer["replacement"] != $customText) {
$explanation = _("The SRV target of an OpenRoaming NAPTR record is unexpected.");
$reason = $this::OPENROAMING_BAD_SRV;
$level = $this::OVERALL_OPENROAMING_LEVEL_NOTE;
$results[] = ['level' => $level, 'explanation' => $explanation, 'reason' => $reason];
$resultLevel = min([$resultLevel, $level]);
}
}
}
$srvResolution = $dnsChecks->relevantNAPTRsrvResolution();
$hostnameResolution = $dnsChecks->relevantNAPTRhostnameResolution();

if ($srvResolution <= 0) {
$explanation = _("The DNS SRV target for NAPTR $tag does not resolve. OpenRoaming will not work.");
$level = $this::OVERALL_OPENROAMING_LEVEL_ERROR;
$reason = $this::OPENROAMING_BAD_NAPTR_RESOLVE;
$results[] = ['level' => $level, 'explanation' => $explanation, 'reason' => $reason];
$resultLevel = min([$resultLevel, $this::OVERALL_OPENROAMING_LEVEL_ERROR]);
} elseif ($hostnameResolution <= 0) {
$explanation = _("The DNS hostnames in the SRV records do not resolve to actual host IPs. OpenRoaming will not work.");
$level = $this::OVERALL_OPENROAMING_LEVEL_ERROR;
$reason = $this::OPENROAMING_BAD_SRV_RESOLVE;
$results[] = ['level' => $level, 'explanation' => $explanation, 'reason' => $reason];
$resultLevel = min([$resultLevel, $level]);
}
// connect to all IPs we found and see if they are really an OpenRoaming server
$allHostsOkay = TRUE;
$oneHostOkay = FALSE;
$testCandidates = [];
foreach ($dnsChecks->NAPTR_hostname_records as $oneServer) {
$testCandidates[$oneServer['hostname']][] = ($oneServer['family'] == "IPv4" ? $oneServer['IP'] : "[".$oneServer['IP']."]").":".$oneServer['port'];
}
foreach ($testCandidates as $oneHost => $listOfIPs) {
$connectionTests = new \core\diag\RFC6614Tests(array_values($listOfIPs), $oneHost, "openroaming");
// for now (no OpenRoaming client certs available) only run server-side tests
foreach ($listOfIPs as $oneIP) {
$connectionResult = $connectionTests->cApathCheck($oneIP);
if ($connectionResult != \core\diag\AbstractTest::RETVAL_OK || ( isset($connectionTests->TLS_CA_checks_result['cert_oddity']) && count($connectionTests->TLS_CA_checks_result['cert_oddity']) > 0)) {
$allHostsOkay = FALSE;
} else {
$oneHostOkay = TRUE;
}
}
}
if (!$allHostsOkay) {
if (!$oneHostOkay) {
$explanation = _("When connecting to the discovered OpenRoaming endpoints, they all had errors. OpenRoaming will likely not work.");
$level = $this::OVERALL_OPENROAMING_LEVEL_ERROR;
$reason = $this::OPENROAMING_BAD_CONNECTION;
$results[] = ['level' => $level, 'explanation' => $explanation, 'reason' => $reason];
$resultLevel = min([$resultLevel, $level]);
} else {
$explanation = _("When connecting to the discovered OpenRoaming endpoints, only a subset of endpoints had no errors.");
$level = $this::OVERALL_OPENROAMING_LEVEL_WARN;
$reason = $this::OPENROAMING_SOME_BAD_CONNECTIONS;
$results[] = ['level' => $level, 'explanation' => $explanation, 'reason' => $reason];
$resultLevel = min([$resultLevel, $level]);
}
}
}
}
if (!$dnsChecks->allResponsesSecure) {
$explanation = _("At least one DNS response was NOT secured using DNSSEC. OpenRoaming ANPs may refuse to connect to the endpoint.");
$level = $this::OVERALL_OPENROAMING_LEVEL_WARN;
$reason = $this::OPENROAMING_NO_DNSSEC;
$results[] = ['level' => $level, 'explanation' => $explanation, 'reason' => $reason];
$resultLevel = min([$resultLevel, $level]);
}
if ($resultLevel == $this::OVERALL_OPENROAMING_LEVEL_GOOD) {
$explanation = _("Initial diagnostics regarding the DNS part of OpenRoaming (including DNSSEC) were successful.");
$level = $this::OVERALL_OPENROAMING_LEVEL_GOOD;
$reason = $this::OPENROAMING_ALL_GOOD;
$results = [['level' => $level, 'explanation' => $explanation, 'reason' => $reason]];
}
$this->setOpenRoamingReadinessInfo($resultLevel);
return $results;
}

/**
* Takes note of the OpenRoaming participation and conformance level
*
Expand Down
24 changes: 17 additions & 7 deletions web/diag/action_realmcheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@
server_cert.serialNumber = "<?php echo _("Serial number:") ?>";
server_cert.sha1 = "<?php echo _("SHA1 fingerprint:") ?>";
var not_known_server = "<?php echo _("Connected to undetermined server") ?>";
var running_ajax_openroaming = 0;
$.ajaxSetup({
timeout: 3000
});
$(document).ready(function () {
$('.caresult, .eap_test_results, .udp_results').on('click', '.morelink', function () {
if ($(this).hasClass('less')) {
Expand Down Expand Up @@ -376,6 +380,7 @@ function capath(data, status) {
}

function udp(data, status) {
console.log("udp - ajax - start");
show_debug(JSON.stringify(data));
var v = data.result[0];
$("#src" + data.hostindex + "_img").attr('src', icons[v.level]);
Expand Down Expand Up @@ -410,10 +415,12 @@ function udp(data, status) {
global_level_udp = Math.max(global_level_udp, v.level);
$(".server_cert").show();
running_ajax_stat--;
console.log(running_ajax_stat);
ajax_end();
}

function ajax_end() {
console.log("ajax_end");
if (running_ajax_stat === 0) {
$("#main_static_ico").attr('src', icons[global_level_udp]);
$("#main_static_result").html(global_info[global_level_udp] + ' ' + "<?php echo _("See the appropriate tab for details.") ?>");
Expand Down Expand Up @@ -477,8 +484,9 @@ function run_login() {
$.ajax({
url: 'radius_tests.php?src=0&hostindex=$hostindex&realm='+realm,
type: 'POST',
timeout: 5000,
success: udp_login,
error: udp_login,
error: eee,
data: formData,
cache: false,
contentType: false,
Expand Down Expand Up @@ -511,15 +519,17 @@ function run_udp() {
$(\"#src" . $hostindex . "_img\").attr('src',icon_loading);
$(\"#src$hostindex\").html('');
running_ajax_stat++;
$.get('radius_tests.php',{test_type: 'udp', $extraarg realm: realm, src: $hostindex, lang: '" . $gui->languageInstance->getLang() . "', hostindex: '$hostindex' }, udp, 'json');
//$.get('radius_tests.php',{test_type: 'udp', $extraarg realm: realm, src: $hostindex, lang: '" . $gui->languageInstance->getLang() . "', hostindex: '$hostindex' }, udp, 'json');
$.ajax({url:'radius_tests.php', timeout: 5000, data:{test_type: 'udp', $extraarg realm: realm, src: $hostindex, lang: '" . $gui->languageInstance->getLang() . "', hostindex: '$hostindex'}, error: eee, success: udp, dataType: 'json'});
";
}
?>
}

function eee() {
alert("Unexpected error");
console.log("Unexpected error");
running_ajax_stat--;
ajax_end();
}

function show_debug(text) {
Expand Down Expand Up @@ -669,9 +679,9 @@ function run_dynamic() {
$expectedName = $addr['hostname'];
print "
running_ajax_dyn++;
$.ajax({url:'radius_tests.php', data:{test_type: 'capath', realm: realm, src: '$host', lang: '" . $gui->languageInstance->getLang() . "', hostindex: '$hostindex', expectedname: '$expectedName' }, error: eee, success: capath, dataType: 'json'});
$.ajax({url:'radius_tests.php', timeout: 5000, data:{test_type: 'capath', realm: realm, src: '$host', lang: '" . $gui->languageInstance->getLang() . "', hostindex: '$hostindex', expectedname: '$expectedName' }, error: eee, success: capath, dataType: 'json'});
running_ajax_dyn++;
$.ajax({url:'radius_tests.php', data:{test_type: 'clients', realm: realm, src: '$host', lang: '" . $gui->languageInstance->getLang() . "', hostindex: '$hostindex' }, error: eee, success: clients, dataType: 'json'});
$.ajax({url:'radius_tests.php', timeout: 5000, data:{test_type: 'clients', realm: realm, src: '$host', lang: '" . $gui->languageInstance->getLang() . "', hostindex: '$hostindex' }, error: eee, success: clients, dataType: 'json'});
";
}
echo "}
Expand All @@ -691,7 +701,7 @@ function run_openroaming() {
$expectedName = $addr['hostname'];
print "
running_ajax_openroaming++;
$.ajax({url:'radius_tests.php', data:{test_type: 'openroamingcapath', realm: realm, src: '$host', lang: '" . $gui->languageInstance->getLang() . "', hostindex: '$hostindex', expectedname: '$expectedName' }, error: eee, success: capath, dataType: 'json'});
$.ajax({url:'radius_tests.php', timeout: 5000, data:{test_type: 'openroamingcapath', realm: realm, src: '$host', lang: '" . $gui->languageInstance->getLang() . "', hostindex: '$hostindex', expectedname: '$expectedName' }, error: eee, success: capath, dataType: 'json'});
";
}
echo "}
Expand Down

0 comments on commit ec87e04

Please sign in to comment.