]> git.defcon.no Git - hermes/blob - api/lib/auth_base.php
Added license text
[hermes] / api / lib / auth_base.php
1 <?php
2 /*
3 # Copyright (c) 2012, Gjøvik University College
4 # All rights reserved.
5
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions are met:
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above copyright
11 # notice, this list of conditions and the following disclaimer in the
12 # documentation and/or other materials provided with the distribution.
13 # * Neither the name of the Gjøvik University College nor the
14 # names of its contributors may be used to endorse or promote products
15 # derived from this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY Gjøvik University College ''AS IS'' AND ANY
18 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 # DISCLAIMED. IN NO EVENT SHALL Gjøvik University College BE LIABLE FOR ANY
21 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 require_once('config.php');
29
30 $config = get_config();
31
32 function authlevel_value( $level )
33 {
34 switch ( $level )
35 {
36 case 'limited_read':
37 return 1;
38 case 'full_read':
39 return 2;
40 case 'read_write':
41 return 3;
42 default:
43 return 0;
44 }
45 }
46 function authlevel_name( $level )
47 {
48 switch ( $level )
49 {
50 case 1:
51 return 'limited_read';
52 case 2:
53 return 'full_read';
54 case 3:
55 return 'read_write';
56 default:
57 return 'no_access';
58 }
59 }
60
61 /*******************************
62 * Load authentication plugin ..
63 *******************************/
64 if ( preg_match('/^\w+$/', $config['auth_backend']))
65 {
66 if ( !@include_once ( 'lib/auth_plugins/' . $config['auth_backend'] . ".php" ) )
67 { print json_encode( array( 'response' => 'error', 'cause' => 'auth-load' ) ); exit; }
68 }
69 else
70 { print json_encode( array( 'response' => 'error', 'cause' => 'config-error' ) ); exit; }
71 /*******************************/
72
73 function new_key( $hex = false )
74 {
75 // Basically this is at the moment a slightly modified
76 // version of generate_password() from user_functiions.php
77 // The behaviour/output of this function is expected to change
78 // so using generate_password() directly does not make sense...
79 $length = 16;
80 $string = "";
81 while ( strlen( $string ) < $length )
82 {
83 if ( $hex )
84 $string .= substr(md5(rand().rand()), 0, $length+1);
85 else
86 {
87 $string .= crypt( substr(sha1(rand()), 0, $length+1) );
88 $string = preg_replace( '/\W/', '', $string);
89 }
90 }
91 return substr( $string, 1, $length );
92 }
93
94 function simple_authfail()
95 {
96 print json_encode( array( 'response' => 'failed', 'cause' => 'unauthorized', 'description' => 'Not authorized') );
97 exit;
98 }
99
100 function token_auth( )
101 {
102 global $_POST;
103
104 // TODO: Part of ping/pong requirement.
105 // Run a function to clear all authkeys older than 5 minutes.
106 expire_authkeys();
107
108 if ( array_key_exists('session', $_POST )
109 && array_key_exists('auth_key', $_POST ) )
110 {
111 if ( ! check_session($_POST['session'] ) ) simple_authfail();
112 if ( ! check_authkey($_POST['auth_key'] ) ) simple_authfail();
113 }
114 else simple_authfail();
115 }
116
117 function get_cookie_path ()
118 {
119 $name = $_SERVER["SCRIPT_NAME"];
120 $file = basename($name);
121 $path = preg_replace("/".$file."/", "", $name);
122 return $path;
123
124 }
125
126 function check_authkey ( $key )
127 {
128 // TODO: Make real, actual checks...
129 if ( $key ) return true;
130 return false;
131 }
132
133 function expire_authkeys()
134 {
135 global $config;
136
137 // Force deletion of sessions that have expired keys.
138 $query = sprintf("SELECT session, sessid FROM %s WHERE `last` < DATE_SUB( NOW(), INTERVAL %d MINUTE)",
139 $config['sessionkeys_table'],
140 $config['sessionkey_lifetime']);
141 $result = sql_dbquery( $config['hermes_db'], $query );
142 while ( $row = @mysql_fetch_row( $result ) )
143 {
144 remove_session( $row[0], $row[1] );
145 }
146
147 $query = sprintf("DELETE FROM %s WHERE `last` < DATE_SUB( NOW(), INTERVAL %d MINUTE)",
148 $config['sessionkeys_table'],
149 $config['sessionkey_lifetime']);
150
151 sql_dbexec( $config['hermes_db'], $query );
152 }
153
154 function update_authkey ( $session, $authid )
155 {
156 global $config;
157
158 $key = substr(new_key(), 0, 8);
159
160 expire_authkeys();
161
162 // TODO: Refresh cookie
163
164 $remote = $_SERVER['REMOTE_ADDR'];
165 $query = sprintf("INSERT INTO %s ( `sessid`, `session`, `authid`, `client`, `key`, `last` )
166 VALUES ( '%s', '%s', '%s', '%s', '%s', NOW() )
167 ON DUPLICATE KEY UPDATE `key` = '%s', `last` = NOW()",
168 $config['sessionkeys_table'],
169 session_id(),
170 session_name(),
171 sql_clean($authid),
172 sql_clean($remote),
173 sql_clean($key),
174 sql_clean($key));
175 if ( ! sql_dbexec( $config['hermes_db'], $query ) )
176 {
177 mysql_error();
178 }
179 $_SESSION['kkey'] = $key;
180 $_SESSION['when'] = time();
181 return $key;
182 }
183
184 function check_session ( $name )
185 {
186 session_name( $name );
187 session_start();
188 if ( ! $_SESSION['authid'] )
189 {
190 return clear_credentials($name);
191 }
192 if ( ! $_COOKIE['client_key'] )
193 {
194 return clear_credentials($name);
195 }
196
197 $authid = $_SESSION['authid'];
198 $type = $_SESSION['type'];
199 $client_key = $_COOKIE['client_key'];
200
201 $level = get_authorization( $type, $authid );
202 if ( $level == false )
203 {
204 return clear_credentials($name);
205 }
206
207 $session_key = md5( $name . $authid );
208 if ( $client_key != $session_key )
209 {
210 return clear_credentials($name);
211 }
212
213 // If we got this far, things are looking good.
214 return true;
215 }
216
217 function set_credentials( $authid, $type )
218 {
219 $name = new_key(true);
220 session_name( $name );
221 session_start();
222 $_SESSION['authid'] = $authid;
223 $_SESSION['type'] = $type;
224
225 $client_key = md5( $name . $authid );
226 setcookie('client_key', $client_key, time()+180*60, get_cookie_path() );
227
228 return $name;
229 }
230
231 function clear_credentials($name)
232 {
233 global $config;
234
235 setcookie('client_key', '', 0, get_cookie_path() );
236
237 remove_session($name);
238 $_SESSION = array();
239
240 $query = sprintf("DELETE FROM %s WHERE `session` = '%s'",
241 $config['sessionkeys_table'],
242 sql_clean($name));
243 sql_dbexec( $config['hermes_db'], $query );
244
245 return false;
246 }
247
248 function remove_session ($name, $id = null )
249 {
250 if ( $id == null )
251 {
252 session_destroy();
253 setcookie($name, '', 0, "/");
254 return;
255 }
256 $current_session = session_name( );
257 $current_sessid = session_id( );
258 session_commit();
259
260 session_id( $id );
261 session_start();
262 setcookie( $name, '', 0, "/");
263 $_SESSION=array();
264 session_destroy();
265
266 if ( $current_session && $current_session != $name )
267 {
268 session_id($current_sessid);
269 session_start();
270 }
271 }
272 function add_apikey ( $host, $level )
273 {
274 global $config;
275 if ( !is_numeric($level) ) return false;
276
277 $key = new_key();
278
279 // Try to add the new key to authorizations first. If this
280 // fails, there will be the least amount of data to clean up ...
281 if ( ! update_authorization( "key", $key, $level ) ) return false;
282
283 $query = sprintf("INSERT INTO %s ( host, apikey ) VALUES ( '%s', '%s' )",
284 $config['apikeys_table'],
285 sql_clean($host),
286 sql_clean($key));
287
288 if ( ! sql_dbexec( $config['hermes_db'], $query ) ) return false;
289 return $key;
290 }
291
292 function remove_apikey( $key )
293 {
294 global $config;
295 if ( ! verify_apikey( $key, true ) ) return false;
296 if ( ! remove_authorization( $key ) ) return false;
297
298 $query = sprintf("DELETE FROM %s WHERE apikey = '%s'",
299 $config['apikeys_table'],
300 sql_clean($key) );
301 if ( ! sql_dbexec( $config['hermes_db'], $query ) ) return false;
302
303 return true;
304 }
305
306 function verify_apikey( $key, $skip_hostcheck = false )
307 {
308 global $config;
309
310 $query = sprintf("SELECT host FROM %s WHERE apikey = '%s'",
311 $config['apikeys_table'],
312 sql_clean($key) );
313 $row = sql_dbquery_single( $config['hermes_db'], $query );
314 if (!$row) return false;
315 $host = $row['host'];
316
317 if ( $host && ( $skip_hostcheck ) )
318 return true;
319
320 if ( $host == $_SERVER['REMOTE_ADDR'] ) return true;
321 return false;
322
323 }
324
325 function list_apikeys ()
326 {
327 global $config;
328 $query = sprintf("SELECT k.apikey AS apikey, k.host AS host,
329 a.access_level AS access_level
330 FROM %s k INNER JOIN %s a ON k.apikey = a.authid
331 WHERE a.type = 'key'",
332 $config['apikeys_table'],
333 $config['authorizations_table']);
334 $list = array();
335 $result = sql_dbquery( $config['hermes_db'], $query);
336 if ( ! $result ) return $list;
337 while ( $row = @mysql_fetch_assoc( $result ) )
338 {
339 array_push( $list, array(
340 'api_key' => $row['apikey'],
341 'host' => $row['host'],
342 'level' => authlevel_name( $row['access_level'] )
343 ));
344 }
345 return $list;
346
347 }
348
349 function list_authusers ()
350 {
351 global $config;
352 $query = sprintf("SELECT authid, access_level
353 FROM %s
354 WHERE type = 'user'",
355 $config['authorizations_table']);
356 $list = array();
357 $result = sql_dbquery( $config['hermes_db'], $query);
358 if ( ! $result ) return $list;
359 while ( $row = @mysql_fetch_assoc( $result ) )
360 {
361 $username = $row['authid'];
362 $user_data = authuser_getinfo( $username );
363
364 // TODO: Remove invalid users here?
365 if ( ! $user_data ) continue;
366
367 array_push( $list, array(
368 'user' => $username,
369 'name' => $user_data['name'],
370 'email' => $user_data['email'],
371 'level' => authlevel_name( $row['access_level'] )
372 ));
373 }
374 return $list;
375
376 }
377
378
379
380 function update_authorization( $type, $authid, $level )
381 {
382 global $config;
383 if ( !is_numeric($level) ) return false;
384 if ( ($type != "key") && ($type != "user") ) return false;
385
386 $query = sprintf("INSERT INTO %s ( authid, type, access_level ) VALUES ( '%s', '%s', %d )
387 ON DUPLICATE KEY UPDATE access_level=%d",
388 $config['authorizations_table'],
389 sql_clean($authid),
390 $type,
391 $level, $level);
392 if ( ! sql_dbexec( $config['hermes_db'], $query ) ) return false;
393 return true;
394 }
395
396 function remove_authorization( $authid )
397 {
398 global $config;
399 $query = sprintf("DELETE FROM %s WHERE authid = '%s'",
400 $config['authorizations_table'],
401 sql_clean($authid) );
402 //print $query . "\n\n";
403 if ( ! sql_dbexec( $config['hermes_db'], $query ) ) return false;
404 return true;
405 }
406
407
408 function get_authorization( $type, $authid )
409 {
410 global $config;
411
412 // If API-key is used, but key fails verification, write is impossible.
413 if ( ( $type == "key" ) && ( ! verify_apikey( $authid, true ) ) )
414 return false;
415
416 // If User-login is used, but backend is unable to provide info, fail.
417 if ( ( $type == "user" ) && ( ! authuser_getinfo( $authid ) ) )
418 return false;
419
420 // The only types of access control supported are "user" or "key".
421 if ( ($type != "user" ) && ($type != "key") )
422 return false;
423
424 $query = sprintf("SELECT access_level FROM %s WHERE authid = '%s'",
425 $config['authorizations_table'],
426 sql_clean($authid) );
427 $row = sql_dbquery_single( $config['hermes_db'], $query );
428 if (!$row) return false;
429 $level = $row['access_level'];
430 return $level;
431 }
432
433 function can_write ( )
434 {
435 // Stub, to be called on any API nodes that write data in the DB.
436 $authid = $_SESSION['authid'];
437 $type = $_SESSION['type'];
438
439 $level = get_authorization( $type, $authid );
440 if ( $level >= authlevel_value('read_write') ) return $level;
441 else return false;
442 }
443
444 ?>