Passed
Push — 1.11.x ( bce6cd...c146d9 )
by Angel Fernando Quiroz
12:25
created

main/auth/key/key_auth.class.php (3 issues)

1
<?php
2
3
use ChamiloSession as Session;
4
5
/**
6
 * Used to authenticate user with an access token. By default this method is disabled.
7
 * Method used primarily to make API calls: Rss, file upload.
8
 *
9
 * Access is granted only for the services that are enabled.
10
 *
11
 * To be secured this method must
12
 *
13
 *      1) be called through httpS to avoid sniffing (note that this is the case anyway with other methods such as cookies)
14
 *      2) the url/access token must be secured
15
 *
16
 * This authentication method is session less. This is to ensure that the navigator
17
 * do not receive an access cookie that will grant it access to other parts of the
18
 * application.
19
 *
20
 *
21
 * Usage:
22
 *
23
 * Enable KeyAuth for a specific service. Add the following lines so that
24
 * the key authentication method is enabled for a specific service before
25
 * calling global.inc.php.
26
 *
27
 *      include_once '.../main/inc/autoload.inc.php';
28
 *      KeyAuth::enable_services('my_service');
29
 *      include_once '.../main/inc/global.inc.php';
30
 *
31
 *
32
 * Enable url access for a short period of time:
33
 *
34
 *      token = KeyAuth::create_temp_token();
35
 *      url = '...?access_token=' . $token ;
36
 *
37
 * @see AccessToken
38
 *
39
 * @license see /license.txt
40
 * @author Laurent Opprecht <[email protected]> for the Univesity of Geneva
41
 */
42
class KeyAuth
43
{
44
    const PARAM_ACCESS_TOKEN = 'access_token';
45
46
    protected static $services = [];
47
48
    protected function __construct()
49
    {
50
    }
51
52
    public static function create_temp_token($service = null, $duration = 60, $user_id = null)
53
    {
54
        return UserApiKeyManager::create_temp_token($service, $duration, $user_id);
55
    }
56
57
    /**
58
     * Returns enabled services.
59
     *
60
     * @return array
61
     */
62
    public static function get_services()
63
    {
64
        return self::$services;
65
    }
66
67
    /**
68
     * Name of the service for which we are goint to check the API Key.
69
     * If empty it disables authentication.
70
     *
71
     * !! 10 chars max !!
72
     *
73
     * @param string $_
74
     */
75
    public static function enable_services($_)
76
    {
77
        $args = func_get_args();
78
        $names = [];
79
        foreach ($args as $arg) {
80
            if (is_object($arg)) {
81
                $f = [$arg, 'get_service_name'];
82
                $name = call_user_func($f);
83
            } else {
84
                $name = $arg;
85
            }
86
            $name = substr($name, 0, 10);
87
            self::$services[$name] = $name;
88
        }
89
    }
90
91
    public static function disable_services($_)
92
    {
93
        $args = func_get_args();
94
        $names = [];
95
        foreach ($args as $name) {
96
            $name = substr($name, 0, 10);
97
            unset(self::$services[$name]);
98
        }
99
    }
100
101
    public static function is_service_enabled($service)
102
    {
103
        $services = self::get_services();
104
        foreach ($services as $s) {
105
            if ($s == $service) {
106
                return true;
107
            }
108
        }
109
110
        return false;
111
    }
112
113
    public static function clear_services()
114
    {
115
        self::$services[$name] = [];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $name seems to be never defined.
Loading history...
116
    }
117
118
    /**
119
     * Enable key authentication for the default service - i.e. chamilo.
120
     */
121
    public static function enable()
122
    {
123
        self::enable_services(UserApiKeyManager::default_service());
124
    }
125
126
    public static function disable()
127
    {
128
        self::$services[$name] = [];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $name seems to be never defined.
Loading history...
129
    }
130
131
    /**
132
     * Returns true if the key authentication method is enabled. False otherwise.
133
     * Default to false.
134
     *
135
     * @return bool
136
     */
137
    public static function is_enabled()
138
    {
139
        return !empty(self::$services);
140
    }
141
142
    /**
143
     * @return KeyAuth
144
     */
145
    public static function instance()
146
    {
147
        static $result = null;
148
        if (empty($result)) {
149
            $result = new self();
150
        }
151
152
        return $result;
153
    }
154
155
    /**
156
     * Returns true if authentication accepts to run otherwise returns false.
157
     *
158
     * @return bool
159
     */
160
    public function accept()
161
    {
162
        /**
163
         * Authentication method must be enabled.
164
         */
165
        if (!self::is_enabled()) {
166
            return false;
167
        }
168
169
        $token = $this->get_access_token();
170
        if ($token->is_empty()) {
171
            return false;
172
        }
173
174
        $key = UserApiKeyManager::get_by_id($token->get_id());
175
        if (empty($key)) {
176
            return false;
177
        }
178
179
        /**
180
         * The service corresponding to the key must be enabled.
181
         */
182
        $service = $key['api_service'];
183
        if (!self::is_service_enabled($service)) {
184
            return false;
185
        }
186
187
        /**
188
         * User associated with the key must be active.
189
         */
190
        $user = api_get_user_info($token->get_user_id());
191
        if (empty($user)) {
192
            return false;
193
        }
194
        if (!$user['active']) {
195
            return false;
196
        }
197
198
        /**
199
         * Token must be valid.
200
         */
201
        return $token->is_valid();
202
    }
203
204
    /**
205
     * If accepted tear down session, log in user and returns true.
206
     * If not accepted do nothing and returns false.
207
     *
208
     * @return bool
209
     */
210
    public function login()
211
    {
212
        if (!$this->accept()) {
213
            return false;
214
        }
215
        /**
216
         * ! important this is to ensure we don't grant access for other parts.
217
         */
218
        Session::destroy();
219
220
        /**
221
         * We don't allow redirection since access is granted only for this call.
222
         */
223
        global $no_redirection, $noredirection;
224
        $no_redirection = true;
225
        $noredirection = true;
226
        Session::write('noredirection', $noredirection);
227
228
        $user_id = $this->get_user_id();
229
        $course_code = $this->get_course_code();
230
        $group_id = $this->get_group_id();
231
232
        Login::init_user($user_id, true);
233
        Login::init_course($course_code, true);
0 ignored issues
show
Deprecated Code introduced by
The function Login::init_course() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

233
        /** @scrutinizer ignore-deprecated */ Login::init_course($course_code, true);
Loading history...
234
        Login::init_group($group_id, true);
235
236
        return true;
237
    }
238
239
    /**
240
     * Returns the request access token.
241
     *
242
     * @return AccessToken
243
     */
244
    public function get_access_token()
245
    {
246
        $string = Request::get(self::PARAM_ACCESS_TOKEN);
247
248
        return AccessToken::parse($string);
249
    }
250
251
    public function get_user_id()
252
    {
253
        return $this->get_access_token()->get_user_id();
254
    }
255
256
    public function get_course_code()
257
    {
258
        return Request::get('cidReq', 0);
259
    }
260
261
    /**
262
     * @return int
263
     */
264
    public function get_group_id()
265
    {
266
        return Request::get('gidReq', 0);
267
    }
268
}
269