Completed
Push — master ( a1987d...ef66da )
by Terrence
21:32 queued 06:26
created

ShibError::printError()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 63
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 22
nc 4
nop 0
dl 0
loc 63
ccs 0
cts 27
cp 0
crap 20
rs 9.568
c 0
b 0
f 0

How to fix   Long Method   

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
namespace CILogon\Service;
4
5
use CILogon\Service\Util;
6
use CILogon\Service\Content;
7
use CILogon\Service\Loggit;
8
9
/**
10
 * ShibError
11
 * This class handles errors passed by the Shibboleth SP
12
 * software when /etc/shibboleth/shibboleth2.xml is
13
 * configured as follows:
14
 *     <Errors redirectErrors="https://cilogon.org"/>
15
 * Note that with v.2.4.x of the Shibboleth SP software,
16
 * the 'redirectErrors' attribute must be an absolute URL,
17
 * meaning that the shibboleth2.xml file will be different
18
 * for https://test.cilogon.org/.  V.2.5 of the SP
19
 * software should allow relative URLS.
20
 *
21
 * To handle errors from the Shibboleth SP software,
22
 * create a new ShibError instance at the root index.php
23
 * file. The constructor looks for various 'GET'
24
 * parameters that get passed by the SP software. If there
25
 * is an error, it checks to see if the error was caused
26
 * by requesting silver assurance. If so, try the request
27
 * again WITHOUT requesting silver assurance. If not, put
28
 * put an error page with the info provided by the SP
29
 * software.
30
 *
31
 * Example usage:
32
 *     require_once 'ShibError.php';
33
 *     // The class constructor does ALL of the work
34
 *     $shiberror = new ShibError();
35
 */
36
class ShibError
37
{
38
39
    /**
40
     * @var array $errorarray Holds the values of the various shibboleth
41
     *      error parameters
42
     */
43
    private $errorarray;
44
45
    /**
46
     * @var array $errorparams Shibboleth error parameters passed to the
47
     * redirectErrors handler:
48
     * https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPErrors
49
     */
50
    private static $errorparams = array(
51
        'requestURL',    // The URL associated with the request
52
        'errorType',     // The general type of error
53
        'errorText',     // The actual error message
54
        'entityID',      // Name of identity provider, if known
55
        'now',           // Current date and time
56
        'statusCode',    // SAML status code causing error, sent by IdP
57
        'statusCode2',   // SAML sub-status code causing error, sent by IdP
58
        'statusMessage', // SAML status message, sent by IdP
59
        'contactName',   // A support contact name for the IdP
60
                         //     provided by that site's metadata.
61
        'contactEmail',  // A contact email address for the IdP contact
62
                         //     provided by that site's metadata.
63
        'errorURL',      // The URL of an error handling page for the IdP
64
                         //     provided by that site's metadata.
65
    );
66
67
    /**
68
     * __construct
69
     *
70
     * Default constructor. This method attempts to read in the
71
     * various Shibboleth SP error parameters that would have been
72
     * passed as parameters to the 'redirectErrors' handler URL, i.e.
73
     * in the $_GET global variable.
74
     *
75
     * @return ShibError A new ShibError object.
76
     */
77
    public function __construct()
78
    {
79
        $this->errorarray = array();
80
        foreach (static::$errorparams as $param) {
0 ignored issues
show
Bug introduced by
Since $errorparams is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $errorparams to at least protected.
Loading history...
81
            if (isset($_GET[$param])) {
82
                $this->errorarray[$param] = rtrim($_GET[$param]);
83
            }
84
        }
85
86
        if ($this->isError()) {
87
            // Check if we tried to get silver before. If so, don't print
88
            // an error. Instead, try again without asking for silver.
89
            if (Util::getSessionVar('requestsilver') == '1') {
90
                $responseurl = null;
91
                if (strlen(Util::getSessionVar('responseurl')) > 0) {
92
                    $responseurl = Util::getSessionVar('responseurl');
93
                }
94
                $providerId = Util::getPortalOrNormalCookieVar('providerId');
95
                Content::redirectToGetShibUser(
96
                    $providerId,
97
                    'gotuser',
98
                    $responseurl,
99
                    false
100
                );
101
                Util::unsetSessionVar('requestsilver');
102
            // CIL-410 Temporary fix for /secure/testidp Shibboleth error.
103
            // Check for error and redirect to /testidp .
104
            } elseif (($this->errorarray['errorType'] == 'shibsp::ConfigurationException') &&
105
                ($this->errorarray['errorText'] ==
106
                    'None of the configured SessionInitiators handled the request.') &&
107
                (preg_match('%/secure/testidp%', $this->errorarray['requestURL']))
108
                ) {
109
                header('Location: https://' . Util::getDN() . '/testidp/');
110
            // CIL-480 Check for user IdP login failure and OAuth transaction
111
            // and redirect appropriately
112
            } elseif (($this->errorarray['errorType'] == 'opensaml::FatalProfileException') &&
113
                ($this->errorarray['errorText'] == 'SAML response reported an IdP error.') &&
114
                ($this->errorarray['statusCode2'] == 'urn:oasis:names:tc:SAML:2.0:status:AuthnFailed')
115
                ) {
116
                $clientparams = json_decode(Util::getSessionVar('clientparams'), true); // OAuth 2.0
117
                $failureuri = Util::getSessionVar('failureuri'); // OAuth 1.0a
118
                if (array_key_exists('redirect_uri', $clientparams)) {
119
                    Util::unsetAllUserSessionVars();
120
                    header('Location: ' . $clientparams['redirect_uri'] .
121
                        (preg_match('/\?/', $clientparams['redirect_uri'])?'&':'?') .
122
                        'error=access_denied&error_description=' .
123
                        'User%20denied%20authorization%20request' .
124
                        ((array_key_exists('state', $clientparams)) ?
125
                            '&state='.$clientparams['state'] : ''));
126
                } elseif (strlen($failureuri) > 0) {
127
                    Util::unsetAllUserSessionVars();
128
                    header('Location: ' . $failureuri . '?reason=cancel');
129
                } else {
130
                    $this->printError();
131
                }
132
            } else {
133
                $this->printError();
134
            }
135
            exit; // No further processing!!!
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
136
        }
137
    }
138
139
    /**
140
     * isError
141
     *
142
     * This method returns true if several Shibboleth error parameters
143
     * were passed in via the $_GET array. These parameters are sent
144
     * by the Shibboleth SP software when there is an error.
145
     *
146
     * @return bool True if several Shibboleth error parameters were
147
     *         passed to the handler URL. False otherwise.
148
     */
149
    public function isError()
150
    {
151
        return ((isset($this->errorarray['requestURL'])) &&
152
                (isset($this->errorarray['errorType'])) &&
153
                (isset($this->errorarray['errorText'])) &&
154
                (isset($this->errorarray['now'])) &&
155
                (strlen($this->errorarray['requestURL']) > 0) &&
156
                (strlen($this->errorarray['errorType']) > 0) &&
157
                (strlen($this->errorarray['errorText']) > 0) &&
158
                (strlen($this->errorarray['now']) > 0));
159
    }
160
161
    /**
162
     * printError
163
     *
164
     * This method prints out text for an error message page. It also
165
     * logs the error and sends an alert email with the shibboleth
166
     * error parameters. You should probably 'exit()' after you call
167
     * this so more HTML doesn't get output.
168
     */
169
    public function printError()
170
    {
171
        $errorstr1 = '';  // For logging - one line
172
        $errorstr2 = '';  // For HTML and email - multi-line
173
        foreach ($this->errorarray as $key => $value) {
174
            $errorstr1 .= Util::htmlent($key.'="' . $value . '" ');
175
            $errorstr2 .= Util::htmlent(sprintf("%-14s= %s\n", $key, $value));
176
        }
177
178
        $log = new Loggit();
179
        $log->error('Shibboleth error: ' . $errorstr1);
180
181
        Content::printHeader('Shiboleth Error');
182
183
        echo '
184
        <div class="boxed">
185
        ';
186
187
        $erroroutput = '
188
        <p>
189
        The CILogon Service has encountered a Shibboleth error.
190
        </p>
191
        <blockquote><pre>' . $errorstr2 . '</pre>
192
        </blockquote>
193
        <p>
194
        System administrators have been
195
        notified. This may be a temporary error. Please try again later, or
196
        contact us at the email address at the bottom of the page.
197
        </p>
198
        ';
199
200
        $skin = Util::getSkin();
201
        $forceauthn = $skin->getConfigOption('forceauthn');
202
        if ((!is_null($forceauthn)) && ((int)$forceauthn == 1)) {
203
            $erroroutput .= '
204
            <p>
205
            Note that this error may be due to your selected Identity
206
            Provider (IdP) not fully supporting &quot;forced
207
            reauthentication&quot;. This setting forces users to log in at
208
            the IdP every time, thus bypassing Single Sign-On (SSO).
209
            </p>
210
            ';
211
        }
212
213
        Content::printErrorBox($erroroutput);
214
215
        echo '
216
        <div>
217
        ';
218
        Content::printFormHead();
219
        echo '
220
        <input type="submit" name="submit" class="submit" value="Proceed" />
221
        </form>
222
        </div>
223
        ';
224
225
226
        echo '
227
        </div>
228
        ';
229
        Content::printFooter();
230
231
        Util::sendErrorAlert('Shibboleth Error', $errorstr2);
232
    }
233
}
234