Authentication::authenticate()   C
last analyzed

Complexity

Conditions 15
Paths 196

Size

Total Lines 67
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 45
c 1
b 0
f 0
dl 0
loc 67
rs 5.1166
cc 15
nc 196
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
 * Contributions to this work were made on behalf of the GÉANT project, a 
5
 * project that has received funding from the European Union’s Framework 
6
 * Programme 7 under Grant Agreements No. 238875 (GN3) and No. 605243 (GN3plus),
7
 * Horizon 2020 research and innovation programme under Grant Agreements No. 
8
 * 691567 (GN4-1) and No. 731122 (GN4-2).
9
 * On behalf of the aforementioned projects, GEANT Association is the sole owner
10
 * of the copyright in all material which was developed by a member of the GÉANT
11
 * project. GÉANT Vereniging (Association) is registered with the Chamber of 
12
 * Commerce in Amsterdam with registration number 40535155 and operates in the 
13
 * UK as a branch of GÉANT Vereniging.
14
 * 
15
 * Registered office: Hoekenrode 3, 1102BR Amsterdam, The Netherlands. 
16
 * UK branch address: City House, 126-130 Hills Road, Cambridge CB2 1PQ, UK
17
 *
18
 * License: see the web/copyright.inc.php file in the file structure or
19
 *          <base_url>/copyright.php after deploying the software
20
 */
21
22
namespace web\lib\admin;
23
24
use Exception;
25
26
/**
27
 * This class handles admin user authentication.
28
 * 
29
 * @author Stefan Winter <[email protected]>
30
 */
31
class Authentication extends \core\common\Entity {
32
33
    /**
34
     * initialise ourselves, and simpleSAMLphp
35
     */
36
    public function __construct() {
37
        parent::__construct();
38
        include_once \config\Master::AUTHENTICATION['ssp-path-to-autoloader'];
39
    }
40
    /**
41
     * finds out whether the user is already authenticated. Does not trigger an authentication if not.
42
     *
43
     * @return boolean auth state
44
     */
45
    public function isAuthenticated() {
46
47
        $authSimple = new \SimpleSAML\Auth\Simple(\config\Master::AUTHENTICATION['ssp-authsource']);
48
        $session = \SimpleSAML\Session::getSessionFromRequest();
49
        $status = $authSimple->isAuthenticated();
50
        $session->cleanup();
51
        return $status;
52
    }
53
54
    /**
55
     * authenticates a user.
56
     * 
57
     * @return void
58
     * @throws Exception
59
     */
60
    public function authenticate() {
61
        \core\common\Entity::intoThePotatoes();
62
        $loggerInstance = new \core\common\Logging();
63
        $authSimple = new \SimpleSAML\Auth\Simple(\config\Master::AUTHENTICATION['ssp-authsource']);
64
        if (!$authSimple->isAuthenticated()) {
65
            $_SESSION['saveLog'] = true;
66
        }
67
        
68
        $authSimple->requireAuth();
69
        $admininfo = $authSimple->getAttributes();
70
        \core\common\Logging::debug_s(4, $admininfo, "SAML ATTR:\n", "\n");
71
        if (isset($_SESSION['saveLog']) && $_SESSION['saveLog'] == true) {
72
            $saveLog = true;
73
        } else {
74
            $saveLog = false;
75
        }
76
        unset($_SESSION['saveLog']);
77
        $session = \SimpleSAML\Session::getSessionFromRequest();
78
        $session->cleanup();
79
        if (!isset($admininfo[\config\Master::AUTHENTICATION['ssp-attrib-identifier']][0])) {
80
            $failtext = "FATAL ERROR: we did not receive a unique user identifier from the authentication source!";
81
            echo $failtext;
82
            throw new Exception($failtext);
83
        }
84
        $user = $admininfo[\config\Master::AUTHENTICATION['ssp-attrib-identifier']][0];
85
        if ($saveLog) {
86
            $loggerInstance->debug(4, "Writing log\n");
87
            $this->logLoginTime($user);
88
        }
89
        $_SESSION['user'] = $user;
90
        $_SESSION['name'] = $admininfo[\config\Master::AUTHENTICATION['ssp-attrib-name']][0] ?? _("Unnamed User");
91
        $_SESSION['auth_email'] = $admininfo[\config\Master::AUTHENTICATION['ssp-attrib-email']][0] ?? _("");
92
        if (isset($admininfo[\config\Master::AUTHENTICATION['ssp-entitlement']])) {
93
            $_SESSION['entitlement'] = $admininfo[\config\Master::AUTHENTICATION['ssp-entitlement']];
94
        }
95
        /*
96
         * This is a nice pathological test case for a user ID.
97
         *
98
         * */
99
        //$_SESSION['user'] = "<saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" NameQualifier=\"https://idp.jisc.ac.uk/idp/shibboleth\" SPNameQualifier=\"https://cat-beta.govroam.uk/simplesaml/module.php/saml/sp/metadata.php/default-sp\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent\">XXXXXXXXXXXXXXXX</saml:NameID>";
100
101
102
        $newNameReceived = FALSE;
103
104
        $userObject = new \core\User($user);
105
106
        $attribMapping = [
107
            "ssp-attrib-name" => "user:realname",
108
            "ssp-attrib-email" => "user:email"];
109
110
        foreach ($attribMapping as $SSPside => $CATside) {
111
            if (isset($admininfo[\config\Master::AUTHENTICATION[$SSPside]][0]) && (count($userObject->getAttributes($CATside)) == 0) && \config\Master::DB['USER']['readonly'] === FALSE) {
112
                $name = $admininfo[\config\Master::AUTHENTICATION[$SSPside]][0];
113
                $userObject->addAttribute($CATside, NULL, $name);
114
                $loggerInstance->writeAudit($_SESSION['user'], "NEW", "User - added $CATside from external auth source");
115
                if ($CATside == "user:realname") {
116
                    $newNameReceived = TRUE;
117
                }
118
            }
119
        }
120
        if (count($userObject->getAttributes('user:realname')) > 0 || $newNameReceived) { // we have a real name in the DB. We trust this more than a session one, so set it
121
            $nameArray = $userObject->getAttributes("user:realname");
122
            if (!empty($nameArray[0])) {
123
                $_SESSION['name'] = $nameArray[0]['value'];
124
            }
125
        }
126
        \core\common\Entity::outOfThePotatoes();
127
    }
128
129
    /**
130
     * deauthenticates the user.
131
     * Sends a SAML LogoutRequest to the IdP, which will kill the SSO session and return us to our own logout_check page.
132
     * 
133
     * @return void
134
     */
135
    public function deauthenticate() {
136
137
        $as = new \SimpleSAML\Auth\Simple(\config\Master::AUTHENTICATION['ssp-authsource']);
138
        $servername = htmlspecialchars(strip_tags(filter_input(INPUT_SERVER, 'SERVER_NAME')));
139
        $scriptself = htmlspecialchars(strip_tags(filter_input(INPUT_SERVER, 'PHP_SELF')));
140
        $url = "https://www.eduroam.org"; // fallback if something goes wrong during URL construction below
141
        $trailerPosition = strrpos($scriptself, "/inc/logout.php");
142
        if ($trailerPosition !== FALSE) {
143
            $base = substr($scriptself, 0, $trailerPosition);
144
            if ($base !== FALSE) {
145
                $url = "//$servername" . $base . "/logout_check.php";
146
            }
147
        }
148
149
        $as->logout([
150
            'ReturnTo' => $url,
151
            'ReturnStateParam' => 'LogoutState',
152
            'ReturnStateStage' => 'MyLogoutState',
153
        ]);
154
    }
155
    
156
    private function logLoginTime($user) {
157
        $handle = \core\DBConnection::handle("INST");
158
        if (!$handle instanceof \core\DBConnection) {
159
            $frontendHandle = $handle;
0 ignored issues
show
Unused Code introduced by
The assignment to $frontendHandle is dead and can be removed.
Loading history...
160
        }
161
        $truncatedUser = substr($user,0,999);      
162
        $handle->exec("INSERT INTO admin_logins (user_id, last_login) VALUES ('$truncatedUser', NOW()) ON DUPLICATE KEY UPDATE last_login=NOW()");
163
    }
164
165
}
166