]> gitweb.fluxo.info Git - lorea/elgg.git/commitdiff
cleaned up the web services unit tests
authorcash <cash@36083f99-b078-4883-b0ff-0f9b5a30f544>
Sun, 25 Oct 2009 21:37:21 +0000 (21:37 +0000)
committercash <cash@36083f99-b078-4883-b0ff-0f9b5a30f544>
Sun, 25 Oct 2009 21:37:21 +0000 (21:37 +0000)
git-svn-id: http://code.elgg.org/elgg/trunk@3581 36083f99-b078-4883-b0ff-0f9b5a30f544

engine/lib/api.php
engine/tests/services/api.php
languages/en.php

index 63826cf74ce912543d704beb60f0c5b772d547ec..38b93cd3a766e2a3d83926b9c2a9a9d8bd84ecba 100644 (file)
@@ -348,8 +348,9 @@ function expose_function($method, $function, array $parameters = NULL, $descript
        }
        
        if ($parameters != NULL) {
-               // ensure the required flag is set correctly in default case
+               // ensure the required flag is set correctly in default case for each parameter
                foreach ($parameters as $key => $value) {
+                       // check if 'required' was specified - if not, make it true
                        if (!array_key_exists('required', $value)) {
                                $parameters[$key]['required'] = true;
                        }
@@ -627,14 +628,13 @@ function verify_parameters($method, $parameters) {
 
        // check that the parameters were registered correctly and all required ones are there
        foreach ($API_METHODS[$method]['parameters'] as $key => $value) {
-               // must be array to describe parameter in expose and type must be defined
+               // this tests the expose structure: must be array to describe parameter and type must be defined
                if (!is_array($value) || !isset($value['type'])) {
                        throw new APIException(sprintf(elgg_echo('APIException:InvalidParameter'), $key, $method));
                }
                                
                // Check that the variable is present in the request if required
-               $is_param_required = !isset($value['required']) || $value['required'];
-               if ($is_param_required && !array_key_exists($key, $parameters)) {
+               if ($value['required'] && !array_key_exists($key, $parameters)) {
                        throw new APIException(sprintf(elgg_echo('APIException:MissingParameterInMethod'), $key, $method));
                }
        }
@@ -739,9 +739,12 @@ function api_auth_key() {
        // check that it is active
        $api_user = get_api_user($CONFIG->site_id, $api_key);
        if (!$api_user) {
-               throw new APIException(elgg_echo('APIException:MissingAPIKey'));
+               // key is not active or does not exist
+               throw new APIException(elgg_echo('APIException:BadAPIKey'));
        }
        
+       // can be used for keeping stats
+       // plugin can also return false to fail this authentication method
        return trigger_plugin_hook('api_key', 'use', $api_key, true);
 }
 
@@ -956,6 +959,34 @@ function cache_hmac_check_replay($hmac) {
 
 // API key functions /////////////////////////////////////////////////////////////////////
 
+/**
+ * Generate a new API user for a site, returning a new keypair on success.
+ *
+ * @param int $site_guid The GUID of the site. (default is current site)
+ */
+function create_api_user($site_guid) {
+       global $CONFIG;
+
+       if (!isset($site_guid)) {
+               $site_guid = $CONFIG->site_id;  
+       }
+       
+       $site_guid = (int)$site_guid;
+
+       $public = sha1(rand().$site_guid.microtime());
+       $secret = sha1(rand().$site_guid.microtime().$public);
+
+       $insert = insert_data("INSERT into {$CONFIG->dbprefix}api_users
+               (site_guid, api_key, secret) values
+               ($site_guid, '$public', '$secret')");
+
+       if ($insert) {
+               return get_api_user($site_guid, $public);
+       }
+
+       return false;
+}
+
 /**
  * Find an API User's details based on the provided public api key. These users are not users in the traditional sense.
  *
@@ -989,29 +1020,6 @@ function remove_api_user($site_guid, $api_key) {
        return false;
 }
 
-/**
- * Generate a new API user for a site, returning a new keypair on success.
- *
- * @param int $site_guid The GUID of the site.
- */
-function create_api_user($site_guid) {
-       global $CONFIG;
-
-       $site_guid = (int)$site_guid;
-
-       $public = sha1(rand().$site_guid.microtime());
-       $secret = sha1(rand().$site_guid.microtime().$public);
-
-       $insert = insert_data("INSERT into {$CONFIG->dbprefix}api_users
-               (site_guid, api_key, secret) values
-               ($site_guid, '$public', '$secret')");
-
-       if ($insert) {
-               return get_api_user($site_guid, $public);
-       }
-
-       return false;
-}
 
 // User Authorization functions ////////////////////////////////////////////////////////////////
 
@@ -1029,7 +1037,7 @@ function pam_auth_usertoken($credentials = NULL) {
 
        $token = get_input('auth_token');
 
-       $validated_userid = validate_user_token($CONFIG->site_id, $token);
+       $validated_userid = validate_user_token($token);
 
        if ($validated_userid) {
                $u = get_entity($validated_userid);
@@ -1071,16 +1079,16 @@ function pam_auth_session($credentials = NULL) {
  * Obtain a token for a user.
  *
  * @param string $username The username
- * @param string $password The password
+ * @param int $expire minutes until token expires (default is 60 minutes)
  */
-function obtain_user_token($username, $password) {
+function create_user_token($username, $expire = 60) {
        global $CONFIG;
 
-       $site = $CONFIG->site_id;
+       $site_guid = $CONFIG->site_id;
        $user = get_user_by_username($username);
        $time = time();
-       $time += 60*60; // token is good for one hour
-       $token = md5(rand(). microtime() . $username . $password . $time . $site);
+       $time += 60 * $expire;
+       $token = md5(rand(). microtime() . $username . $time . $site_guid);
 
        if (!$user) {
                return false;
@@ -1088,7 +1096,7 @@ function obtain_user_token($username, $password) {
 
        if (insert_data("INSERT into {$CONFIG->dbprefix}users_apisessions
                                (user_guid, site_guid, token, expires) values
-                               ({$user->guid}, $site, '$token', '$time') on duplicate key update token='$token', expires='$time'")) {
+                               ({$user->guid}, $site_guid, '$token', '$time') on duplicate key update token='$token', expires='$time'")) {
                return $token;
        }
 
@@ -1101,24 +1109,24 @@ function obtain_user_token($username, $password) {
  * A token registered with one site can not be used from a different apikey(site), so be aware of this
  * during development.
  *
- * @param int $site The ID of the site
  * @param string $token The Token.
+ * @param int $site_guid The ID of the site (default is current site)
  * @return mixed The user id attached to the token or false.
  */
-function validate_user_token($site, $token) {
+function validate_user_token($token, $site_guid) {
        global $CONFIG;
 
-       $site = (int)$site;
-       $token = sanitise_string($token);
-
-       if (!$site) {
-               throw new ConfigurationException(elgg_echo('ConfigurationException:NoSiteID'));
+       if (!isset($site_guid)) {
+               $site_guid = $CONFIG->site_id;  
        }
+       
+       $site_guid = (int)$site_guid;
+       $token = sanitise_string($token);
 
        $time = time();
 
        $user = get_data_row("SELECT * from {$CONFIG->dbprefix}users_apisessions
-               where token='$token' and site_guid=$site and $time < expires");
+               where token='$token' and site_guid=$site_guid and $time < expires");
 
        if ($user) {
                return $user->user_guid;
@@ -1127,6 +1135,43 @@ function validate_user_token($site, $token) {
        return false;
 }
 
+/**
+ * Remove user token
+ * 
+ * @param string $token
+ * @param int $site_guid The ID of the site (default is current site)
+ * @return bool
+ */
+function remove_user_token($token, $site_guid) {
+       global $CONFIG;
+       
+       if (!isset($site_guid)) {
+               $site_guid = $CONFIG->site_id;  
+       }
+       
+       $site_guid = (int)$site_guid;
+       $token = sanitise_string($token);
+               
+       return delete_data("DELETE from {$CONFIG->dbprefix}users_apisessions 
+               where site_guid=$site_guid and token='$token'");        
+}
+
+/**
+ * Remove expired tokens
+ * 
+ * @return bool
+ */
+function remove_expired_user_tokens() {
+       global $CONFIG;
+       
+       $site_guid = $CONFIG->site_id;
+       
+       $time = time();
+       
+       return delete_data("DELETE from {$CONFIG->dbprefix}users_apisessions 
+               where site_guid=$site_guid and expires < $time");       
+}
+
 // Client api functions ///////////////////////////////////////////////////////////////////
 
 /**
@@ -1298,7 +1343,7 @@ function list_all_apis() {
  */
 function auth_gettoken($username, $password) {
        if (authenticate($username, $password)) {
-               $token = obtain_user_token($username, $password);
+               $token = create_user_token($username);
                if ($token) {
                        return $token;
                }
index cad28a45240fd6448ea4463f3e3e61bbc9e8e1c3..66fff268d4d87aa0a04a7644c7d62e852175d210 100644 (file)
@@ -20,34 +20,67 @@ class ElggCoreServicesApiTest extends ElggCoreUnitTest {
        \r
 // expose_function\r
        public function testExposeFunctionNoMethod() {\r
-               \r
-               $this->expectException('InvalidParameterException');\r
-               expose_function();\r
+               try {\r
+                       expose_function();\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'InvalidParameterException');\r
+                       $this->assertIdentical($e->getMessage(), elgg_echo('InvalidParameterException:APIMethodOrFunctionNotSet'));\r
+               }\r
        }\r
        \r
        public function testExposeFunctionNoFunction() {\r
-               $this->expectException('InvalidParameterException');\r
-               expose_function('test');\r
+               try {\r
+                       expose_function('test');\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'InvalidParameterException');\r
+                       $this->assertIdentical($e->getMessage(), elgg_echo('InvalidParameterException:APIMethodOrFunctionNotSet'));\r
+               }\r
        }\r
        \r
        public function testExposeFunctionBadParameters() {\r
-               $this->expectException('InvalidParameterException');\r
-               expose_function('test', 'test', 'BAD');\r
+               try {\r
+                       expose_function('test', 'test', 'BAD');\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'InvalidParameterException');\r
+                       $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('InvalidParameterException:APIParametersArrayStructure'), 'test'));\r
+               }\r
        }\r
        \r
-       public function testExposeFunctionParametersNotArray() {\r
-               $this->expectException('InvalidParameterException');\r
-               expose_function('test', 'test', array('param1' => 'string'));\r
+       public function testExposeFunctionParametersBadArray() {\r
+               try {\r
+                       expose_function('test', 'test', array('param1' => 'string'));\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'InvalidParameterException');\r
+                       $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('InvalidParameterException:APIParametersArrayStructure'), 'test'));\r
+               }\r
        }\r
        \r
        public function testExposeFunctionBadHttpMethod() {\r
-               $this->expectException('InvalidParameterException');\r
-               expose_function('test', 'test', null, '', 'BAD');\r
+               try {\r
+                       expose_function('test', 'test', null, '', 'BAD');\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'InvalidParameterException');\r
+                       $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('InvalidParameterException:UnrecognisedHttpMethod'), 'BAD', 'test'));\r
+               }\r
        }\r
        \r
        public function testExposeFunctionSuccess() {\r
                global $API_METHODS;\r
-               $parameters = array('param1' => array('type' => 'int', 'required' => true));\r
+               // this is a general test but also tests specifically for setting 'required' correctly\r
+               $parameters = array('param1' => array('type' => 'int', 'required' => true), \r
+                                                       'param2' => array('type' => 'bool'),\r
+                                                       'param3' => array('type' => 'string', 'required' => false), );\r
+               \r
+               $this->assertTrue(expose_function('test', 'foo', $parameters));\r
+               \r
+               $parameters = array('param1' => array('type' => 'int', 'required' => true), \r
+                                                       'param2' => array('type' => 'bool', 'required' => true),\r
+                                                       'param3' => array('type' => 'string', 'required' => false), );\r
                $method['function'] = 'foo';\r
                $method['parameters'] = $parameters;\r
                $method['call_method'] = 'GET'; \r
@@ -55,7 +88,6 @@ class ElggCoreServicesApiTest extends ElggCoreUnitTest {
                $method['require_api_auth'] = false;\r
                $method['require_user_auth'] = false;\r
 \r
-               $this->assertTrue(expose_function('test', 'foo', $parameters));\r
                $this->assertIdentical($method, $API_METHODS['test']);\r
        }\r
 \r
@@ -70,26 +102,36 @@ class ElggCoreServicesApiTest extends ElggCoreUnitTest {
        } \r
 \r
 // authenticate_method\r
-       public function testApiMethodNotImplemented() {\r
-               global $CONFIG;\r
-               \r
-               $results = send_api_get_call($CONFIG->wwwroot . 'pg/api/rest/json/', array('method' => 'bad.method'));\r
-               $obj = json_decode($results);\r
-               $this->assertIdentical(sprintf(elgg_echo('APIException:MethodCallNotImplemented'), 'bad.method'), $obj->api[0]->message);\r
+       public function testAuthenticateMethodNotImplemented() {\r
+               try {\r
+                       authenticate_method('BAD');\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'APIException');\r
+                       $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('APIException:MethodCallNotImplemented'), 'BAD'));\r
+               }                               \r
        }\r
-\r
-       public function testAuthenticateForApi() {\r
-               $this->registerFunction(true, false);\r
-               \r
-               $this->expectException('APIException');\r
-               authenticate_method('test');\r
+       \r
+       public function testAuthenticateMethodApiAuth() {\r
+               $this->registerFunction(true);\r
+               try {\r
+                       authenticate_method('test');\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'APIException');\r
+                       $this->assertIdentical($e->getMessage(), elgg_echo('APIException:APIAuthenticationFailed'));\r
+               }                               \r
        }\r
-\r
-       public function testAuthenticateForUser() {\r
+       \r
+       public function testAuthenticateMethodUserAuth() {\r
                $this->registerFunction(false, true);\r
-               \r
-               $this->expectException('APIException');\r
-               authenticate_method('test');\r
+               try {\r
+                       authenticate_method('test');\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'APIException');\r
+                       $this->assertIdentical($e->getMessage(), elgg_echo('APIException:UserAuthenticationFailed'));\r
+               }                               \r
        }\r
        \r
        public function testAuthenticateMethod() {\r
@@ -98,27 +140,67 @@ class ElggCoreServicesApiTest extends ElggCoreUnitTest {
                $this->assertTrue(authenticate_method('test'));\r
        }\r
        \r
-// api_authenticate\r
-       public function testApiAuthenticate() {\r
-               $this->registerFunction(true, false);\r
-               \r
-               $this->assertFalse(api_authenticate());\r
-       }\r
-       \r
 // execute_method\r
+       public function testExecuteMethodNotImplemented() {\r
+               try {\r
+                       execute_method('BAD');\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'APIException');\r
+                       $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('APIException:MethodCallNotImplemented'), 'BAD'));\r
+               }                               \r
+       }\r
+\r
        public function testExecuteMethodNonCallable() {\r
                expose_function('test', 'foo');\r
                \r
-               $this->expectException('ApiException');\r
-               execute_method('test');\r
+               try {\r
+                       execute_method('test');\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'APIException');\r
+                       $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('APIException:FunctionDoesNotExist'), 'test'));\r
+               }                               \r
        }\r
 \r
        public function testExecuteMethodWrongMethod() {\r
                $this->registerFunction();\r
                \r
-               // get when it should be a post\r
-               $this->expectException('CallException');\r
-               execute_method('test');\r
+               try {\r
+                       // GET when it should be a POST\r
+                       execute_method('test');\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'CallException');\r
+                       $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('CallException:InvalidCallMethod'), 'test', 'POST'));\r
+               }                                               \r
+       }\r
+\r
+// verify parameters\r
+       public function testVerifyParametersTypeNotSet() {\r
+               $params = array('param1' => array('required' => true));\r
+               expose_function('test', 'elgg_echo', $params);\r
+               \r
+               try {\r
+                       verify_parameters('test', array());\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'APIException');\r
+                       $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('APIException:InvalidParameter'), 'param1', 'test'));\r
+               }                                               \r
+       }\r
+       \r
+       public function testVerifyParametersMissing() {\r
+               $params = array('param1' => array('type' => 'int', 'required' => true));\r
+               expose_function('test', 'elgg_echo', $params);\r
+               \r
+               try {\r
+                       verify_parameters('test', array());\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'APIException');\r
+                       $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('APIException:MissingParameterInMethod'), 'param1', 'test'));\r
+               }                                               \r
        }\r
        \r
        public function testVerifyParameters() {\r
@@ -126,13 +208,9 @@ class ElggCoreServicesApiTest extends ElggCoreUnitTest {
                \r
                $parameters = array('param1' => 0);\r
                $this->assertTrue(verify_parameters('test', $parameters));\r
-               \r
-               $parameters = array('param2' => true);\r
-               $this->expectException('APIException');\r
-               $this->assertTrue(verify_parameters('test', $parameters));\r
        }\r
        \r
-       public function testserialise_parameters() {\r
+       public function testSerialiseParameters() {\r
                \r
                // int and bool\r
                $this->registerFunction();\r
@@ -177,6 +255,34 @@ class ElggCoreServicesApiTest extends ElggCoreUnitTest {
                $s = serialise_parameters('test', $parameters);\r
        }\r
        \r
+// api key methods\r
+       public function testApiAuthenticate() {\r
+               $this->assertFalse(api_authenticate());\r
+       }\r
+       \r
+       public function testApiAuthKeyNoKey() {\r
+               try {\r
+                       api_auth_key();\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'APIException');\r
+                       $this->assertIdentical($e->getMessage(), elgg_echo('APIException:MissingAPIKey'));\r
+               }\r
+       }\r
+\r
+       public function testApiAuthKeyBadKey() {\r
+               global $CONFIG;\r
+               \r
+               $CONFIG->input['api_key'] = 'BAD';\r
+               try {\r
+                       api_auth_key();\r
+                       $this->assertTrue(FALSE);\r
+               } catch (Exception $e) {\r
+                       $this->assertIsA($e, 'APIException');\r
+                       $this->assertIdentical($e->getMessage(), elgg_echo('APIException:BadAPIKey'));\r
+               }\r
+       }\r
+       \r
        protected function registerFunction($api_auth = false, $user_auth = false, $params = null) {\r
                $parameters = array('param1' => array('type' => 'int', 'required' => true),\r
                                                        'param2' => array('type' => 'bool', 'required' => false), );\r
index 78310b9f7131ebc504d1822a6336830ce25e0db2..5c562431fd4e9517c587ddee6d19795d9e16d6e6 100644 (file)
@@ -138,7 +138,8 @@ $english = array(
        'APIException:AlgorithmNotSupported' => "Algorithm '%s' is not supported or has been disabled.",
        'ConfigurationException:CacheDirNotSet' => "Cache directory 'cache_path' not set.",
        'APIException:NotGetOrPost' => "Request method must be GET or POST",
-       'APIException:MissingAPIKey' => "Missing X-Elgg-apikey HTTP header",
+       'APIException:MissingAPIKey' => "Missing API key",
+       'APIException:BadAPIKey' => "Bad API key",
        'APIException:MissingHmac' => "Missing X-Elgg-hmac header",
        'APIException:MissingHmacAlgo' => "Missing X-Elgg-hmac-algo header",
        'APIException:MissingTime' => "Missing X-Elgg-time header",