From b7573aeaa2502b3d9b43d0289a5a836b23282ede Mon Sep 17 00:00:00 2001
From: Maximilien Bersoult <mbersoult@centreon.com>
Date: Wed, 28 Mar 2018 15:47:16 +0200
Subject: [PATCH] feat(api): Split role between configuration and realtime

An user can have a role to access to configuration API or realtime API.
---
 .../centreon_administration_widget.class.php  | 17 ++++
 www/api/class/centreon_clapi.class.php        | 17 ++++
 .../centreon_configuration_objects.class.php  | 17 ++++
 .../class/centreon_home_customview.class.php  | 13 +++
 www/api/class/centreon_keepalive.class.php    | 15 +++-
 www/api/class/centreon_metric.class.php       | 13 +++
 www/api/class/centreon_proxy.class.php        | 13 +++
 .../class/centreon_realtime_base.class.php    | 17 ++++
 .../class/centreon_results_acceptor.class.php | 19 +++-
 www/api/class/centreon_wiki.class.php         | 17 ++++
 www/api/class/webService.class.php            | 26 +++++-
 www/api/index.php                             | 14 +--
 www/api/internal.php                          |  2 +-
 www/class/centreonUser.class.php              | 89 ++++++++++++-------
 .../configObject/contact/DB-Func.php          | 43 ++++-----
 .../configObject/contact/formContact.ihtml    |  7 +-
 .../configObject/contact/formContact.php      | 20 +++--
 .../configObject/contact/help.php             |  3 +-
 www/install/createTables.sql                  |  1 +
 .../centreon/Update-DB-2.8.20_to_2.8.21.sql   |  5 ++
 20 files changed, 298 insertions(+), 70 deletions(-)

diff --git a/www/api/class/centreon_administration_widget.class.php b/www/api/class/centreon_administration_widget.class.php
index 5a11d198dd..2cc4d810aa 100644
--- a/www/api/class/centreon_administration_widget.class.php
+++ b/www/api/class/centreon_administration_widget.class.php
@@ -74,4 +74,21 @@ class CentreonAdministrationWidget extends CentreonWebService
         $widgetObj = new CentreonWidget($centreon, $this->pearDB);
         return $widgetObj->getWidgetModels($q, $range);
     }
+
+    /**
+     * Authorize to access to the action
+     *
+     * @param string $action The action name
+     * @param array $user The current user
+     * @param boolean $isInternal If the api is call in internal
+     * @return boolean If the has access to the action
+     */
+    public function authorize($action, $user, $isInternal)
+    {
+        if (parent::authorize($action, $user, $isInternal)) {
+            return true;
+        }
+
+        return $user->hasAccessRestApiConfiguration();
+    }
 }
diff --git a/www/api/class/centreon_clapi.class.php b/www/api/class/centreon_clapi.class.php
index 932b1c08b6..1e506c7238 100644
--- a/www/api/class/centreon_clapi.class.php
+++ b/www/api/class/centreon_clapi.class.php
@@ -189,4 +189,21 @@ class CentreonClapi extends CentreonWebService
         }
         return $return;
     }
+
+    /**
+     * Authorize to access to the action
+     *
+     * @param string $action The action name
+     * @param array $user The current user
+     * @param boolean $isInternal If the api is call in internal
+     * @return boolean If the has access to the action
+     */
+    public function authorize($action, $user, $isInternal)
+    {
+        if (parent::authorize($action, $user, $isInternal)) {
+            return true;
+        }
+
+        return $user->hasAccessRestApiConfiguration();
+    }
 }
diff --git a/www/api/class/centreon_configuration_objects.class.php b/www/api/class/centreon_configuration_objects.class.php
index 55ef936724..6146bf3569 100644
--- a/www/api/class/centreon_configuration_objects.class.php
+++ b/www/api/class/centreon_configuration_objects.class.php
@@ -270,4 +270,21 @@ class CentreonConfigurationObjects extends CentreonWebService
         }
         return $tmpValues;
     }
+
+    /**
+     * Authorize to access to the action
+     *
+     * @param string $action The action name
+     * @param array $user The current user
+     * @param boolean $isInternal If the api is call in internal
+     * @return boolean If the has access to the action
+     */
+    public function authorize($action, $user, $isInternal)
+    {
+        if (parent::authorize($action, $user, $isInternal)) {
+            return true;
+        }
+
+        return $user->hasAccessRestApiConfiguration();
+    }
 }
diff --git a/www/api/class/centreon_home_customview.class.php b/www/api/class/centreon_home_customview.class.php
index 84b7fa4a5c..ff90db6ae0 100644
--- a/www/api/class/centreon_home_customview.class.php
+++ b/www/api/class/centreon_home_customview.class.php
@@ -163,4 +163,17 @@ class CentreonHomeCustomview extends CentreonWebService
             'tabs' => $tabs
         );
     }
+
+    /**
+     * Authorize to access to the action
+     *
+     * @param string $action The action name
+     * @param array $user The current user
+     * @param boolean $isInternal If the api is call in internal
+     * @return boolean If the has access to the action
+     */
+    public function authorize($action, $user, $isInternal)
+    {
+        return true;
+    }
 }
diff --git a/www/api/class/centreon_keepalive.class.php b/www/api/class/centreon_keepalive.class.php
index e055763456..e08d0c64be 100644
--- a/www/api/class/centreon_keepalive.class.php
+++ b/www/api/class/centreon_keepalive.class.php
@@ -50,7 +50,7 @@ class CentreonKeepalive extends CentreonWebService
     {
         parent::__construct();
     }
-    
+
     /**
      * Keep alive
      */
@@ -59,4 +59,17 @@ class CentreonKeepalive extends CentreonWebService
         $session = new CentreonSession();
         $session->updateSession($this->pearDB);
     }
+
+    /**
+     * Authorize to access to the action
+     *
+     * @param string $action The action name
+     * @param array $user The current user
+     * @param boolean $isInternal If the api is call in internal
+     * @return boolean If the has access to the action
+     */
+    public function authorize($action, $user, $isInternal)
+    {
+        return true;
+    }
 }
diff --git a/www/api/class/centreon_metric.class.php b/www/api/class/centreon_metric.class.php
index 1ae1cc4b73..925355b0ac 100644
--- a/www/api/class/centreon_metric.class.php
+++ b/www/api/class/centreon_metric.class.php
@@ -675,4 +675,17 @@ class CentreonMetric extends CentreonWebService
         }
         return $periods;
     }
+
+    /**
+     * Authorize to access to the action
+     *
+     * @param string $action The action name
+     * @param array $user The current user
+     * @param boolean $isInternal If the api is call in internal
+     * @return boolean If the has access to the action
+     */
+    public function authorize($action, $user, $isInternal)
+    {
+        return true;
+    }
 }
diff --git a/www/api/class/centreon_proxy.class.php b/www/api/class/centreon_proxy.class.php
index a2a5ffef4a..a047e8b4b3 100644
--- a/www/api/class/centreon_proxy.class.php
+++ b/www/api/class/centreon_proxy.class.php
@@ -26,4 +26,17 @@ class CentreonProxy extends CentreonWebService
             'message' => $message
         );
     }
+
+    /**
+     * Authorize to access to the action
+     *
+     * @param string $action The action name
+     * @param array $user The current user
+     * @param boolean $isInternal If the api is call in internal
+     * @return boolean If the has access to the action
+     */
+    public function authorize($action, $user, $isInternal)
+    {
+        return true;
+    }
 }
diff --git a/www/api/class/centreon_realtime_base.class.php b/www/api/class/centreon_realtime_base.class.php
index 30637ed158..d0c8637022 100644
--- a/www/api/class/centreon_realtime_base.class.php
+++ b/www/api/class/centreon_realtime_base.class.php
@@ -247,4 +247,21 @@ class CentreonRealtimeBase extends CentreonWebService
         }
         return $tmpValues;
     }
+
+    /**
+     * Authorize to access to the action
+     *
+     * @param string $action The action name
+     * @param array $user The current user
+     * @param boolean $isInternal If the api is call in internal
+     * @return boolean If the has access to the action
+     */
+    public function authorize($action, $user, $isInternal)
+    {
+        if (parent::authorize($action, $user, $isInternal)) {
+            return true;
+        }
+
+        return $user->hasAccessRestApiRealtime();
+    }
 }
diff --git a/www/api/class/centreon_results_acceptor.class.php b/www/api/class/centreon_results_acceptor.class.php
index 999fadcf66..52bef36428 100644
--- a/www/api/class/centreon_results_acceptor.class.php
+++ b/www/api/class/centreon_results_acceptor.class.php
@@ -66,7 +66,7 @@ class CentreonResultsAcceptor extends CentreonConfigurationObjects
     }
 
     /*
-     * Get poller Listing 
+     * Get poller Listing
      */
     private function getPollers()
     {
@@ -236,4 +236,21 @@ class CentreonResultsAcceptor extends CentreonConfigurationObjects
             throw new RestBadRequestException('Bad arguments - Cannot find command list');
         }
     }
+
+    /**
+     * Authorize to access to the action
+     *
+     * @param string $action The action name
+     * @param array $user The current user
+     * @param boolean $isInternal If the api is call in internal
+     * @return boolean If the has access to the action
+     */
+    public function authorize($action, $user, $isInternal)
+    {
+        if (parent::authorize($action, $user, $isInternal)) {
+            return true;
+        }
+
+        return $user->hasAccessRestApiConfiguration();
+    }
 }
diff --git a/www/api/class/centreon_wiki.class.php b/www/api/class/centreon_wiki.class.php
index e669a6fa20..338e397314 100644
--- a/www/api/class/centreon_wiki.class.php
+++ b/www/api/class/centreon_wiki.class.php
@@ -78,4 +78,21 @@ class CentreonWiki extends CentreonWebService
             'result' => $result
         );
     }
+
+    /**
+     * Authorize to access to the action
+     *
+     * @param string $action The action name
+     * @param array $user The current user
+     * @param boolean $isInternal If the api is call in internal
+     * @return boolean If the has access to the action
+     */
+    public function authorize($action, $user, $isInternal)
+    {
+        if (parent::authorize($action, $user, $isInternal)) {
+            return true;
+        }
+
+        return $user->hasAccessRestApiConfiguration();
+    }
 }
diff --git a/www/api/class/webService.class.php b/www/api/class/webService.class.php
index a6244a46c2..4ea72122e7 100644
--- a/www/api/class/webService.class.php
+++ b/www/api/class/webService.class.php
@@ -121,6 +121,23 @@ class CentreonWebService
         }
     }
 
+    /**
+     * Authorize to access to the action
+     *
+     * @param string $action The action name
+     * @param array $user The current user
+     * @param boolean $isInternal If the api is call in internal
+     * @return boolean If the has access to the action
+     */
+    public function authorize($action, $user, $isInternal = false)
+    {
+        if ($isInternal || $user->is_admin()) {
+            return true;
+        }
+
+        return false;
+    }
+
     /**
      * Get webservice
      *
@@ -220,8 +237,11 @@ class CentreonWebService
      * Route the webservice to the good method
      * @global string _CENTREON_PATH_
      * @global type $pearDB3
+     *
+     * @param CentreonUser $user The current user
+     * @param boolean $isInternal If the Rest API call is internal
      */
-    public static function router()
+    public static function router($user, $isInternal = false)
     {
         global $pearDB;
 
@@ -260,6 +280,10 @@ class CentreonWebService
             static::sendJson("Method not found", 404);
         }
 
+        if (false === $wsObj->authorize($action, $user, $isInternal)) {
+            static::sendJson('Forbidden', 403);
+        }
+
         /* Execute the action */
         try {
             static::updateTokenTtl();
diff --git a/www/api/index.php b/www/api/index.php
index 1249620ab7..101b470335 100644
--- a/www/api/index.php
+++ b/www/api/index.php
@@ -50,11 +50,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' &&
     if (false === isset($_POST['username']) || false === isset($_POST['password'])) {
         CentreonWebService::sendJson("Bad parameters", 400);
     }
-    
+
     /* @todo Check if user already have valid token */
     require_once _CENTREON_PATH_ . "/www/class/centreonLog.class.php";
     require_once _CENTREON_PATH_ . "/www/class/centreonAuth.class.php";
-    
+
     /* Authenticate the user */
     $log = new CentreonUserLog(0, $pearDB);
     $auth = new CentreonAuth($_POST['username'], $_POST['password'], 0, $pearDB, $log, 1, "", "API");
@@ -62,10 +62,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' &&
         CentreonWebService::sendJson("Bad credentials", 403);
         exit();
     }
-    
+
     /* Check if user exists in contact table */
     $reachAPI = 0;
-    $res = $pearDB->prepare("SELECT contact_id, reach_api, contact_admin FROM contact WHERE contact_activate = '1' AND contact_register = '1' AND contact_alias = ?");
+    $res = $pearDB->prepare("SELECT contact_id, reach_api, reach_api_rt, contact_admin
+        FROM contact
+        WHERE contact_activate = '1' AND contact_register = '1' AND contact_alias = ?");
     $res = $pearDB->execute($res, array($_POST['username']));
     while ($data = $res->fetchRow()) {
       if (isset($data['contact_admin']) && $data['contact_admin'] == 1) {
@@ -73,6 +75,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' &&
         } else {
             if (isset($data['reach_api']) && $data['reach_api'] == 1) {
                $reachAPI = 1;
+            } else if (isset($data['reach_api_rt']) && $data['reach_api_rt'] == 1) {
+                $reachAPI = 1;
             }
         }
     }
@@ -111,4 +115,4 @@ if (is_null($userInfos)) {
 $centreon = new Centreon($userInfos);
 $oreon = $centreon;
 
-CentreonWebService::router();
+CentreonWebService::router($centreon->user);
diff --git a/www/api/internal.php b/www/api/internal.php
index 6f39d44a06..ea80351013 100644
--- a/www/api/internal.php
+++ b/www/api/internal.php
@@ -64,4 +64,4 @@ if (false === isset($centreon) || false === is_object($centreon)) {
     CentreonWebService::sendJson("Unauthorized", 401);
 }
 
-CentreonWebService::router();
+CentreonWebService::router($centreon->user, true);
diff --git a/www/class/centreonUser.class.php b/www/class/centreonUser.class.php
index c9af2e59f3..8578b57cd2 100644
--- a/www/class/centreonUser.class.php
+++ b/www/class/centreonUser.class.php
@@ -59,7 +59,10 @@ class CentreonUser
 	var $userCrypted;
     protected $token;
     public $default_page;
-        
+
+    protected $restApi;
+    protected $restApiRt;
+
 	# User LCA
 	# Array with elements ID for loop test
 	var $lcaTopo;
@@ -68,7 +71,7 @@ class CentreonUser
 	var $lcaTStr;
 
     /**
-     * 
+     *
      * @global type $pearDB
      * @param type $user
      */
@@ -101,10 +104,16 @@ class CentreonUser
          */
         $this->log = new CentreonUserLog($this->user_id, $pearDB);
         $this->userCrypted = md5($this->alias);
+
+        /**
+         * Init rest api auth
+         */
+        $this->restApi = isset($user['reach_api']) && $user['reach_api'] == 1;
+        $this->restApiRt = isset($user['reach_api_rt']) && $user['reach_api_rt'] == 1;
     }
 
     /**
-     * 
+     *
      * @global type $pearDB
      * @param type $div_name
      * @return int
@@ -124,7 +133,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @param type $pearDB
      * @return int
      */
@@ -140,10 +149,10 @@ class CentreonUser
         $DBRESULT->free();
         return $lcaTopo;
     }
-    
+
     /**
      * Check if user is admin or had ACL
-     * 
+     *
      * @param type $sid
      * @param type $pearDB
      */
@@ -175,7 +184,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @return type
      */
     function get_name()
@@ -184,7 +193,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @return type
      */
     function get_email()
@@ -193,7 +202,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @return type
      */
     function get_alias()
@@ -202,7 +211,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @return type
      */
     function get_version()
@@ -211,7 +220,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @return type
      */
     function get_lang()
@@ -220,7 +229,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @return type
      */
     function get_passwd()
@@ -229,7 +238,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @return type
      */
     function get_admin()
@@ -238,7 +247,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @return type
      */
     function is_admin()
@@ -247,7 +256,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @global type $pearDB
      * @return type
      */
@@ -264,11 +273,11 @@ class CentreonUser
 
         return $this->js_effects;
     }
-  
+
   // Set
 
     /**
-     * 
+     *
      * @param type $id
      */
     function set_id($id)
@@ -277,7 +286,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @param type $name
      */
     function set_name($name)
@@ -286,7 +295,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @param type $email
      */
     function set_email($email)
@@ -295,7 +304,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @param type $lang
      */
     function set_lang($lang)
@@ -304,7 +313,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @param type $alias
      */
     function set_alias($alias)
@@ -313,7 +322,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @param type $version
      */
     function set_version($version)
@@ -322,7 +331,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @param type $js_effects
      */
     function set_js_effects($js_effects)
@@ -331,7 +340,7 @@ class CentreonUser
     }
 
     /**
-     * 
+     *
      * @return type
      */
     function getMyGMT()
@@ -437,7 +446,7 @@ class CentreonUser
             . 'WHERE cp_contact_id = ? '
             . 'AND  cp_key IN( ';
         $queryValues[] = $this->user_id;
-        
+
         $queryKey ='';
         foreach ($keys as $key) {
             $queryKey .=' ?,';
@@ -445,14 +454,14 @@ class CentreonUser
         }
         $queryKey = rtrim($queryKey, ',');
         $deleteQuery .= $queryKey. ' )';
-        
+
         $stmt = $db->prepare($deleteQuery);
         $res = $db->execute($stmt, $queryValues);
-        
+
         if (PEAR::isError($res)) {
             throw new Exception('Bad Request');
         }
-       
+
         $insertQuery = 'INSERT INTO contact_param (cp_key, cp_value, cp_contact_id) VALUES (?, ?, ?)';
         $stmt = $db->prepare($insertQuery);
         foreach ($parameters as $key => $value) {
@@ -460,20 +469,20 @@ class CentreonUser
             $db->execute($stmt, $sqlParams);
         }
     }
-  
+
   /**
    * Get token
-   * 
+   *
    * @return string
    */
     public function getToken()
     {
         return $this->token;
     }
-  
+
   /**
    * Set token
-   * 
+   *
    * @param string $token
    * @return void
    */
@@ -481,4 +490,20 @@ class CentreonUser
     {
         $this->token = $token;
     }
+
+    /**
+     * If the user has access to Rest API Configuration
+     */
+    public function hasAccessRestApiConfiguration()
+    {
+        return $this->restApi;
+    }
+
+    /**
+     * If the user has access to Rest API Realtime
+     */
+    public function hasAccessRestApiRealtime()
+    {
+        return $this->restApiRt;
+    }
 }
diff --git a/www/include/configuration/configObject/contact/DB-Func.php b/www/include/configuration/configObject/contact/DB-Func.php
index 9d059544b3..b30970d297 100644
--- a/www/include/configuration/configObject/contact/DB-Func.php
+++ b/www/include/configuration/configObject/contact/DB-Func.php
@@ -56,7 +56,7 @@ function testContactExistence($name = null)
 
     $DBRESULT = $pearDB->query("SELECT contact_name, contact_id FROM contact WHERE contact_name = '" . htmlentities($centreon->checkIllegalChar($name), ENT_QUOTES, "UTF-8") . "'");
     $contact = $DBRESULT->fetchRow();
-   
+
     if ($DBRESULT->numRows() >= 1 && $contact["contact_id"] == $id) {
         return true;
     } elseif ($DBRESULT->numRows() >= 1 && $contact["contact_id"] != $id) {
@@ -81,7 +81,7 @@ function testAliasExistence($alias = null)
 
     $DBRESULT = $pearDB->query("SELECT contact_alias, contact_id FROM contact WHERE contact_alias = '" . htmlentities($alias, ENT_QUOTES, "UTF-8") . "'");
     $contact = $DBRESULT->fetchRow();
-    
+
     if ($DBRESULT->numRows() >= 1 && $contact["contact_id"] == $id) {
         return true;
     } elseif ($DBRESULT->numRows() >= 1 && $contact["contact_id"] != $id) {
@@ -123,10 +123,10 @@ function keepOneContactAtLeast($ct_id = null)
     /*
      * Get activated contacts
      */
-    $DBRESULT = $pearDB->query("SELECT COUNT(*) AS nbr_valid 
-            FROM contact 
-            WHERE contact_activate = '1' 
-            AND contact_oreon = '1' 
+    $DBRESULT = $pearDB->query("SELECT COUNT(*) AS nbr_valid
+            FROM contact
+            WHERE contact_activate = '1'
+            AND contact_oreon = '1'
             AND contact_id <> '" . $pearDB->escape($contact_id) . "'");
     $contacts = $DBRESULT->fetchRow();
 
@@ -157,7 +157,7 @@ function enableContactInDB($contact_id = null, $contact_arr = array())
 
     foreach ($contact_arr as $key => $value) {
         $DBRESULT = $pearDB->query("UPDATE contact SET contact_activate = '1' WHERE contact_id = '" . intval($key). "'");
-        
+
         $DBRESULT2 = $pearDB->query("SELECT contact_name FROM `contact` WHERE `contact_id` = '" . intval($key) . "' LIMIT 1");
         $row = $DBRESULT2->fetchRow();
 
@@ -185,10 +185,10 @@ function disableContactInDB($contact_id = null, $contact_arr = array())
     foreach ($contact_arr as $key => $value) {
         if (keepOneContactAtLeast($key)) {
             $pearDB->query("UPDATE contact SET contact_activate = '0' WHERE contact_id = '" . intval($key) . "'");
-            
+
             $DBRESULT2 = $pearDB->query("SELECT contact_name FROM `contact` WHERE `contact_id` = '" . intval($key) . "' LIMIT 1");
             $row = $DBRESULT2->fetchRow();
-            
+
             $centreon->CentreonLogAction->insertLog("contact", $key, $row['contact_name'], "disable");
         }
     }
@@ -311,11 +311,11 @@ function multipleContactInDB($contacts = array(), $nbrDup = array())
 function updateContactInDB($contact_id = null, $from_MC = false)
 {
     global $form;
-    
+
     if (!$contact_id) {
         return;
     }
-    
+
     $ret = $form->getSubmitValues();
     # Global function to use
     if ($from_MC) {
@@ -395,7 +395,7 @@ function insertContact($ret = array())
             "`contact_id` , `timeperiod_tp_id` , `timeperiod_tp_id2` , `contact_name` , " .
             "`contact_alias` , `contact_autologin_key` , `contact_passwd` , `contact_lang` , `contact_template_id`, " .
             "`contact_host_notification_options` , `contact_service_notification_options` , " .
-            "`contact_email` , `contact_pager` , `contact_comment` , `contact_oreon`, `reach_api`, `contact_register`, `contact_enable_notifications` , " .
+            "`contact_email` , `contact_pager` , `contact_comment` , `contact_oreon`, `reach_api`, `reach_api_rt`, `contact_register`, `contact_enable_notifications` , " .
             "`contact_admin` , `contact_type_msg`, `contact_activate`, `contact_auth_type`, " .
             "`contact_ldap_dn`, `contact_location`, `contact_address1`, `contact_address2`, " .
             "`contact_address3`, `contact_address4`, `contact_address5`, `contact_address6`)" .
@@ -439,6 +439,7 @@ function insertContact($ret = array())
         isset($ret["contact_oreon"]["contact_oreon"]) && $ret["contact_oreon"]["contact_oreon"] != null ? $rq .= "'" . $ret["contact_oreon"]["contact_oreon"] . "', " : $rq .= " '1', ";
     }
     isset($ret["reach_api"]["reach_api"]) && $ret["reach_api"]["reach_api"] != null ? $rq .= $ret["reach_api"]["reach_api"] . ", " : $rq .= " 0, ";
+    isset($ret["reach_api_rt"]["reach_api_rt"]) && $ret["reach_api_rt"]["reach_api_rt"] != null ? $rq .= $ret["reach_api_rt"]["reach_api_rt"] . ", " : $rq .= " 0, ";
     isset($ret["contact_register"]) && $ret["contact_register"] != null ? $rq .= "'" . $ret["contact_register"] . "', " : $rq .= " '1', ";
     isset($ret["contact_enable_notifications"]["contact_enable_notifications"]) && $ret["contact_enable_notifications"]["contact_enable_notifications"] != null ? $rq .= "'" . $ret["contact_enable_notifications"]["contact_enable_notifications"] . "', " : $rq .= "NULL, ";
     isset($ret["contact_admin"]["contact_admin"]) && $ret["contact_admin"]["contact_admin"] != null ? $rq .= "'" . $ret["contact_admin"]["contact_admin"] . "', " : $rq .= "'0', ";
@@ -468,7 +469,7 @@ function insertContact($ret = array())
             $ret["contact_passwd"] = $ret["contact_passwd2"] = $utilsObject->encodePass($ret["contact_passwd"], 'md5');
         }
     }
-    
+
     /* Prepare value for changelog */
     $fields = CentreonLogAction::prepareChanges($ret);
     $centreon->CentreonLogAction->insertLog("contact", $contact_id["MAX(contact_id)"], $ret["contact_name"], "a", $fields);
@@ -495,7 +496,7 @@ function updateContact($contact_id = null, $from_MC = false)
     $rq .= "timeperiod_tp_id2 = ";
     isset($ret["timeperiod_tp_id2"]) && $ret["timeperiod_tp_id2"] != null ? $rq .= "'" . $ret["timeperiod_tp_id2"] . "', " : $rq .= "NULL, ";
     # If we are doing a MC, we don't have to set name and alias field
-    
+
     if (!$from_MC) {
         $rq .= "contact_name = ";
         isset($ret["contact_name"]) && $ret["contact_name"] != null ? $rq .= "'" . $ret["contact_name"] . "', " : $rq .= "NULL, ";
@@ -531,6 +532,8 @@ function updateContact($contact_id = null, $from_MC = false)
     isset($ret["contact_oreon"]["contact_oreon"]) && $ret["contact_oreon"]["contact_oreon"] != null ? $rq .= "'" . $ret["contact_oreon"]["contact_oreon"] . "', " : $rq .= "NULL, ";
     $rq .= "reach_api = ";
     isset($ret["reach_api"]["reach_api"]) && $ret["reach_api"]["reach_api"] != null ? $rq .= "'" . $ret["reach_api"]["reach_api"] . "', " : $rq .= "NULL, ";
+    $rq .= "reach_api_rt = ";
+    isset($ret["reach_api_rt"]["reach_api_rt"]) && $ret["reach_api_rt"]["reach_api_rt"] != null ? $rq .= "'" . $ret["reach_api_rt"]["reach_api_rt"] . "', " : $rq .= "NULL, ";
     $rq .= "contact_enable_notifications = ";
     isset($ret["contact_enable_notifications"]["contact_enable_notifications"]) && $ret["contact_enable_notifications"]["contact_enable_notifications"] != null ? $rq .= "'" . $ret["contact_enable_notifications"]["contact_enable_notifications"] . "', " : $rq .= "NULL, ";
     $rq .= "contact_admin = ";
@@ -566,7 +569,7 @@ function updateContact($contact_id = null, $from_MC = false)
     if (isset($ret["contact_lang"]) && $ret["contact_lang"] != null && $contact_id == $centreon->user->get_id()) {
         $centreon->user->set_lang($ret["contact_lang"]);
     }
-    
+
     if (isset($ret["contact_passwd"])) {
         if ($encryptType == 1) {
             $ret["contact_passwd"] = $ret["contact_passwd2"] = $utilsObject->encodePass($ret["contact_passwd"], 'md5');
@@ -585,13 +588,13 @@ function updateContact($contact_id = null, $from_MC = false)
 function updateContact_MC($contact_id = null)
 {
     global $form, $pearDB, $centreon, $encryptType;
-    
+
     if (!$contact_id) {
         return;
     }
 
     $utilsObject = new CentreonUtils();
-    
+
     $ret = array();
     $ret = $form->getSubmitValues();
     $rq = "UPDATE contact SET ";
@@ -684,7 +687,7 @@ function updateContact_MC($contact_id = null)
 
         $DBRESULT2 = $pearDB->query("SELECT contact_name FROM `contact` WHERE contact_id='" . intval($contact_id) . "' LIMIT 1");
         $row = $DBRESULT2->fetchRow();
-        
+
         /* Prepare value for changelog */
         $fields = CentreonLogAction::prepareChanges($ret);
         $centreon->CentreonLogAction->insertLog("contact", $contact_id, $row["contact_name"], "mc", $fields);
@@ -694,7 +697,7 @@ function updateContact_MC($contact_id = null)
 function updateContactHostCommands($contact_id = null, $ret = array())
 {
     global $form, $pearDB;
-    
+
     if (!$contact_id) {
         return;
     }
@@ -869,7 +872,7 @@ function insertLdapContactInDB($tmpContacts = array())
         }
         $tmpContacts["contact_name"][$select_key] = str_replace(array(" ", ","), array("_", "_"), $tmpContacts["contact_name"][$select_key]);
         $arId = $tmpContacts["ar_id"][$select_key];
-        
+
         if (isset($tmpContacts["contact_name"][$select_key]) && testContactExistence($tmpContacts["contact_name"][$select_key])) {
             $tmpConf["contact_name"] = $tmpContacts["contact_name"][$select_key];
             $tmpConf["contact_alias"] = $tmpContacts["contact_alias"][$select_key];
diff --git a/www/include/configuration/configObject/contact/formContact.ihtml b/www/include/configuration/configObject/contact/formContact.ihtml
index 9fc8217149..29f99daae6 100644
--- a/www/include/configuration/configObject/contact/formContact.ihtml
+++ b/www/include/configuration/configObject/contact/formContact.ihtml
@@ -33,7 +33,7 @@
         <tr class="list_two"><td class="FormRowField"><img class="helpTooltip" name="email"> {$form.contact_email.label}</td><td class="FormRowValue">{$form.contact_email.html}</td></tr>
         <tr class="list_one"><td class="FormRowField"><img class="helpTooltip" name="pager"> {$form.contact_pager.label}</td><td class="FormRowValue">{$form.contact_pager.html}</td></tr>
         <tr class="list_two"><td class="FormRowField"><img class="helpTooltip" name="pager"> {$form.contact_template_id.label}</td><td class="FormRowValue">{$form.contact_template_id.html}</td></tr>
-        
+
         <tr class="list_lvl_1">
             <td class="ListColLvl1_name" colspan="2">
                 <h4>{$form.header.groupLinks}</h4>
@@ -118,6 +118,7 @@
         {if $displayAdminFlag == 1}
         <tr class="list_two"><td class="FormRowField"><img class="helpTooltip" name="admin"> {$form.contact_admin.label}</td><td class="FormRowValue">{$form.contact_admin.html}</td></tr>
         <tr class="list_one"><td class="FormRowField"><img class="helpTooltip" name="reach_api"> {$form.reach_api.label}</td><td class="FormRowValue">{$form.reach_api.html}</td></tr>
+        <tr class="list_two"><td class="FormRowField"><img class="helpTooltip" name="reach_api_rt"> {$form.reach_api_rt.label}</td><td class="FormRowValue">{$form.reach_api_rt.html}</td></tr>
         {/if}
         <tr class="list_lvl_1">
             <td class="ListColLvl1_name" colspan="2">
@@ -125,7 +126,7 @@
             </td>
         </tr>
         {if $o == "mc"}
-            <tr class="list_two"><td class="FormRowField"><img class="helpTooltip" name="mc_update"> {$form.mc_mod_acl.label}</td><td class="FormRowValue">{$form.mc_mod_acl.html}</td></tr>
+            <tr class="list_one"><td class="FormRowField"><img class="helpTooltip" name="mc_update"> {$form.mc_mod_acl.label}</td><td class="FormRowValue">{$form.mc_mod_acl.html}</td></tr>
         {/if}
         <tr class="list_one"><td class="FormRowField"><img class="helpTooltip" name="aclgroups"> {$form.contact_acl_groups.label}</td><td class="FormRowValue">{$form.contact_acl_groups.html}</td></tr>
         {if $o == "a" || $o == "c"}
@@ -175,4 +176,4 @@
     </div>
     {$form.hidden}
 </form>
-{$helptext}
\ No newline at end of file
+{$helptext}
diff --git a/www/include/configuration/configObject/contact/formContact.php b/www/include/configuration/configObject/contact/formContact.php
index 3a609b0082..3081b7b5c7 100644
--- a/www/include/configuration/configObject/contact/formContact.php
+++ b/www/include/configuration/configObject/contact/formContact.php
@@ -205,8 +205,8 @@ $aclCond = "";
 if (!$centreon->user->admin) {
     $aclCond = " WHERE acl_group_id IN (" . $acl->getAccessGroupsString() . ") ";
 }
-$sql = "SELECT acl_group_id, acl_group_name 
-    FROM acl_groups 
+$sql = "SELECT acl_group_id, acl_group_name
+    FROM acl_groups
     {$aclCond}
     ORDER BY acl_group_name";
 $DBRESULT = $pearDB->query($sql);
@@ -357,7 +357,12 @@ if ($centreon->user->admin) {
     $tab = array();
     $tab[] = HTML_QuickForm::createElement('radio', 'reach_api', null, _("Yes"), '1');
     $tab[] = HTML_QuickForm::createElement('radio', 'reach_api', null, _("No"), '0');
-    $form->addGroup($tab, 'reach_api', _("Reach API"), '&nbsp;');
+    $form->addGroup($tab, 'reach_api', _("Reach API Configuration"), '&nbsp;');
+
+    $tab = array();
+    $tab[] = HTML_QuickForm::createElement('radio', 'reach_api_rt', null, _("Yes"), '1');
+    $tab[] = HTML_QuickForm::createElement('radio', 'reach_api_rt', null, _("No"), '0');
+    $form->addGroup($tab, 'reach_api_rt', _("Reach API Realtime"), '&nbsp;');
 }
 
 /**
@@ -408,7 +413,12 @@ if ($centreon->optGen['ldap_auth_enable'] == 1) {
     }
 }
 if ($o != "mc") {
-    $form->setDefaults(array('contact_oreon' => '1', "contact_admin" => '0', "reach_api" => '0'));
+    $form->setDefaults(array(
+        'contact_oreon' => '1',
+        'contact_admin' => '0',
+        'reach_api' => '0',
+        'reach_api_rt' => '0'
+    ));
 }
 $form->addElement('select', 'contact_auth_type', _("Authentication Source"), $auth_type);
 
@@ -706,4 +716,4 @@ function uncheckAllS(object)
         document.getElementById('sNone').checked = false;
     }
 }
-</script>
\ No newline at end of file
+</script>
diff --git a/www/include/configuration/configObject/contact/help.php b/www/include/configuration/configObject/contact/help.php
index 2898d5ffaa..cc45a09962 100644
--- a/www/include/configuration/configObject/contact/help.php
+++ b/www/include/configuration/configObject/contact/help.php
@@ -36,7 +36,8 @@ $help["admin"] = dgettext("help", "Specify if the user has administrative permis
 $help["autologin_key"] = dgettext("help", "Token used for autologin. Refer to the Centreon documentation to know more about its usage.");
 $help["auth_type"] = dgettext("help", "Specify the source for user credentials. Choose between Centreon and LDAP, whereas LDAP is only available when configured in Administration Options.");
 $help["location"] = dgettext("help", "Select the timezone, in which the user resides, from the list. The timezones are listed as time difference to Greenwich Mean Time (GMT) in hours.");
-$help["reach_api"] = dgettext("help", "Allow this user to access to Centreon Rest API with its account.");
+$help["reach_api"] = dgettext("help", "Allow this user to access to Centreon Rest API Configuration with its account.");
+$help["reach_api_rt"] = dgettext("help", "Allow this user to access to Centreon Rest API Realtime with its account.");
 
 /*
  * Additional Information
diff --git a/www/install/createTables.sql b/www/install/createTables.sql
index 07c4aed957..a9dcc2dc62 100644
--- a/www/install/createTables.sql
+++ b/www/install/createTables.sql
@@ -749,6 +749,7 @@ CREATE TABLE `contact` (
   `contact_location` int(11) DEFAULT '0',
   `contact_oreon` enum('0','1') DEFAULT NULL,
   `reach_api` int(11) DEFAULT '0',
+  `reach_api_rt` int(1) DEFAULT 0,
   `contact_enable_notifications` enum('0','1','2') DEFAULT '2',
   `contact_template_id` int(11) DEFAULT NULL,
   `contact_admin` enum('0','1') DEFAULT '0',
diff --git a/www/install/sql/centreon/Update-DB-2.8.20_to_2.8.21.sql b/www/install/sql/centreon/Update-DB-2.8.20_to_2.8.21.sql
index dccabf1b4a..01f7e7ff91 100644
--- a/www/install/sql/centreon/Update-DB-2.8.20_to_2.8.21.sql
+++ b/www/install/sql/centreon/Update-DB-2.8.20_to_2.8.21.sql
@@ -1,2 +1,7 @@
 -- Change version of Centreon
 UPDATE `informations` SET `value` = '2.8.21' WHERE CONVERT( `informations`.`key` USING utf8 ) = 'version' AND CONVERT ( `informations`.`value` USING utf8 ) = '2.8.20' LIMIT 1;
+
+-- Temporary fix for limit realtime and configuration Rest API
+ALTER TABLE `contact` ADD COLUMN `reach_api_rt` int(1) DEFAULT 0 AFTER `reach_api`;
+-- Update users with right to reach api
+UPDATE contact SET reach_api_rt = "1" WHERE reach_api = "1";
-- 
GitLab