Passed
Push — master ( 32b95a...2c2bb9 )
by Stefan
05:45 queued 29s
created

Telepath::magic()   F

Complexity

Conditions 47
Paths > 20000

Size

Total Lines 201
Code Lines 112

Duplication

Lines 79
Ratio 39.3 %

Importance

Changes 0
Metric Value
dl 79
loc 201
c 0
b 0
f 0
rs 2
cc 47
eloc 112
nc 774690
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * ******************************************************************************
5
 * Copyright 2011-2017 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 
6
 * and GN4-2 consortia
7
 *
8
 * License: see the web/copyright.php file in the file structure
9
 * ******************************************************************************
10
 */
11
12
namespace core\diag;
13
14
use \Exception;
15
16
require_once(dirname(dirname(__DIR__)) . "/config/_config.php");
17
18
/**
19
 * The overall coordination class that runs all kinds of tests to find out where
20
 * and what is wrong. Operates on the realm of a user. Can do more magic if it
21
 * also knows which federation the user is currently positioned in, or even 
22
 * which exact hotspot to analyse.
23
 */
24
class Telepath extends AbstractTest {
25
26
    private $additionalFindings;
27
    private $realm;
28
    private $visitedFlr;
29
    private $visitedHotspot;
30
    private $catIdP;
31
    private $dbIdP;
32
    private $idPFederation;
33
    private $testsuite;
34
35
    public function __construct(string $realm, $visitedFlr = NULL, $visitedHotspot = NULL) {
36
        parent::__construct();
37
38
        $this->additionalFindings = [];
39
        $this->realm = $realm;
40
        $this->visitedFlr = $visitedFlr;
41
        $this->visitedHotspot = $visitedHotspot;
42
        $links = \core\Federation::determineIdPIdByRealm($realm);
43
        $this->catIdP = $links["CAT"];
44
        $this->dbIdP = $links["EXTERNAL"];
45
        $this->idPFederation = $links["FEDERATION"];
46
        // this is NULL if the realm is not known in either DB
47
        // if so, let's try a regex to extract the ccTLD if any
48
        $matches = [];
49
        if ($this->idPFederation === NULL && preg_match("/\.(..)$/", $realm, $matches)) {
50
            $this->idPFederation = strtoupper($matches[1]);
51
        }
52
        $this->loggerInstance->debug(4, "XYZ: IdP-side NRO is " . $this->idPFederation . "\n");
53
    }
54
55
    /* The eduroam OT monitoring has the following return codes:
56
     * 
57
58
      Status codes
59
60
      0 - O.K.
61
      -1 - Accept O.K. Reject No
62
      -2 - Reject O.K. Accept No
63
      -3 - Accept No Reject No
64
      -9 - system error
65
      -10 - Accept O.K. Reject timeou
66
      -11 - Accept O.K. Reject no EAP
67
      -20 - Reject O.K. Accept timeou
68
      -21 - Reject O.K. Accept no EAP
69
      -31 - Accept No  Reject timeou
70
      -32 - Accept Timeout Reject no
71
      -33 - Accept Timeout Reject timeou
72
      -35 - Accept No Reject no EAP
73
      -36 - Reject No Accept no EAP
74
      -37 - Reject No EAP Accept no EAP
75
      -40 - UDP test error
76
77
     */
78
79
    private function genericAPIStatus($type, $param1 = NULL, $param2 = NULL) {
80
        $endpoints = [
81
            'tlr_test' => "https://monitor.eduroam.org/mapi/index.php?type=tlr_test&tlr=$param1",
82
            'federation_via_tlr' => "https://monitor.eduroam.org/mapi/index.php?type=federation_via_tlr&federation=$param1",
83
            'flrs_test' => "https://monitor.eduroam.org/mapi/index.php?type=flrs_test&federation=$param1",
84
            'flr_by_federation' => "https://monitor.eduroam.org/mapi/index.php?type=flr_by_federation&federation=$param2&with=$param1",
85
        ];
86
        $ignore = [
87
            'tlr_test' => 'tlr',
88
            'federation_via_tlr' => 'fed',
89
            'flrs_test' => 'fed',
90
            'flr_by_federation' => 'fed',
91
        ];
92
        $this->loggerInstance->debug(4, "Doing Monitoring API check with $endpoints[$type]\n");
93
        $jsonResult = \core\common\OutsideComm::downloadFile($endpoints[$type]);
94
        $this->loggerInstance->debug(4, "Monitoring API Result: $jsonResult\n");
95
        $decoded = json_decode($jsonResult, TRUE);
96
        $retval = [];
97
        $retval["RAW"] = $decoded;
98
        $atLeastOneFunctional = FALSE;
99
        $allFunctional = TRUE;
100
        if (!isset($decoded[$type]) || isset($decoded['ERROR'])) {
101
            $retval["STATUS"] = AbstractTest::STATUS_MONITORINGFAIL;
102
            return $retval;
103
        }
104
        foreach ($decoded[$type] as $instance => $resultset) {
105
            if ($instance == $ignore[$type]) {
106
                // don't care
107
                continue;
108
            }
109
            // TLR test has statuscode on this level, otherwise need to recurse
110
            // one more level
111
            switch ($type) {
112
                case "tlr_test":
113 View Code Duplication
                    switch ($resultset['status_code']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
114
                        case 0:
115
                            $atLeastOneFunctional = TRUE;
116
                            break;
117
                        case 9: // monitoring itself has an error, no effect on our verdict
118
                        case -1: // Reject test fails, but we diagnose supposed-working connection, so no effect on our verdict
119
                        case -10: // same as previous
120
                        case -11: // same as previous
121
                            break;
122
                        default:
123
                            $allFunctional = FALSE;
124
                    }
125
                    break;
126
                default:
127
                    foreach ($resultset as $particularInstance => $particularResultset) {
128 View Code Duplication
                        switch ($particularResultset['status_code']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
129
                            case 0:
130
                                $atLeastOneFunctional = TRUE;
131
                                break;
132
                            case 9: // monitoring itself has an error, no effect on our verdict
133
                            case -1: // Reject test fails, but we diagnose supposed-working connection, so no effect on our verdict
134
                            case -10: // same as previous
135
                            case -11: // same as previous
136
                                break;
137
                            default:
138
                                $allFunctional = FALSE;
139
                        }
140
                    }
141
            }
142
        }
143
144
        if ($allFunctional) {
145
            $retval["STATUS"] = AbstractTest::STATUS_GOOD;
146
            return $retval;
147
        }
148
        if ($atLeastOneFunctional) {
149
            $retval["STATUS"] = AbstractTest::STATUS_PARTIAL;
150
            return $retval;
151
        }
152
        $retval["STATUS"] = AbstractTest::STATUS_DOWN;
153
        return $retval;
154
    }
155
156
    private function checkEtlrStatus() {
157
        // TODO: we always check the European TLRs even though the connection in question might go via others and/or this one
158
        // needs a table to determine what goes where :-(
159
        return $this->genericAPIStatus("tlr_test", "TLR_EU");
160
    }
161
162
    private function checkFedEtlrUplink($fed) {
163
        // TODO: we always check the European TLRs even though the connection in question might go via others and/or this one
164
        // needs a table to determine what goes where :-(
165
        return $this->genericAPIStatus("federation_via_tlr", $fed);
166
    }
167
168
    private function checkFlrServerStatus($fed) {
169
        // TODO: we always check the European TLRs even though the connection in question might go via others and/or this one
170
        // needs a table to determine what goes where :-(
171
        return $this->genericAPIStatus("flrs_test", $fed);
172
    }
173
174
    private function checkNROFlow() {
175
        return $this->genericAPIStatus("flr_by_federation", $this->idPFederation, $this->visitedFlr);
176
    }
177
178
    /**
179
     * Runs the CAT-internal diagnostics tests. Determines the state of the 
180
     * realm (and indirectly that of the links and statuses of involved proxies
181
     * and returns a judgment whether external Monitoring API tests are warranted
182
     * or not
183
     * @return boolean TRUE if external tests have to be run
184
     */
185
    private function CATInternalTests() {
186
        // we are expecting to get a REJECT from all runs, because that means the packet got through to the IdP.
187
        // (the ETLR sometimes does a "Reject instead of Ignore" but that is filtered out and changed into a timeout
188
        // by the test suite automatically, so it does not disturb the measurement)
189
        // If that's true, we can exclude two sources of problems (both proxy levels). Hooray!
190
        $allAreConversationReject = TRUE;
191
        $atLeastOneConversationReject = FALSE;
192
193
        foreach (CONFIG_DIAGNOSTICS['RADIUSTESTS']['UDP-hosts'] as $probeindex => $probe) {
194
            $reachCheck = $this->testsuite->udpReachability($probeindex);
195
            if ($reachCheck != RADIUSTests::RETVAL_CONVERSATION_REJECT) {
196
                $allAreConversationReject = FALSE;
197
            } else {
198
                $atLeastOneConversationReject = TRUE;
199
            }
200
201
            $this->additionalFindings[AbstractTest::INFRA_ETLR][] = ["DETAIL" => $this->testsuite->consolidateUdpResult($probeindex)];
202
            $this->additionalFindings[AbstractTest::INFRA_NRO_IDP][] = ["DETAIL" => $this->testsuite->consolidateUdpResult($probeindex)];
203
            $this->additionalFindings[AbstractTest::INFRA_IDP_RADIUS][] = ["DETAIL" => $this->testsuite->consolidateUdpResult($probeindex)];
204
        }
205
206
        if ($allAreConversationReject) {
207
            $this->additionalFindings[AbstractTest::INFRA_ETLR][] = ["CONNCHECK" => RADIUSTests::RETVAL_CONVERSATION_REJECT];
208
            $this->additionalFindings[AbstractTest::INFRA_NRO_IDP][] = ["CONNCHECK" => RADIUSTests::RETVAL_CONVERSATION_REJECT];
209
            $this->additionalFindings[AbstractTest::INFRA_IDP_RADIUS][] = ["CONNCHECK" => RADIUSTests::RETVAL_CONVERSATION_REJECT];
210
            $this->additionalFindings[AbstractTest::INFRA_LINK_ETLR_NRO_IDP][] = ["LINKCHECK" => RADIUSTests::L_OK];
211
            // we have actually reached an IdP, so all links are good, and the
212
            // realm is routable in eduroam. So even if it exists in neither DB
213
            // we can exclude the NONEXISTENTREALM case
214
            unset($this->possibleFailureReasons[AbstractTest::INFRA_ETLR]);
215
            unset($this->possibleFailureReasons[AbstractTest::INFRA_NRO_IDP]);
216
            unset($this->possibleFailureReasons[AbstractTest::INFRA_LINK_ETLR_NRO_IDP]);
217
            unset($this->possibleFailureReasons[AbstractTest::INFRA_NONEXISTENTREALM]);
218
        }
219
220
        if ($atLeastOneConversationReject) {
221
            // at least we can be sure it exists
222
            unset($this->possibleFailureReasons[AbstractTest::INFRA_NONEXISTENTREALM]);
223
            // It could still be an IdP RADIUS problem in that some cert oddities 
224
            // in combination with the device lead to a broken auth
225
            // if there is nothing beyond the "REMARK" level, then it's not an IdP problem
226
            // otherwise, add the corresponding warnings and errors to $additionalFindings
227
            switch ($this->additionalFindings[AbstractTest::INFRA_IDP_RADIUS][0]['DETAIL']['level']) {
228
                case RADIUSTests::L_OK:
229
                case RADIUSTests::L_REMARK:
230
                    // both are fine - the IdP is working and the user problem
231
                    // is not on the IdP RADIUS level
232
                    $this->additionalFindings[AbstractTest::INFRA_IDP_RADIUS][] = ["ODDITYLEVEL" => $this->additionalFindings[AbstractTest::INFRA_IDP_RADIUS][0]['DETAIL']['level']];
233
                    unset($this->possibleFailureReasons[AbstractTest::INFRA_IDP_RADIUS]);
234
                    break;
235
                case RADIUSTests::L_WARN:
236
                    $this->additionalFindings[AbstractTest::INFRA_IDP_RADIUS][] = ["ODDITYLEVEL" => RADIUSTests::L_WARN];
237
                    $this->possibleFailureReasons[AbstractTest::INFRA_IDP_RADIUS] = 0.3; // possibly we found the culprit - if RADIUS server is misconfigured AND user is on a device which reacts picky about exactly this oddity.
238
                    break;
239
                case RADIUSTests::L_ERROR:
240
                    $this->additionalFindings[AbstractTest::INFRA_IDP_RADIUS][] = ["ODDITYLEVEL" => RADIUSTests::L_ERROR];
241
                    $this->possibleFailureReasons[AbstractTest::INFRA_IDP_RADIUS] = 0.8; // errors are never good, so we can be reasonably sure we've hit the spot!
242
            }
243
        }
244
    }
245
246
    public function magic() {
247
248
        // simple things first: do we know anything about the realm, either
249
        // because it's a CAT participant or because it's in the eduroam DB?
250
        // if so, we can exclude the INFRA_NONEXISTENTREALM cause
251
252
        $this->additionalFindings[AbstractTest::INFRA_NONEXISTENTREALM][] = ["ID1" => $this->catIdP, "ID2" => $this->dbIdP];
253
254
        if ($this->catIdP != \core\Federation::UNKNOWN_IDP || $this->dbIdP != \core\Federation::UNKNOWN_IDP) {
255
            unset($this->possibleFailureReasons[AbstractTest::INFRA_NONEXISTENTREALM]);
256
        }
257
258
        // let's do the least amount of testing needed:
259
        // - The CAT reachability test already covers ELTRs, IdP NRO level and the IdP itself.
260
        //   if the realm maps to a CAT IdP, we can run the more thorough tests; otherwise just
261
        //   the normal shallow ones
262
263
        if ($this->catIdP > 0) {
264
            $idpObject = new \core\IdP($this->catIdP);
265
            $profileObjects = $idpObject->listProfiles();
266
267
            $bestProfile = FALSE;
268
269
270
            foreach ($profileObjects as $profileObject) {
271
                $mangledRealm = substr($profileObject->realm, strpos($profileObject->realm, "@") + 1);
272
                $readinessLevel = $profileObject->readinessLevel();
273
                if ($readinessLevel == \core\AbstractProfile::READINESS_LEVEL_SHOWTIME && $mangledRealm == $this->realm) {
274
                    $bestProfile = $profileObject;
275
                    break;
276
                }
277
                if ($readinessLevel == \core\AbstractProfile::READINESS_LEVEL_SUFFICIENTCONFIG && $profileObject->realm == $this->realm) {
278
                    $bestProfile = $profileObject;
279
                }
280
            }
281
            if ($bestProfile == FALSE) { // huh? no match on the realm. Then let's take the next-best with SUFFICIENTCONFIG
282
                foreach ($profileObjects as $profileObject) {
283
                    $readinessLevel = $profileObject->readinessLevel();
284
                    if ($readinessLevel == \core\AbstractProfile::READINESS_LEVEL_SUFFICIENTCONFIG) {
285
                        $bestProfile = $profileObject;
286
                        break;
287
                    }
288
                }
289
            }
290
            if ($bestProfile != FALSE) { // still nothing? then there's only a very incomplete profile definition, and we can't work with that. Fall back to shallow
291
                $this->additionalFindings[AbstractTest::INFRA_IDP_RADIUS][] = ["Profile" => $bestProfile->identifier];
292
                $this->testsuite = new RADIUSTests($this->realm, $bestProfile->getRealmCheckOuterUsername(), $bestProfile->getEapMethodsinOrderOfPreference(1), $bestProfile->getCollapsedAttributes()['eap:server_name'], $bestProfile->getCollapsedAttributes()["eap:ca_file"]);
293
            } else {
294
                $this->additionalFindings[AbstractTest::INFRA_IDP_RADIUS][] = ["Profile" => "UNCONCLUSIVE"];
295
                $this->testsuite = new RADIUSTests($this->realm, "anonymous@" . $this->realm);
296
            }
297
        } else {
298
            $this->testsuite = new RADIUSTests($this->realm, "anonymous@" . $this->realm);
299
        }
300
301
        // these are the normal "realm check" tests covering ETLR, LINK_NRO_IDP, NRO, IDP_RADIUS
302
        $this->CATInternalTests();
303
        // - if the test does NOT go through, we need to find out which of the three is guilty
304
        // - then, the international "via ETLR" check can be used to find out if the IdP alone
305
        //   is guilty. If that one fails, the direct monitoring of servers and ETLRs themselves
306
        //   closes the loop.
307
        // let's see if the ETLRs are up
308 View Code Duplication
        if (array_key_exists(AbstractTest::INFRA_ETLR, $this->possibleFailureReasons)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
309
310
            $etlrStatus = $this->checkEtlrStatus();
311
            $this->additionalFindings[AbstractTest::INFRA_ETLR][] = $etlrStatus;
312
            switch ($etlrStatus["STATUS"]) {
313
                case AbstractTest::STATUS_GOOD:
314
                    unset($this->possibleFailureReasons[AbstractTest::INFRA_ETLR]);
315
                    break;
316
                case AbstractTest::STATUS_PARTIAL:
317
                case AbstractTest::STATUS_MONITORINGFAIL:
318
                    // one of the ETLRs is down, or there is a failure in the monitoring system? 
319
                    // This probably doesn't impact the user unless he's unlucky and has his session fall into failover.
320
                    // keep ETLR as a possible problem with original probability
321
                    break;
322
                case AbstractTest::STATUS_DOWN:
323
                    // Oh! Well if it is not international roaming, that still doesn't have an effect /in this case/. 
324
                    if ($this->idPFederation == $this->visitedFlr) {
325
                        unset($this->possibleFailureReasons[AbstractTest::INFRA_ETLR]);
326
                        break;
327
                    }
328
                    // But it is about int'l roaming, and we are spot on here.
329
                    // Raise probability by much (even monitoring is sometimes wrong, or a few minutes behind reality)
330
                    $this->possibleFailureReasons[AbstractTest::INFRA_ETLR] = 0.95;
331
            }
332
        }
333
334
        // then let's check the IdP's FLR, if we know the IdP federation at all
335
        if ($this->idPFederation != NULL) {
336
            if (array_key_exists(AbstractTest::INFRA_NRO_IDP, $this->possibleFailureReasons)) {
337
                // first the direct connectivity to the server
338
                $flrServerStatus = $this->checkFlrServerStatus($this->idPFederation);
339
                $this->additionalFindings[AbstractTest::INFRA_NRO_IDP][] = $flrServerStatus;
340 View Code Duplication
                switch ($flrServerStatus["STATUS"]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
341
                    case AbstractTest::STATUS_GOOD:
342
                        unset($this->possibleFailureReasons[AbstractTest::INFRA_NRO_IDP]);
343
                        break;
344
                    case AbstractTest::STATUS_PARTIAL:
345
                        // a subset of the FLRs is down? This probably doesn't impact the user unless he's unlucky and has his session fall into failover.
346
                        // keep FLR as a possible problem with original probability
347
                        break;
348
                    case AbstractTest::STATUS_DOWN:
349
                        // Raise probability by much (even monitoring is sometimes wrong, or a few minutes behind reality)
350
                        $this->possibleFailureReasons[AbstractTest::INFRA_NRO_IDP] = 0.95;
351
                }
352
            }
353
354
            // now let's theck the link
355 View Code Duplication
            if (array_key_exists(AbstractTest::INFRA_LINK_ETLR_NRO_IDP, $this->possibleFailureReasons)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
356
                $flrUplinkStatus = $this->checkFedEtlrUplink($this->idPFederation);
357
                $this->additionalFindings[AbstractTest::INFRA_NRO_IDP][] = $flrUplinkStatus;
358
                switch ($flrUplinkStatus["STATUS"]) {
359
                    case AbstractTest::STATUS_GOOD:
360
                        unset($this->possibleFailureReasons[AbstractTest::INFRA_NRO_IDP]);
361
                        unset($this->possibleFailureReasons[AbstractTest::INFRA_LINK_ETLR_NRO_IDP]);
362
                        break;
363
                    case AbstractTest::STATUS_PARTIAL:
364
                        // a subset of the FLRs is down? This probably doesn't impact the user unless he's unlucky and has his session fall into failover.
365
                        // keep FLR as a possible problem with original probability
366
                        break;
367
                    case AbstractTest::STATUS_DOWN:
368
                        // Raise probability by much (even monitoring is sometimes wrong, or a few minutes behind reality)
369
                        // if earlier test found the server itself to be the problem, keep it, otherwise put the blame on the link
370
                        if ($this->possibleFailureReasons[AbstractTest::INFRA_NRO_IDP] != 0.95) {
371
                            $this->possibleFailureReasons[AbstractTest::INFRA_LINK_ETLR_NRO_IDP] = 0.95;
372
                        }
373
                }
374
            }
375
        }
376
        // now, if we know the country the user is currently in, let's see 
377
        // if the NRO SP-side is up
378
        if ($this->visitedFlr !== NULL) {
379
            $visitedFlrStatus = $this->checkFlrServerStatus($this->visitedFlr);
380
            $this->additionalFindings[AbstractTest::INFRA_NRO_SP][] = $visitedFlrStatus;
381
            // direct query to server
382 View Code Duplication
            switch ($visitedFlrStatus["STATUS"]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
383
                case AbstractTest::STATUS_GOOD:
384
                    unset($this->possibleFailureReasons[AbstractTest::INFRA_NRO_SP]);
385
                    break;
386
                case AbstractTest::STATUS_PARTIAL:
387
                    // a subset of the FLRs is down? This probably doesn't impact the user unless he's unlucky and has his session fall into failover.
388
                    // keep FLR as a possible problem with original probability
389
                    break;
390
                case AbstractTest::STATUS_DOWN:
391
                    // Raise probability by much (even monitoring is sometimes wrong, or a few minutes behind reality)
392
                    $this->possibleFailureReasons[AbstractTest::INFRA_NRO_SP] = 0.95;
393
            }
394
            // and again its uplink to the ETLR
395
            $visitedFlrUplinkStatus = $this->checkFedEtlrUplink($this->visitedFlr);
396
            $this->additionalFindings[AbstractTest::INFRA_NRO_SP][] = $visitedFlrUplinkStatus;
397
            switch ($visitedFlrUplinkStatus["STATUS"]) {
398
                case AbstractTest::STATUS_GOOD:
399
                    unset($this->possibleFailureReasons[AbstractTest::INFRA_NRO_SP]);
400
                    unset($this->possibleFailureReasons[AbstractTest::INFRA_LINK_ETLR_NRO_SP]);
401
                    break;
402
                case AbstractTest::STATUS_PARTIAL:
403
                    // a subset of the FLRs is down? This probably doesn't impact the user unless he's unlucky and has his session fall into failover.
404
                    // keep FLR as a possible problem with original probability
405
                    break;
406
                case AbstractTest::STATUS_DOWN:
407
                    // Raise probability by much (even monitoring is sometimes wrong, or a few minutes behind reality)
408
                    // if earlier test found the server itself to be the problem, keep it, otherwise put the blame on the link
409
                    if ($this->possibleFailureReasons[AbstractTest::INFRA_NRO_SP] != 0.95) {
410
                        $this->possibleFailureReasons[AbstractTest::INFRA_LINK_ETLR_NRO_SP] = 0.95;
411
                    }
412
            }
413
        }
414
        // the last thing we can do (but it's a bit redundant): check the country-to-country link
415
        // it's only needed if all three and their links are up, but we want to exclude funny routing blacklists 
416
        // which occur only in the *combination* of source and dest
417
        // if there is an issue at that point, blame the SP: once a request
418
        // would have reached the ETLRs, things would be all good (assuming
419
        // perfection on the ETLRs here!). So the SP has a wrong config.
420
        if ($this->idPFederation !== NULL &&
421
                $this->visitedFlr !== NULL &&
422
                !array_key_exists(AbstractTest::INFRA_ETLR, $this->possibleFailureReasons) &&
423
                !array_key_exists(AbstractTest::INFRA_LINK_ETLR_NRO_IDP, $this->possibleFailureReasons) &&
424
                !array_key_exists(AbstractTest::INFRA_NRO_IDP, $this->possibleFailureReasons) &&
425
                !array_key_exists(AbstractTest::INFRA_LINK_ETLR_NRO_SP, $this->possibleFailureReasons) &&
426
                !array_key_exists(AbstractTest::INFRA_NRO_SP, $this->possibleFailureReasons)
427
        ) {
428
            $countryToCountryStatus = $this->checkNROFlow();
429
            $this->additionalFindings[AbstractTest::INFRA_NRO_SP][] = $countryToCountryStatus;
430
            $this->additionalFindings[AbstractTest::INFRA_ETLR][] = $countryToCountryStatus;
431
            $this->additionalFindings[AbstractTest::INFRA_NRO_IDP][] = $countryToCountryStatus;
432 View Code Duplication
            switch ($countryToCountryStatus["STATUS"]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
433
                case AbstractTest::STATUS_GOOD:
434
                    // all routes work
435
                    break;
436
                case AbstractTest::STATUS_PARTIAL:
437
                // at least one, or even all have a routing problem
438
                case AbstractTest::STATUS_DOWN:
439
                    // that's rather telling.
440
                    $this->possibleFailureReasons[AbstractTest::INFRA_NRO_SP] = 0.95;
441
            }
442
        }
443
444
        $this->normaliseResultSet();
445
446
        return ["SUSPECTS" => $this->possibleFailureReasons, "EVIDENCE" => $this->additionalFindings];
447
    }
448
449
}
450