From 672f041e45c91540c7246f22728b6eb444612013 Mon Sep 17 00:00:00 2001 From: Jon Langseth Date: Fri, 20 Jan 2012 15:47:43 +0100 Subject: [PATCH] Added support for user-based authentication, resulting changes: Implemented auth-nodes: authorize_user, remove_user, list_users. Changed access-responses from int to string. Modified update_authorizations() and authorizations table to include user-type. Made list_apikeys aware of 'type' column. --- api/auth.php | 75 +++++++++++++++++++++++++++++++++++++- api/lib/auth_base.php | 48 +++++++++++++++++++++--- doc/sql-data/structure.sql | 5 +++ 3 files changed, 121 insertions(+), 7 deletions(-) diff --git a/api/auth.php b/api/auth.php index 1513aae..336c6c3 100644 --- a/api/auth.php +++ b/api/auth.php @@ -130,7 +130,7 @@ else 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 ) ) ); + print json_encode( array( 'response' => 'ok', 'key' => $key, 'host' => $host, 'access' => authlevel_name( get_authorization( "key", $key ) ) ) ); break; } else print json_encode ( array( 'response' => 'invalid') ); @@ -175,16 +175,89 @@ else // 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. + if ( ! can_write() ) + simple_authfail(); + + if ( array_key_exists('username', $_GET ) + && array_key_exists('access', $_GET )) + { + $user = $_GET['username']; + $access = $_GET['access']; + $level = authlevel_value( $access ); + + if ( ! $level ) + { + print json_encode ( array( 'response' => 'invalid', 'cause' => 'parameters' ) ); + break; + } + if ( ! authuser_getinfo( $user ) ) + { + print json_encode( array ( 'response' => 'failed', 'cause' => 'nonexistant')); + break; + } + + if ( ! update_authorization( "user", $user, $level ) ) + { + print json_encode( array( 'response' => 'failed', 'cause' => 'error', 'detail' => 'Database error.')); + break; + } + + print json_encode( array( 'response' => 'ok', 'user' => $user, 'access' => authlevel_name( get_authorization( "user", $user ) ) ) ); + break; + } + else print json_encode ( array( 'response' => 'invalid') ); + break; + 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. + if ( ! can_write() ) + simple_authfail(); + + if ( array_key_exists('username', $_GET )) + { + $user = $_GET['username']; + + $t_level = get_authorization( "user", $user ); + + if ( $t_level && ! remove_authorization( $user ) ) + { + print json_encode( array( 'response' => 'failed', 'cause' => 'error', 'detail' => 'Database error.')); + break; + } + if ( ! authmethod_readonly() ) + { + if ( !authuser_getinfo( $user ) ) + { + print json_encode( array ( 'response' => 'failed', 'cause' => 'nonexistant')); + break; + } + if ( !authuser_delete( $user ) ) + { + print json_encode( array( 'response' => 'failed', 'cause' => 'error', 'detail' => 'Database error.')); + break; + } + } + + print json_encode( array( 'response' => 'ok', 'user' => $user, 'access' => authlevel_name( get_authorization( "user", $user ) ) ) ); + break; + } + else print json_encode ( array( 'response' => 'invalid') ); + 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. + if ( ! can_write() ) + simple_authfail(); + $list = list_users(); + print json_encode( array( 'response' => 'ok', 'list' => $list ) ); + break; + case "/add_user": // Add user to backend if backend is read-write and // the current authentication has write access. diff --git a/api/lib/auth_base.php b/api/lib/auth_base.php index 97e557f..a2ce62c 100644 --- a/api/lib/auth_base.php +++ b/api/lib/auth_base.php @@ -252,7 +252,7 @@ function add_apikey ( $host, $level ) // 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; + if ( ! update_authorization( "key", $key, $level ) ) return false; $query = sprintf("INSERT INTO %s ( host, apikey ) VALUES ( '%s', '%s' )", $config['apikeys_table'], @@ -301,7 +301,8 @@ 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", + FROM %s k INNER JOIN %s a ON k.apikey = a.authid + WHERE a.type = 'key'", $config['apikeys_table'], $config['authorizations_table']); $list = array(); @@ -318,14 +319,49 @@ function list_apikeys () return $list; } -function update_authorization( $authid, $level ) + +function list_users () +{ + global $config; + $query = sprintf("SELECT authid, access_level + FROM %s + WHERE type = 'user'", + $config['authorizations_table']); + $list = array(); + $result = sql_dbquery( $config['provision_db'], $query); + if ( ! $result ) return $list; + while ( $row = @mysql_fetch_assoc( $result ) ) + { + $username = $row['authid']; + $user_data = authuser_getinfo( $username ); + + // TODO: Remove invalid users here? + if ( ! $user_data ) continue; + + array_push( $list, array( + 'user' => $username, + 'name' => $user_data['name'], + 'email' => $user_data['email'], + 'level' => authlevel_name( $row['access_level'] ) + )); + } + return $list; + +} + + + +function update_authorization( $type, $authid, $level ) { global $config; if ( !is_numeric($level) ) return false; - $query = sprintf("INSERT INTO %s ( authid, access_level ) VALUES ( '%s', %d ) + if ( ($type != "key") && ($type != "user") ) return false; + + $query = sprintf("INSERT INTO %s ( authid, type, access_level ) VALUES ( '%s', '%s', %d ) ON DUPLICATE KEY UPDATE access_level=%d", $config['authorizations_table'], sql_clean($authid), + $type, $level, $level); if ( ! sql_dbexec( $config['provision_db'], $query ) ) return false; return true; @@ -348,7 +384,7 @@ 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 ) ) ) + if ( ( $type == "key" ) && ( ! verify_apikey( $authid, true ) ) ) return false; // If User-login is used, but backend is unable to provide info, fail. @@ -373,7 +409,7 @@ 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 ); if ( $level >= authlevel_value('read_write') ) return $level; else return false; diff --git a/doc/sql-data/structure.sql b/doc/sql-data/structure.sql index d077eda..b4555a1 100644 --- a/doc/sql-data/structure.sql +++ b/doc/sql-data/structure.sql @@ -1040,12 +1040,17 @@ CREATE TABLE IF NOT EXISTS `apikeys` ( -- Table structure for table `authorizations` -- +DROP TABLE IF EXISTS `authorizations`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE IF NOT EXISTS `authorizations` ( `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, `authid` varchar(255) NOT NULL, + `type` varchar(16) NOT NULL, `access_level` int(11) NOT NULL, PRIMARY KEY (`authid`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; -- -- Table structure for table `number_pool` -- 2.39.2