source: admin/WebConsole/rest/ogagent.php @ ee80b18

Last change on this file since ee80b18 was 3cffc27, checked in by Ramón M. Gómez <ramongomez@…>, 5 years ago

#992: Set local session flag on user login or logout.

  • Property mode set to 100644
File size: 10.7 KB
RevLine 
[b1735a7]1<?php
[8f3c218]2/**
3 * @file    ogagent.php
4 * @brief   OpenGnsys REST routes for OGAgent communications.
5 * @warning All input and output messages are formatted in JSON.
6 * @note    Some ideas are based on article "How to create REST API for Android app using PHP, Slim and MySQL" by Ravi Tamada, thanx.
7 * @license GNU GPLv3+
8 * @author  Ramón M. Gómez, ETSII Univ. Sevilla
9 * @version 1.1.0 - First version
10 * @date    2016-10-03
11 */
[b1735a7]12
13
14// OGAgent sessions log file.
15define('LOG_FILE', '/opt/opengnsys/log/ogagent.log');
16
[8f3c218]17// Function to write a line into log file.
18function writeLog($message = "") {
19        file_put_contents(LOG_FILE, date(DATE_ISO8601).": $message\n", FILE_APPEND);
20}
21
[a9140b0]22/**
23 * @brief    OGAgent notifies that its service is started on a client.
[21e5ee3]24 * @note     Route: /ogagent/started, Method: POST, Format: JSON
[a9140b0]25 * @param    string ip         IP address
26 * @param    string mac        MAC (Ethernet) address
[e7d4fbb7]27 * @param    string ostype     OS type (Linux, Windows, macOS)
[21e5ee3]28 * @param    string osversion  OS version
[a9140b0]29 * @param    string secret     random secret key to access client's REST API
30 * @return   Null string if OK, else error message.
31 */
[b1735a7]32$app->post('/ogagent/started',
33    function() use ($app) {
[2913439]34        global $cmd;
[1985678]35        $secret = "";
[2913439]36        $osType = $osVersion = "none";
[b1735a7]37        try {
38                // Reading POST parameters in JSON format.
39                $input = json_decode($app->request()->getBody());
40                $ip = htmlspecialchars($input->ip);
41                $mac = htmlspecialchars($input->mac);
[31970a0]42                if (isset($input->ostype))  $osType = htmlspecialchars($input->ostype);
43                if (isset($input->osversion))  $osVersion = str_replace(",", ";", htmlspecialchars($input->osversion));
[21e5ee3]44                // Check sender agent type and IP address consistency (same as parameter value).
45                if (empty(preg_match('/^python-requests\//', $_SERVER['HTTP_USER_AGENT'])) or $ip !== $_SERVER['REMOTE_ADDR']) {
46                    throw new Exception("Bad OGAgent: ip=$ip, sender=".$_SERVER['REMOTE_ADDR'].", agent=".$_SERVER['HTTP_USER_AGENT']);
[a9140b0]47                }
[210ee85]48                // Client secret key for secure communications.
49                if (isset($input->secret)) {
[a9140b0]50                    // Check if secret key is valid (32 alphanumeric characters).
51                    if (! ctype_alnum($input->secret) or strlen($input->secret) !== 32) {
52                        throw new Exception("Bad secret key: ip=$ip, mac=$mac, os=$osType:$osVersion.");
53                    }
[210ee85]54                    // Store secret key in DB.
[f6045a5]55                    if (isset($input->secret))  $secret = htmlspecialchars($input->secret);
[8ba8712]56                    $cmd->texto = <<<EOD
57UPDATE ordenadores
58   SET agentkey='$secret'
59 WHERE ip='$ip' AND mac=UPPER(REPLACE('$mac', ':', ''))
60 LIMIT 1;
61EOD;
[55fcaa6]62                    if ($cmd->Ejecutar() !== true or mysqli_affected_rows($cmd->Conexion->controlador) !== 1) {
[a9140b0]63                        // DB access error or not updated.
64                        throw new Exception("Cannot store new secret key: ip=$ip, mac=$mac, os=$osType:$osVersion.");
[2913439]65                    }
[210ee85]66                } else {
67                    // Insecure agent exception.
[31970a0]68                    throw new Exception("Insecure OGAgent started: ip=$ip, mac=$mac, os=$osType:$osVersion.");
[210ee85]69                }
[b1735a7]70                // Default processing: log activity.
[8f3c218]71                writeLog("OGAgent started: ip=$ip, mac=$mac, os=$osType:$osVersion.");
[b1735a7]72                // Response.
[d98bc86]73                $response = "";
[b1735a7]74                jsonResponse(200, $response);
75        } catch (Exception $e) {
[8ba8712]76                // Communication error.
[b1735a7]77                $response["message"] = $e->getMessage();
[8f3c218]78                writeLog($app->request()->getResourceUri().": ERROR: ".$response["message"]);
[b1735a7]79                jsonResponse(400, $response);
80        }
81    }
82);
83
[21e5ee3]84/**
85 * @brief    OGAgent notifies that its service is stopped on client.
86 * @note     Route: /ogagent/stopped, Method: POST, Format: JSON
87 * @param    string ip         IP address
88 * @param    string mac        MAC (Ethernet) address
[e7d4fbb7]89 * @param    string ostype     OS type (Linux, Windows, macOS)
[21e5ee3]90 * @param    string osversion  OS version
91 * @return   Null string if OK, else error message.
92 */
[b1735a7]93$app->post('/ogagent/stopped',
94    function() use ($app) {
[2913439]95        $osType = $osVersion = "none";
[b1735a7]96        try {
97                // Reading POST parameters in JSON format.
98                $input = json_decode($app->request()->getBody());
99                $ip = htmlspecialchars($input->ip);
100                $mac = htmlspecialchars($input->mac);
[31970a0]101                if (isset($input->ostype))  $osType = htmlspecialchars($input->ostype);
102                if (isset($input->osversion))  $osVersion = str_replace(",", ";", htmlspecialchars($input->osversion));
[21e5ee3]103                // Check sender agent type and IP address consistency (same as parameter value).
104                if (empty(preg_match('/^python-requests\//', $_SERVER['HTTP_USER_AGENT'])) or $ip !== $_SERVER['REMOTE_ADDR']) {
105                    throw new Exception("Bad OGAgent: ip=$ip, sender=".$_SERVER['REMOTE_ADDR'].", agent=".$_SERVER['HTTP_USER_AGENT']);
[a9140b0]106                }
107                // May check if client is included in the server database?
[b1735a7]108                // Default processing: log activity.
[8f3c218]109                writeLog("OGAgent stopped: ip=$ip, mac=$mac, os=$osType:$osVersion.");
[b1735a7]110                // Response.
[d98bc86]111                $response = "";
[b1735a7]112                jsonResponse(200, $response);
113        } catch (Exception $e) {
[8ba8712]114                // Communication error.
[b1735a7]115                $response["message"] = $e->getMessage();
[8f3c218]116                writeLog($app->request()->getResourceUri().": ERROR: ".$response["message"]);
[b1735a7]117                jsonResponse(400, $response);
118        }
119    }
120);
121
[21e5ee3]122/**
123 * @brief    OGAgent notifies that an user logs in.
124 * @note     Route: /ogagent/loggedin, Method: POST, Format: JSON
125 * @param    string ip         IP address
126 * @param    string user       username
[e7d4fbb7]127 * @param    string language   session language
128 * @param    string ostype     OS type (Linux, Windows, macOS)
129 * @param    string osversion  OS version
[21e5ee3]130 * @return   Null string if OK, else error message.
131 */
[b1735a7]132$app->post('/ogagent/loggedin',
133    function() use ($app) {
[8f3c218]134        global $cmd;
135        $redirto = Array();
136        $result = Array();
137
[b1735a7]138        try {
139                // Reading POST parameters in JSON format.
140                $input = json_decode($app->request()->getBody());
141                $ip = htmlspecialchars($input->ip);
142                $user = htmlspecialchars($input->user);
[e98bdbc]143                // Remote session contains "rdp", else it's local.
144                if (strpos($input->session ?? "", "rdp") !== false) {
145                        $session = "remote";
146                } else {
147                        $session = "local";
148                }
149                $language = strstr($input->language ?? "", "_", true);
150                $osType = htmlspecialchars($input->ostype ?? "none");
151                $osVersion = str_replace(",", ";", htmlspecialchars($input->osversion ?? "none"));
[a9140b0]152                // Check sender IP address consistency (same as parameter value).
[21e5ee3]153                if (empty(preg_match('/^python-requests\//', $_SERVER['HTTP_USER_AGENT'])) or $ip !== $_SERVER['REMOTE_ADDR']) {
154                    throw new Exception("Bad OGAgent: ip=$ip, sender=".$_SERVER['REMOTE_ADDR'].", agent=".$_SERVER['HTTP_USER_AGENT']);
[a9140b0]155                }
[8f3c218]156                // Check if client is included in the server database.
[8ba8712]157                $cmd->CreaParametro("@ip", $ip, 0);
[8f3c218]158                $cmd->texto = <<<EOD
[9551d71]159SELECT ordenadores.idordenador, ordenadores.nombreordenador, remotepc.urllogin,
[e98bdbc]160       remotepc.urlrelease, remotepc.reserved > NOW() AS reserved
[8f3c218]161  FROM remotepc
162 RIGHT JOIN ordenadores ON remotepc.id=ordenadores.idordenador
[8ba8712]163 WHERE ordenadores.ip=@ip
[8f3c218]164 LIMIT 1;
165EOD;
166                $rs=new Recordset;
167                $rs->Comando=&$cmd;
168                if ($rs->Abrir()) {
169                        // Read query data.
170                        $rs->Primero();
[8ba8712]171                        $id = $rs->campos['idordenador'];
[e98bdbc]172                        $sendlogin[0]['url'] = $rs->campos['urllogin'];
173                        $sendrel[0]['url'] = $rs->campos['urlrelease'];
[8ba8712]174                        $reserved = $rs->campos['reserved'];
[8f3c218]175                        $rs->Cerrar();
[8ba8712]176                        if (!is_null($id)) {
177                                // Log activity, respond to client and continue processing.
[b46042c]178                                writeLog("User logged in: ip=$ip, user=$user, lang=$language, os=$osType:$osVersion.");
[8ba8712]179                                $response = "";
180                                jsonResponseNow(200, $response);
181                        } else {
182                                throw new Exception("Client is not in the database: ip=$ip, user=$user");
183                        }
[3cffc27]184                        // Compose sentence to store if the user session is local or not.
185                        $cmd->texto = "UPDATE remotepc SET islocal = IF('$session' = 'local', 1, 0)";
[8ba8712]186                        // Redirect notification to UDS server, if needed.
[e98bdbc]187                        if ($reserved == 1 and !is_null($sendlogin[0]['url'])) {
188                                $sendlogin[0]['get'] = $app->request()->getBody();
189                                $result = multiRequest($sendlogin);
[b942930]190                                // ... (check response)
191                                //if ($result[0]['code'] != 200) {
192                                // ...
[3cffc27]193                                // Add user's session language to the SQL sentence.
194                                $cmd->texto .= ", language = '$language";
[8f3c218]195                        }
[e98bdbc]196                        // Release a reserved client if a user opens a local session.
197                        if ($reserved == 1 and $session === "local" and ! is_null($sendrel[0]['url'])) {
198                                $result = multiRequest($sendrel);
199                        }
[3cffc27]200                        // Update the database.
201                        $cmd->texto .= " WHERE id = '$id';";
202                        $cmd->Ejecutar();
[8ba8712]203                } else {
204                        throw new Exception("Database error");
[8f3c218]205                }
[b1735a7]206        } catch (Exception $e) {
[8ba8712]207                // Communication error.
[b1735a7]208                $response["message"] = $e->getMessage();
[8f3c218]209                writeLog($app->request()->getResourceUri().": ERROR: ".$response["message"]);
[b1735a7]210                jsonResponse(400, $response);
211        }
212    }
213);
214
[21e5ee3]215/**
216 * @brief    OGAgent notifies that an user logs out.
217 * @note     Route: /ogagent/loggedout, Method: POST, Format: JSON
218 * @param    string ip         IP address
219 * @param    string user       username
220 * @return   Null string if OK, else error message.
221 */
[b1735a7]222$app->post('/ogagent/loggedout',
223    function() use ($app) {
[b942930]224        global $cmd;
225        $redirto = Array();
226        $result = Array();
227
[b1735a7]228        try {
229                // Reading POST parameters in JSON format.
230                $input = json_decode($app->request()->getBody());
231                $ip = htmlspecialchars($input->ip);
232                $user = htmlspecialchars($input->user);
[21e5ee3]233                // Check sender agent type and IP address consistency (same as parameter value).
234                if (empty(preg_match('/^python-requests\//', $_SERVER['HTTP_USER_AGENT'])) or $ip !== $_SERVER['REMOTE_ADDR']) {
235                    throw new Exception("Bad OGAgent: ip=$ip, sender=".$_SERVER['REMOTE_ADDR'].", agent=".$_SERVER['HTTP_USER_AGENT']);
[a9140b0]236                }
[b942930]237                // Check if client is included in the server database.
[8ba8712]238                $cmd->CreaParametro("@ip", $ip, 0);
[b942930]239                $cmd->texto = <<<EOD
[17c28dc]240SELECT ordenadores.idordenador, ordenadores.nombreordenador, remotepc.urllogout,
[8ba8712]241       remotepc.reserved > NOW() AS reserved
[b942930]242  FROM remotepc
243 RIGHT JOIN ordenadores ON remotepc.id=ordenadores.idordenador
[8ba8712]244 WHERE ordenadores.ip=@ip
[b942930]245 LIMIT 1;
246EOD;
247                $rs=new Recordset;
248                $rs->Comando=&$cmd;
249                if ($rs->Abrir()) {
250                        // Read query data.
251                        $rs->Primero();
[8ba8712]252                        $id = $rs->campos['idordenador'];
[31eaff2]253                        $url = $rs->campos['urllogout'];
[8ba8712]254                        $reserved = $rs->campos['reserved'];
[b942930]255                        $rs->Cerrar();
[8ba8712]256                        if (!is_null($id)) {
257                                // Log activity, respond to client and continue processing.
[4d06fd4b]258                                writeLog("User logged out: ip=$ip, user=$user.");
[8ba8712]259                        } else {
260                                throw new Exception("Client is not in the database: ip=$ip, user=$user");
261                        }
262                        // Redirect notification to UDS server, if needed.
[31eaff2]263                        if ($reserved == 1 and !is_null($url)) {
264                                $redirto[0]['url'] = $url;
[030ee20]265                                $redirto[0]['get'] = $app->request()->getBody();
[b942930]266                                $result = multiRequest($redirto);
267                                // ... (check response)
268                                //if ($result[0]['code'] != 200) {
269                                // ...
270                        }
[3cffc27]271                        // Disable local session flag.
272                        $cmd->texto = "UPDATE remotepc SET islocal = 0 WHERE id = '$id';";
273                        $cmd->Ejecutar();
[8ba8712]274                } else {
275                        throw new Exception("Database error");
[b942930]276                }
[b1735a7]277        } catch (Exception $e) {
[8ba8712]278                // Communication error.
[b1735a7]279                $response["message"] = $e->getMessage();
[8f3c218]280                writeLog($app->request()->getResourceUri().": ERROR: ".$response["message"]);
[b1735a7]281                jsonResponse(400, $response);
282        }
[31eaff2]283        $response = "";
284        jsonResponse(200, $response);
[b1735a7]285    }
286);
287
[b6ec162]288
Note: See TracBrowser for help on using the repository browser.