Completed
Push — master ( 5afbfa...75f886 )
by Terrence
10:45
created

ShibError::__construct()   C

Complexity

Conditions 7
Paths 15

Size

Total Lines 33
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 33
ccs 0
cts 25
cp 0
rs 6.7272
cc 7
eloc 22
nc 15
nop 1
crap 56
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
     * @param string|null $redirectUrl In case of Shibboleth error, redirect
76
     *        to this URL. If null, then print out error to user.
77
     *
78
     * @return ShibError A new ShibError object.
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
79
     */
80
    public function __construct($redirectUrl = null)
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
81
    {
82
        $this->errorarray = array();
83
        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; consider using self, or increasing the visibility of $errorparams to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
84
            if (isset($_GET[$param])) {
85
                $this->errorarray[$param] = rtrim($_GET[$param]);
86
            }
87
        }
88
89
        if ($this->isError()) {
90
            // Check if we tried to get silver before. If so, don't print
91
            // an error. Instead, try again without asking for silver.
92
            if (Util::getSessionVar('requestsilver') == '1') {
93
                $responseurl = null;
94
                if (strlen(Util::getSessionVar('responseurl')) > 0) {
95
                    $responseurl = Util::getSessionVar('responseurl');
96
                }
97
                $providerId = Util::getPortalOrNormalCookieVar('providerId');
98
                Content::redirectToGetShibUser(
99
                    $providerId,
100
                    'gotuser',
101
                    $responseurl,
102
                    false
103
                );
104
            } elseif (!is_null($redirectUrl)) {
105
                header('Location: ' . $redirectUrl);
106
            } else {
107
                $this->printError();
108
            }
109
            Util::unsetSessionVar('requestsilver');
110
            exit; // No further processing!!!
0 ignored issues
show
Coding Style Compatibility introduced by
The method __construct() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

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