Issues (2160)

plugin/keycloak/start.php (2 issues)

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use ChamiloSession as Session;
5
use OneLogin\Saml2\Auth;
0 ignored issues
show
This use statement conflicts with another class in this namespace, Auth. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
use OneLogin\Saml2\AuthnRequest;
7
use OneLogin\Saml2\Settings;
8
9
require_once '../../main/inc/global.inc.php';
10
11
$pluginKeycloak = api_get_plugin_setting('keycloak', 'tool_enable') === 'true';
12
13
if (!$pluginKeycloak) {
14
    api_not_allowed(true);
15
}
16
17
// Create a settings.dist.php
18
if (file_exists('settings.php')) {
19
    require_once 'settings.php';
20
} else {
21
    $message = '';
22
    if (api_is_platform_admin()) {
23
        $message = 'Create a settings.php file in plugin/keycloak/';
24
    }
25
    api_not_allowed(true, $message);
26
}
27
28
$content = '';
29
$auth = new Auth($settingsInfo);
30
31
/*if (isset($_REQUEST['delete'])) {
32
    Session::erase('samlNameId');
33
    Session::erase('samlSessionIndex');
34
    Session::erase('samlNameIdFormat');
35
    Session::erase('samlUserdata');
36
    Session::erase('AuthNRequestID');
37
    Session::erase('LogoutRequestID');
38
    echo 'delete all';
39
    exit;
40
}*/
41
42
$settings = new Settings($settingsInfo);
43
$authRequest = new AuthnRequest($settings);
44
45
$samlRequest = $authRequest->getRequest();
46
$idpData = $settings->getIdPData();
47
48
if (isset($_GET['sso'])) {
49
    $auth->login();
50
// If AuthNRequest ID need to be saved in order to later validate it, do instead
51
    /*$ssoBuiltUrl = $auth->login(null, [], false, false, true);
52
    $_SESSION['AuthNRequestID'] = $auth->getLastRequestID();
53
    header('Pragma: no-cache');
54
    header('Cache-Control: no-cache, must-revalidate');
55
    header('Location: ' . $ssoBuiltUrl);
56
    exit();*/
57
} elseif (isset($_GET['slo'])) {
58
    /*
59
    if (isset($idpData['singleLogoutService']) && isset($idpData['singleLogoutService']['url'])) {
60
        $sloUrl = $idpData['singleLogoutService']['url'];
61
    } else {
62
        throw new Exception("The IdP does not support Single Log Out");
63
    }
64
65
    if (isset($_SESSION['samlSessionIndex']) && !empty($_SESSION['samlSessionIndex'])) {
66
        $logoutRequest = new \OneLogin\Saml2\LogoutRequest($settings, null, $_SESSION['samlSessionIndex']);
67
    } else {
68
        $logoutRequest = new \OneLogin\Saml2\LogoutRequest($settings);
69
    }
70
    $samlRequest = $logoutRequest->getRequest();
71
    $parameters = array('SAMLRequest' => $samlRequest);
72
    $url = \OneLogin\Saml2\Utils::redirect($sloUrl, $parameters, true);
73
    header("Location: $url");
74
    exit;*/
75
    $returnTo = null;
76
    $parameters = [];
77
    $nameId = Session::read('samlNameId');
78
    $sessionIndex = Session::read('samlSessionIndex');
79
    $nameIdFormat = Session::read('samlNameIdFormat');
80
    $auth->logout($returnTo, $parameters, $nameId, $sessionIndex, false, $nameIdFormat);
81
82
// If LogoutRequest ID need to be saved in order to later validate it, do instead
83
    // $sloBuiltUrl = $auth->logout(null, [], $nameId, $sessionIndex, true);
84
    /*$_SESSION['LogoutRequestID'] = $auth->getLastRequestID();
85
    header('Pragma: no-cache');
86
    header('Cache-Control: no-cache, must-revalidate');
87
    header('Location: ' . $sloBuiltUrl);
88
    exit();*/
89
} elseif (isset($_GET['acs'])) {
90
    $requestID = Session::read('AuthNRequestID');
91
    $auth->processResponse($requestID);
92
    $errors = $auth->getErrors();
93
    if (!empty($errors)) {
94
        $content .= '<p>'.implode(', ', $errors).'</p>';
95
    }
96
97
    if (!$auth->isAuthenticated()) {
98
        api_not_allowed(true, $content.'<p>Not authenticated</p>');
99
        exit;
100
    }
101
102
    $keyCloackUserName = $auth->getNameId();
103
    $userInfo = api_get_user_info_from_username($keyCloackUserName);
104
    $attributes = $auth->getAttributes();
105
    $userId = 0;
106
    if (!empty($attributes) && empty($userInfo)) {
107
        $firstName = '';
108
        if (isset($attributes['FirstName']) && !empty($attributes['FirstName'])) {
109
            $firstName = reset($attributes['FirstName']);
110
        }
111
112
        $lastName = '';
113
        if (isset($attributes['LastName']) && !empty($attributes['LastName'])) {
114
            $lastName = reset($attributes['LastName']);
115
        }
116
117
        $email = '';
118
        if (isset($attributes['Email']) && !empty($attributes['Email'])) {
119
            $email = reset($attributes['Email']);
120
        }
121
122
        if (empty($email)) {
123
            api_not_allowed(true);
124
        }
125
126
        $userId = UserManager::create_user(
127
            $firstName,
128
            $lastName,
129
            STUDENT,
130
            $email,
131
            $keyCloackUserName,
132
            '',
133
            '',
134
            '',
135
            '',
136
            '',
137
            'keycloak'
138
        );
139
140
        if ($userId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $userId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
141
            $userInfo = api_get_user_info($userId);
142
        }
143
    } else {
144
        // Only load users that were created using this method.
145
        if ($userInfo['auth_source'] === 'keycloak') {
146
            $userId = $userInfo['user_id'];
147
        }
148
    }
149
150
    if (!empty($userId)) {
151
        // Set chamilo sessions
152
        Session::write('samlUserdata', $auth->getAttributes());
153
        Session::write('samlNameId', $auth->getNameId());
154
        Session::write('samlNameIdFormat', $auth->getNameIdFormat());
155
        Session::write('samlSessionIndex', $auth->getSessionIndex());
156
        Session::erase('AuthNRequestID');
157
158
        // Filling session variables with new data
159
        Session::write('_uid', $userId);
160
        Session::write('_user', $userInfo);
161
        Session::write('is_platformAdmin', false);
162
        Session::write('is_allowedCreateCourse', false);
163
    } else {
164
        Display::addFlash(Display::return_message(get_lang('InvalidId')));
165
    }
166
167
    /*if (isset($_POST['RelayState']) && \OneLogin\Saml2\Utils::getSelfURL() != $_POST['RelayState']) {
168
        $auth->redirectTo($_POST['RelayState']);
169
    }*/
170
    header('Location: '.api_get_path(WEB_PATH));
171
    exit;
172
} elseif (isset($_GET['sls'])) {
173
    $requestID = Session::read('LogoutRequestID');
174
    $auth->processSLO(false, $requestID);
175
    $errors = $auth->getErrors();
176
177
    if (empty($errors)) {
178
        Session::erase('samlNameId');
179
        Session::erase('samlSessionIndex');
180
        Session::erase('samlNameIdFormat');
181
        Session::erase('samlUserdata');
182
        Session::erase('AuthNRequestID');
183
        Session::erase('LogoutRequestID');
184
185
        Display::addFlash(Display::return_message('Sucessfully logged out'));
186
        header('Location: '.api_get_path(WEB_PATH));
187
        exit;
188
    } else {
189
        api_not_allowed(true, implode(', ', $errors));
190
    }
191
}
192
193
$template = new Template('');
194
195
if (isset($_SESSION['samlUserdata'])) {
196
    $attributes = Session::read('samlUserdata');
197
    $params = [];
198
    if (!empty($attributes)) {
199
        $content .= 'You have the following attributes:<br>';
200
        $content .= '<table class="table"><thead><th>Name</th><th>Values</th></thead><tbody>';
201
        foreach ($attributes as $attributeName => $attributeValues) {
202
            $content .= '<tr><td>'.htmlentities($attributeName).'</td><td><ul>';
203
            foreach ($attributeValues as $attributeValue) {
204
                $content .= '<li>'.htmlentities($attributeValue).'</li>';
205
            }
206
            $content .= '</ul></td></tr>';
207
        }
208
        $content .= '</tbody></table>';
209
    } else {
210
        $content .= "<p>You don't have any attribute</p>";
211
    }
212
213
    $content .= '<p><a href="?slo" >Logout</a></p>';
214
} else {
215
    $content .= '<p><a href="?sso" >Login</a></p>';
216
    $content .= '<p><a href="?sso2" >Login and access to attrs.php page</a></p>';
217
}
218
219
$template->assign('content', $content);
220
$template->display_one_col_template();
221