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