}
//*************************************************************************************
+if ( ( $_SERVER['PATH_INFO'] == "/login" ) || ( $_SERVER['PATH_INFO'] == "/logout" ) )
+{
switch ( $_SERVER['PATH_INFO'] )
{
case "/login":
}
else if ( array_key_exists('api_key', $_GET) )
{
- if ( apikey_verify( sql_clean( $_GET['api_key'] ) ) == 1 )
+ if ( verify_apikey( sql_clean( $_GET['api_key'] ) ) == 1 )
{
$type = "key";
$authid = $_GET['api_key'];
$auth_key = update_authkey( $session_name, $authid );
print json_encode( array( 'response' => 'ok', 'session' => $session_name, 'auth_key' => $auth_key ));
break;
- case "/ping":
- // API clients are required to periodically ping the server
- // The time between pings (interval) is 5 minutes?
- // A ping call refreshes cookie lifetimes, then
- // generates and stores a new auth_key
- // The ping required a valid session...
- // A successful ping returns a 'response' => 'pong'
- // along with the new auth_key.
- token_auth();
- $session_name = $_GET['session'];
- $authid = $_SESSION['authid'];
- $auth_key = update_authkey( $session_name, $authid );
- print json_encode( array( 'response' => 'pong', 'auth_key' => $auth_key ));
- break;
case "/logout":
// De-authenticate/deauthorize the ongoing session.
// I.e. destroy session data, remove session cookies.
else
print json_encode ( array( 'response' => 'ok') );
break;
- case "/list_users":
- // List valid API user-acounts.
- // Fail with notauthorized if current authentication
- // does not have write access.
- // Should not return users from backend,
- // but should only return users with authorization.
+ default:
+ print json_encode ( array( 'response' => 'invalid') );
+ }
+}
+else
+{
+ token_auth();
+
+ switch ( $_SERVER['PATH_INFO'] )
+ {
+ case "/ping":
+ // API clients are required to periodically ping the server
+ // The time between pings (interval) is 5 minutes?
+ // A ping call refreshes cookie lifetimes, then
+ // generates and stores a new auth_key
+ // The ping required a valid session...
+ // A successful ping returns a 'response' => 'pong'
+ // along with the new auth_key.
+ $session_name = $_GET['session'];
+ $authid = $_SESSION['authid'];
+ $auth_key = update_authkey( $session_name, $authid );
+ print json_encode( array( 'response' => 'pong', 'auth_key' => $auth_key ));
+ break;
+ case "/new_apikey":
+ // If the current authorization has write access, create
+ // a new API key with requested access (ro/rw).
+ if ( ! can_write() )
+ simple_authfail();
+
+ if ( array_key_exists('host_ip', $_GET )
+ && array_key_exists('access', $_GET ))
+ {
+ $host = $_GET['host_ip'];
+ $access = $_GET['access'];
+
+ if (! preg_match("/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/", $host) || ! authlevel_value( $access ) )
+ {
+ print json_encode ( array( 'response' => 'invalid', 'cause' => 'parameters' ) );
+ break;
+ }
+ $level = authlevel_value( $access );
+ $key = add_apikey( $host, $level );
+ if ( ! $key )
+ {
+ print json_encode( array( 'response' => 'failed', 'cause' => 'error', 'detail' => 'Database error.'));
+ break;
+ }
+ print json_encode( array( 'response' => 'ok', 'key' => $key, 'host' => $host, 'access' => authlevel_name( $level ) ) );
+ break;
+ }
+ else print json_encode ( array( 'response' => 'invalid') );
+ break;
+ case "/remove_apikey":
+ // If the current authorization has write access,
+ // remove the given API key.
+ if ( ! can_write() )
+ simple_authfail();
+
+ if ( array_key_exists('api_key', $_GET ) )
+ {
+ $key = sql_clean( $_GET['api_key'] );
+ // Perform a key-verification, skipping host/remote-address check.
+ if ( ! verify_apikey( $key, true ) )
+ {
+ print json_encode( array ( 'response' => 'failed', 'cause' => 'nonexistant'));
+ break;
+ }
+ if ( ! remove_apikey( $key ) )
+ {
+ print json_encode( array( 'response' => 'failed', 'cause' => 'error', 'detail' => 'Database error.'));
+ break;
+ }
+ print json_encode( array( 'response' => 'ok', 'key' => $key ) );
+ break;
+ }
+ else print json_encode ( array( 'response' => 'invalid') );
+ break;
+ case "/list_apikeys":
+ // List valid API keys.
+ // Fail is current authorization does not have write access.
+ if ( ! can_write() )
+ simple_authfail();
+ $list = list_apikeys();
+ print json_encode( array( 'response' => 'ok', 'list' => $list ) );
+ break;
case "/authorize_user":
// Add or update a valid back-end user in authorization
// if the current authentication has write access.
// needed parameters should be username and access level
// If the authorization does not exist, add it.
// If the user is already authorized, replace access level.
+ case "/remove_user":
+ // If the current authentication has write access:
+ // Remove authorization for the given users.
+ // Delete user from backend if backend is read-write.
+ case "/list_users":
+ // List valid API user-acounts.
+ // Fail with notauthorized if current authentication
+ // does not have write access.
+ // Should not return users from backend,
+ // but should only return users with authorization.
case "/add_user":
// Add user to backend if backend is read-write and
// the current authentication has write access.
+ // The created user should be added to authorizations
+ // with an access level of "limited_read (1)"
case "/update_user":
// Update the given user in the backend, if the backend
// is read-write, and the current authentication has
// write access.
- case "/remove_user":
- // Delete user from backend if backend is read-write
- // and the current authentication has write access.
- case "/list_apikeys":
- // List valid API keys.
- // Fail is current authorization does not have write access.
- case "/new_apikey":
- // If the current authorization has write access, create
- // a new API key with requested access (ro/rw).
- case "/remove_apikey":
- // If the current authorization has write access,
- // remove the given API key.
print json_encode ( array( 'response' => 'notimplemented') );
break;
default:
print json_encode ( array( 'response' => 'invalid') );
}
+}
//*************************************************************************************
mysql_close( $config['sql_link'] );
?>
'provision_users_table' => 'users',
'provision_phones_table' => 'phones',
'provision_servers_table' => 'servers',
+ 'apikeys_table' => 'apikeys',
+ 'authorizations_table' => 'authorizations',
'sessionkeys_table' => 'sessionkeys',
'sessionkey_lifetime' => 5, // Minutes
'numbers_table' => 'number_pool',
$config = get_config();
+function authlevel_value( $level )
+{
+ switch ( $level )
+ {
+ case 'limited_read':
+ return 1;
+ case 'full_read':
+ return 2;
+ case 'read_write':
+ return 3;
+ default:
+ return 0;
+ }
+}
+function authlevel_name( $level )
+{
+ switch ( $level )
+ {
+ case 1:
+ return 'limited_read';
+ case 2:
+ return 'full_read';
+ case 3:
+ return 'read_write';
+ default:
+ return 'no_access';
+ }
+}
+
/*******************************
* Load authentication plugin ..
*******************************/
{ print json_encode( array( 'response' => 'error', 'cause' => 'config-error' ) ); exit; }
/*******************************/
-function apikey_verify( $key )
-{
- if ( $key == "6327c08b70f9" ) return 1;
- return false;
-}
-
function new_key( $hex = false )
{
// Basically this is at the moment a slightly modified
while ( strlen( $string ) < $length )
{
if ( $hex )
- $string .= substr(md5(rand().rand()), 0, $length);
+ $string .= substr(md5(rand().rand()), 0, $length+1);
else
{
- $string .= crypt( substr(sha1(rand()), 0, $length) );
+ $string .= crypt( substr(sha1(rand()), 0, $length+1) );
$string = preg_replace( '/\W/', '', $string);
}
}
- return substr( $string, 0, $length );
+ return substr( $string, 1, $length );
}
function simple_authfail()
$_SESSION=array();
session_destroy();
- if ( $current_session != $name )
+ if ( $current_session && $current_session != $name )
{
session_id($current_sessid);
session_start();
}
}
+function add_apikey ( $host, $level )
+{
+ global $config;
+ if ( !is_numeric($level) ) return false;
+
+ $key = new_key();
+
+ // Try to add the new key to authorizations first. If this
+ // fails, there will be the least amount of data to clean up ...
+ if ( ! update_authorization( $key, $level ) ) return false;
+
+ $query = sprintf("INSERT INTO %s ( host, apikey ) VALUES ( '%s', '%s' )",
+ $config['apikeys_table'],
+ sql_clean($host),
+ sql_clean($key));
+
+ if ( ! sql_dbexec( $config['provision_db'], $query ) ) return false;
+ return $key;
+}
+
+function remove_apikey( $key )
+{
+ global $config;
+ if ( ! verify_apikey( $key, true ) ) return false;
+ if ( ! remove_authorization( $key ) ) return false;
+
+ $query = sprintf("DELETE FROM %s WHERE apikey = '%s'",
+ $config['apikeys_table'],
+ sql_clean($key) );
+ if ( ! sql_dbexec( $config['provision_db'], $query ) ) return false;
+
+ return true;
+}
+
+function verify_apikey( $key, $skip_hostcheck = false )
+{
+ global $config;
+
+ $query = sprintf("SELECT host FROM %s WHERE apikey = '%s'",
+ $config['apikeys_table'],
+ sql_clean($key) );
+ $row = sql_dbquery_single( $config['provision_db'], $query );
+ if (!$row) return false;
+ $host = $row['host'];
+
+ if ( $host && ( $skip_hostcheck ) )
+ return true;
+
+ if ( $host == $_SERVER['REMOTE_ADDR'] ) return true;
+ return false;
+
+}
+
+function list_apikeys ()
+{
+ global $config;
+ $query = sprintf("SELECT k.apikey AS apikey, k.host AS host,
+ a.access_level AS access_level
+ FROM %s k INNER JOIN %s a ON k.apikey = a.authid",
+ $config['apikeys_table'],
+ $config['authorizations_table']);
+ $list = array();
+ $result = sql_dbquery( $config['provision_db'], $query);
+ if ( ! $result ) return $list;
+ while ( $row = @mysql_fetch_assoc( $result ) )
+ {
+ array_push( $list, array(
+ 'api_key' => $row['apikey'],
+ 'host' => $row['host'],
+ 'level' => authlevel_name( $row['access_level'] )
+ ));
+ }
+ return $list;
+
+}
+function update_authorization( $authid, $level )
+{
+ global $config;
+ if ( !is_numeric($level) ) return false;
+ $query = sprintf("INSERT INTO %s ( authid, access_level ) VALUES ( '%s', %d )
+ ON DUPLICATE KEY UPDATE access_level=%d",
+ $config['authorizations_table'],
+ sql_clean($authid),
+ $level, $level);
+ if ( ! sql_dbexec( $config['provision_db'], $query ) ) return false;
+ return true;
+}
-function get_authorization()
+function remove_authorization( $authid )
{
- return 1;
+ global $config;
+ $query = sprintf("DELETE FROM %s WHERE authid = '%s'",
+ $config['authorizations_table'],
+ sql_clean($authid) );
+ //print $query . "\n\n";
+ if ( ! sql_dbexec( $config['provision_db'], $query ) ) return false;
+ return true;
}
+
+
+function get_authorization( $type, $authid )
+{
+ global $config;
+
+ // If API-key is used, but key fails verification, write is impossible.
+ if ( ( $type == "key" ) && ( ! verify_apikey( $authid ) ) )
+ return false;
+
+ // If User-login is used, but backend is unable to provide info, fail.
+ if ( ( $type == "user" ) && ( ! authuser_getinfo( $authid ) ) )
+ return false;
+
+ // The only types of access control supported are "user" or "key".
+ if ( ($type != "user" ) && ($type != "key") )
+ return false;
+
+ $query = sprintf("SELECT access_level FROM %s WHERE authid = '%s'",
+ $config['authorizations_table'],
+ sql_clean($authid) );
+ $row = sql_dbquery_single( $config['provision_db'], $query );
+ if (!$row) return false;
+ $level = $row['access_level'];
+ return $level;
+}
+
function can_write ( )
{
// Stub, to be called on any API nodes that write data in the DB.
$authid = $_SESSION['authid'];
$type = $_SESSION['type'];
+
$level = get_authorization( $type, $authid );
- return true;
+ if ( $level >= authlevel_value('read_write') ) return $level;
+ else return false;
}
?>
USE `provision`;
+--
+-- Table structure for table `apikeys`
+--
+
+CREATE TABLE IF NOT EXISTS `apikeys` (
+ `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
+ `host` varchar(64) NOT NULL,
+ `apikey` varchar(128) NOT NULL,
+ PRIMARY KEY (`apikey`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `authorizations`
+--
+
+CREATE TABLE IF NOT EXISTS `authorizations` (
+ `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
+ `authid` varchar(255) NOT NULL,
+ `access_level` int(11) NOT NULL,
+ PRIMARY KEY (`authid`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
--
-- Table structure for table `number_pool`
--