Example #1
0
 /**
  * Removes API key and Entities generated for test
  *
  * @throws \Scalr\Exception\ModelException
  */
 public static function tearDownAfterClass()
 {
     foreach (array_reverse(static::$testData) as $rec) {
         $class = $rec['class'];
         $entry = $rec['pk'];
         $initProperties = $rec['initProp'];
         $entity = new $class();
         /* @var $entity AbstractEntity */
         foreach ($entity->getIterator()->getPrimaryKey() as $pos => $prop) {
             $entity->{$prop} = $entry[$pos];
         }
         //we should init properties which will be used in delete action
         foreach ($initProperties as $prop => $value) {
             $entity->{$prop} = $value;
         }
         try {
             //deletePk method does not remove related objects
             $entity->delete();
         } catch (Exception $e) {
             //we should remove all created Entities
             \Scalr::logException($e);
         }
     }
     static::$testData = [];
     if (!empty(static::$apiKeyEntity)) {
         static::$apiKeyEntity->delete();
     }
     static::changeLoggerConfiguration();
 }
Example #2
0
 protected function run2($stage)
 {
     $hasone = false;
     //Selects only those users who do not have any key yet
     $rs = $this->db->Execute("\n            SELECT u.id FROM `account_users` u\n            LEFT JOIN `account_user_apikeys` k ON k.user_id = u.id\n            WHERE k.user_id IS NULL\n        ");
     while ($rec = $rs->FetchRow()) {
         if (!$hasone) {
             $this->console->out("Initializing API keys for all users who do not have one...");
             $hasone = true;
         }
         try {
             $apiKey = new ApiKeyEntity($rec['id']);
             $apiKey->save();
         } catch (\Exception $e) {
             continue;
         }
     }
 }
Example #3
0
 /**
  * Remove API key generated for test
  *
  * @afterClass
  */
 public static function tearDownAfterClass()
 {
     foreach (static::$testData as $class => $ids) {
         $ids = array_unique($ids, SORT_REGULAR);
         foreach ($ids as $entry) {
             if (!empty($entry)) {
                 $entity = call_user_func_array([$class, 'findPk'], is_object($entry) ? [$entry] : (array) $entry);
                 if (!empty($entity)) {
                     try {
                         $entity->delete();
                     } catch (Exception $e) {
                         error_log($e->getMessage());
                         error_log($class);
                         error_log(print_r($entry, true));
                     }
                 }
             }
         }
     }
     if (!empty(static::$apiKeyEntity)) {
         static::$apiKeyEntity->delete();
     }
 }
Example #4
0
 /**
  * Removes API key generated for test
  *
  * @afterClass
  */
 public static function tearDownAfterClass()
 {
     ksort(static::$testData, SORT_REGULAR);
     foreach (static::$testData as $priority => $data) {
         foreach ($data as $class => $ids) {
             $ids = array_unique($ids, SORT_REGULAR);
             foreach ($ids as $entry) {
                 if (!empty($entry)) {
                     $entity = call_user_func_array([$class, 'findPk'], is_object($entry) ? [$entry] : (array) $entry);
                     if (!empty($entity)) {
                         try {
                             $entity->delete();
                         } catch (Exception $e) {
                             //                                error_log("{$class}:\t" . $e->getMessage() . "\n " . str_replace("\n", "\n ", print_r($entry, true)));
                         }
                     }
                 }
             }
         }
     }
     if (!empty(static::$apiKeyEntity)) {
         static::$apiKeyEntity->delete();
     }
 }
Example #5
0
 /**
  * Authentication middleware
  */
 public function authenticationMiddleware()
 {
     $bDebug = $this->request->headers('x-scalr-debug', 0) == 1;
     //If API is not enabled
     if (!$this->getContainer()->config('scalr.system.api.enabled')) {
         $this->halt(403, 'API is not enabled. See scalr.system.api.enabled');
     }
     //Authentication
     $keyId = $this->request->headers('x-scalr-key-id');
     $signature = $this->request->headers('x-scalr-signature');
     //ISO-8601 formatted date
     $date = trim(preg_replace('/\\s+/', '', $this->request->headers('x-scalr-date')));
     if (empty($keyId) || empty($signature)) {
         throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'Unsigned request');
     } elseif (empty($date) || ($time = strtotime($date)) === false) {
         throw new ApiErrorException(400, ErrorMessage::ERR_BAD_REQUEST, 'Missing or invalid X-Scalr-Date header');
     }
     $sigparts = explode(' ', $signature, 2);
     if (empty($sigparts) || !in_array($sigparts[0], ['V1-HMAC-SHA256'])) {
         throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'Invalid signature');
     }
     $this->apiKey = ApiKeyEntity::findPk($keyId);
     if (!$this->apiKey instanceof ApiKeyEntity || !$this->apiKey->active) {
         throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'Invalid API Key');
     }
     if (abs(time() - $time) > 300) {
         throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'Request is expired.' . ($bDebug ? ' Now is ' . gmdate('Y-m-d\\TH:i:s\\Z') : ''));
     }
     $now = new \DateTime('now');
     if (empty($this->apiKey->lastUsed) || $now->getTimestamp() - $this->apiKey->lastUsed->getTimestamp() > 10) {
         $this->apiKey->lastUsed = $now;
         $this->apiKey->save();
     }
     $qstr = $this->request->get();
     $canonicalStr = '';
     if (!empty($qstr)) {
         ksort($qstr);
         $canonicalStr = http_build_query($qstr, null, '&', PHP_QUERY_RFC3986);
     }
     $reqBody = $this->request->getBody();
     $stringToSign = $this->request->getMethod() . "\n" . $date . "\n" . $this->request->getPath() . "\n" . $canonicalStr . "\n" . (empty($reqBody) ? '' : $reqBody);
     if ($bDebug) {
         $this->meta->stringToSign = $stringToSign;
     }
     switch ($sigparts[0]) {
         default:
             throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'Invalid signature method. Please use "V1-HMAC-SHA256 [SIGNATURE]"');
             break;
         case 'V1-HMAC-SHA256':
             $algo = strtolower(substr($sigparts[0], 8));
     }
     $sig = base64_encode(hash_hmac($algo, $stringToSign, $this->apiKey->secretKey, 1));
     if ($sig !== $sigparts[1]) {
         throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'Signature does not match');
     }
     $user = Entity\Account\User::findPk($this->apiKey->userId);
     /* @var $user Entity\Account\User */
     if (!$user instanceof Entity\Account\User) {
         throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'User does not exist');
     }
     if ($user->status != Entity\Account\User::STATUS_ACTIVE) {
         throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, 'Inactive user status');
     }
     if (\Scalr::config('scalr.auth_mode') == 'ldap') {
         try {
             $ldap = \Scalr::getContainer()->ldap($user->getLdapUsername(), null);
             if (!$ldap->isValidUsername()) {
                 if ($bDebug && $ldap->getConfig()->debug) {
                     $this->meta->ldapDebug = $ldap->getLog();
                 }
                 throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'User does not exist');
             }
             $user->applyLdapGroups($ldap->getUserGroups());
         } catch (LdapException $e) {
             if ($bDebug && $ldap instanceof LdapClient && $ldap->getConfig()->debug) {
                 $this->meta->ldapDebug = $ldap->getLog();
             }
             throw new \RuntimeException($e->getMessage());
         }
     }
     $this->limiter->checkAccountRateLimit($this->apiKey->keyId);
     //Validates API version
     if ($this->settings[ApiApplication::SETTING_API_VERSION] != 1) {
         throw new ApiErrorException(400, ErrorMessage::ERR_BAD_REQUEST, 'Invalid API version');
     }
     if ($this->request->getBody() !== '' && strtolower($this->request->getMediaType()) !== 'application/json') {
         throw new ApiErrorException(400, ErrorMessage::ERR_BAD_REQUEST, 'Invalid Content-Type');
     }
     $this->setUser($user);
     $container = $this->getContainer();
     //Releases auditloger to ensure it will be updated
     $container->release('auditlogger');
     //Adjusts metadata to invoke audit loger
     $container->setShared('auditlogger.metadata', function ($cont) use($user) {
         return (object) ['user' => $user, 'envId' => null, 'remoteAddr' => $this->request->getIp(), 'ruid' => null, 'requestType' => AuditLogger::REQUEST_TYPE_API, 'systemTask' => null];
     });
 }
Example #6
0
 /**
  * Add test environment, test Acl, setups test user, environment and API key
  */
 public static function setUpBeforeClass()
 {
     if (!Scalr::getContainer()->config->defined('scalr.phpunit.apiv2')) {
         static::markTestIncomplete('phpunit apiv2 configurations is invalid');
     }
     if (Scalr::getContainer()->config->defined('scalr.phpunit.apiv2.params.max_results')) {
         static::$maxResults = Scalr::config('scalr.phpunit.apiv2.params.max_results');
     }
     static::$testUserId = Scalr::config('scalr.phpunit.apiv2.userid');
     static::$user = User::findPk(static::$testUserId);
     static::$testUserType = static::$user->type;
     static::$testEnvId = Scalr::config('scalr.phpunit.apiv2.envid');
     static::$env = Environment::findPk(static::$testEnvId);
     if (empty(static::$user) || empty(static::$env)) {
         static::markTestIncomplete('Either test environment or user is invalid.');
     }
     $apiKeyName = static::getTestName();
     $apiKeyEntity = ApiKeyEntity::findOne([['name' => $apiKeyName], ['userId' => static::$testUserId]]);
     if (empty($apiKeyEntity)) {
         $apiKeyEntity = new ApiKeyEntity(static::$testUserId);
         $apiKeyEntity->name = $apiKeyName;
         $apiKeyEntity->save();
     }
     static::$apiKeyEntity = $apiKeyEntity;
     static::$defaultAcl = Scalr::getContainer()->acl;
     static::$data = [static::$testEnvId => []];
     if (empty(static::$fullAccessAcl)) {
         static::$fullAccessAcl = new ApiTestAcl();
         static::$fullAccessAcl->setDb(Scalr::getContainer()->adodb);
         static::$fullAccessAcl->createTestAccountRole(static::$user->getAccountId(), static::getTestName(ApiFixture::ACL_FULL_ACCESS), ApiTestAcl::ROLE_ID_FULL_ACCESS);
         static::$fullAccessAcl->aclType = ApiFixture::ACL_FULL_ACCESS;
     }
     if (empty(static::$readOnlyAccessAcl)) {
         static::$readOnlyAccessAcl = new ApiTestAcl();
         static::$readOnlyAccessAcl->setDb(Scalr::getContainer()->adodb);
         static::$readOnlyAccessAcl->createTestAccountRole(static::$user->getAccountId(), static::getTestName(ApiFixture::ACL_READ_ONLY_ACCESS), ApiTestAcl::ROLE_ID_READ_ONLY_ACCESS);
         static::$readOnlyAccessAcl->aclType = ApiFixture::ACL_READ_ONLY_ACCESS;
     }
 }
Example #7
0
 /**
  * @param string    $action Action
  * @param JsonData  $keyIds JSON encoded structure
  * @throws Scalr_Exception_InsufficientPermissions
  */
 public function xApiKeysActionHandlerAction($action, JsonData $keyIds)
 {
     if ($this->user->isAdmin() || !\Scalr::config('scalr.system.api.enabled')) {
         throw new Scalr_Exception_InsufficientPermissions();
     }
     $processed = [];
     $errors = [];
     foreach ($keyIds as $keyId) {
         try {
             $apiKeyEntity = ApiKeyEntity::findPk($keyId);
             /* @var $apiKeyEntity ApiKeyEntity */
             if ($apiKeyEntity->userId != $this->user->getId()) {
                 throw new Scalr_Exception_Core('Insufficient permissions to modify API key');
             }
             switch ($action) {
                 case 'delete':
                     $apiKeyEntity->delete();
                     $processed[] = $keyId;
                     break;
                 case 'activate':
                 case 'deactivate':
                     $apiKeyEntity->active = $action == 'activate';
                     $apiKeyEntity->save();
                     $processed[] = $keyId;
                     break;
             }
         } catch (Exception $e) {
             $errors[] = $e->getMessage();
         }
     }
     $num = count($keyIds);
     if (count($processed) == $num) {
         $this->response->success('All API keys processed');
     } else {
         array_walk($errors, function (&$item) {
             $item = '- ' . $item;
         });
         $this->response->warning(sprintf("Successfully processed only %d from %d API KEYS. \nFollowing errors occurred:\n%s", count($processed), $num, join($errors, '')));
     }
     $this->response->data(['processed' => $processed]);
 }