source: admin/WebConsole/rest/ogagent.php

lgromero-new-oglive
Last change on this file was 31eaff2, checked in by Ramón M. Gómez <ramongomez@…>, 6 years ago

#839: Avoid error code 500 when redirecting a logout operation to the remote access server (UDS).

  • Property mode set to 100644
File size: 10.1 KB
Line 
1<?php
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 */
12
13
14// OGAgent sessions log file.
15define('LOG_FILE', '/opt/opengnsys/log/ogagent.log');
16
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
22/**
23 * @brief    OGAgent notifies that its service is started on a client.
24 * @note     Route: /ogagent/started, Method: POST, Format: JSON
25 * @param    string ip         IP address
26 * @param    string mac        MAC (Ethernet) address
27 * @param    string ostype     OS type (Linux, Windows, macOS)
28 * @param    string osversion  OS version
29 * @param    string secret     random secret key to access client's REST API
30 * @return   Null string if OK, else error message.
31 */
32$app->post('/ogagent/started',
33    function() use ($app) {
34        global $cmd;
35        $secret = "";
36        $osType = $osVersion = "none";
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);
42                if (isset($input->ostype))  $osType = htmlspecialchars($input->ostype);
43                if (isset($input->osversion))  $osVersion = str_replace(",", ";", htmlspecialchars($input->osversion));
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']);
47                }
48                // Client secret key for secure communications.
49                if (isset($input->secret)) {
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                    }
54                    // Store secret key in DB.
55                    if (isset($input->secret))  $secret = htmlspecialchars($input->secret);
56                    $cmd->texto = <<<EOD
57UPDATE ordenadores
58   SET agentkey='$secret'
59 WHERE ip='$ip' AND mac=UPPER(REPLACE('$mac', ':', ''))
60 LIMIT 1;
61EOD;
62                    if ($cmd->Ejecutar() !== true or mysqli_affected_rows($cmd->Conexion->controlador) !== 1) {
63                        // DB access error or not updated.
64                        throw new Exception("Cannot store new secret key: ip=$ip, mac=$mac, os=$osType:$osVersion.");
65                    }
66                } else {
67                    // Insecure agent exception.
68                    throw new Exception("Insecure OGAgent started: ip=$ip, mac=$mac, os=$osType:$osVersion.");
69                }
70                // Default processing: log activity.
71                writeLog("OGAgent started: ip=$ip, mac=$mac, os=$osType:$osVersion.");
72                // Response.
73                $response = "";
74                jsonResponse(200, $response);
75        } catch (Exception $e) {
76                // Communication error.
77                $response["message"] = $e->getMessage();
78                writeLog($app->request()->getResourceUri().": ERROR: ".$response["message"]);
79                jsonResponse(400, $response);
80        }
81    }
82);
83
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
89 * @param    string ostype     OS type (Linux, Windows, macOS)
90 * @param    string osversion  OS version
91 * @return   Null string if OK, else error message.
92 */
93$app->post('/ogagent/stopped',
94    function() use ($app) {
95        $osType = $osVersion = "none";
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);
101                if (isset($input->ostype))  $osType = htmlspecialchars($input->ostype);
102                if (isset($input->osversion))  $osVersion = str_replace(",", ";", htmlspecialchars($input->osversion));
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']);
106                }
107                // May check if client is included in the server database?
108                // Default processing: log activity.
109                writeLog("OGAgent stopped: ip=$ip, mac=$mac, os=$osType:$osVersion.");
110                // Response.
111                $response = "";
112                jsonResponse(200, $response);
113        } catch (Exception $e) {
114                // Communication error.
115                $response["message"] = $e->getMessage();
116                writeLog($app->request()->getResourceUri().": ERROR: ".$response["message"]);
117                jsonResponse(400, $response);
118        }
119    }
120);
121
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
127 * @param    string language   session language
128 * @param    string ostype     OS type (Linux, Windows, macOS)
129 * @param    string osversion  OS version
130 * @return   Null string if OK, else error message.
131 */
132$app->post('/ogagent/loggedin',
133    function() use ($app) {
134        global $cmd;
135        $osType = $osVersion = "none";
136        $redirto = Array();
137        $result = Array();
138
139        try {
140                // Reading POST parameters in JSON format.
141                $input = json_decode($app->request()->getBody());
142                $ip = htmlspecialchars($input->ip);
143                $user = htmlspecialchars($input->user);
144                $language = isset($input->language) ? substr($input->language, 0, strpos($input->language, "_")) : "";
145                if (isset($input->ostype))  $osType = htmlspecialchars($input->ostype);
146                if (isset($input->osversion))  $osVersion = str_replace(",", ";", htmlspecialchars($input->osversion));
147                // Check sender IP address consistency (same as parameter value).
148                if (empty(preg_match('/^python-requests\//', $_SERVER['HTTP_USER_AGENT'])) or $ip !== $_SERVER['REMOTE_ADDR']) {
149                    throw new Exception("Bad OGAgent: ip=$ip, sender=".$_SERVER['REMOTE_ADDR'].", agent=".$_SERVER['HTTP_USER_AGENT']);
150                }
151                // Check if client is included in the server database.
152                $cmd->CreaParametro("@ip", $ip, 0);
153                $cmd->texto = <<<EOD
154SELECT ordenadores.idordenador, ordenadores.nombreordenador, remotepc.urllogin,
155       remotepc.reserved > NOW() AS reserved
156  FROM remotepc
157 RIGHT JOIN ordenadores ON remotepc.id=ordenadores.idordenador
158 WHERE ordenadores.ip=@ip
159 LIMIT 1;
160EOD;
161                $rs=new Recordset;
162                $rs->Comando=&$cmd;
163                if ($rs->Abrir()) {
164                        // Read query data.
165                        $rs->Primero();
166                        $id = $rs->campos['idordenador'];
167                        $redirto[0]['url'] = $rs->campos['urllogin'];
168                        $reserved = $rs->campos['reserved'];
169                        $rs->Cerrar();
170                        if (!is_null($id)) {
171                                // Log activity, respond to client and continue processing.
172                                writeLog("User logged in: ip=$ip, user=$user, lang=$language, os=$osType:$osVersion.");
173                                $response = "";
174                                jsonResponseNow(200, $response);
175                        } else {
176                                throw new Exception("Client is not in the database: ip=$ip, user=$user");
177                        }
178                        // Redirect notification to UDS server, if needed.
179                        if ($reserved == 1 and !is_null($redirto[0]['url'])) {
180                                $redirto[0]['get'] = $app->request()->getBody();
181                                $result = multiRequest($redirto);
182                                // ... (check response)
183                                //if ($result[0]['code'] != 200) {
184                                // ...
185                                // Updating user's session language for messages.
186                                $cmd->texto = <<<EOD
187UPDATE remotepc
188   SET language = '$language'
189 WHERE id = '$id';
190EOD;
191                                $cmd->Ejecutar();
192                        }
193                } else {
194                        throw new Exception("Database error");
195                }
196        } catch (Exception $e) {
197                // Communication error.
198                $response["message"] = $e->getMessage();
199                writeLog($app->request()->getResourceUri().": ERROR: ".$response["message"]);
200                jsonResponse(400, $response);
201        }
202    }
203);
204
205/**
206 * @brief    OGAgent notifies that an user logs out.
207 * @note     Route: /ogagent/loggedout, Method: POST, Format: JSON
208 * @param    string ip         IP address
209 * @param    string user       username
210 * @return   Null string if OK, else error message.
211 */
212$app->post('/ogagent/loggedout',
213    function() use ($app) {
214        global $cmd;
215        $redirto = Array();
216        $result = Array();
217
218        try {
219                // Reading POST parameters in JSON format.
220                $input = json_decode($app->request()->getBody());
221                $ip = htmlspecialchars($input->ip);
222                $user = htmlspecialchars($input->user);
223                // Check sender agent type and IP address consistency (same as parameter value).
224                if (empty(preg_match('/^python-requests\//', $_SERVER['HTTP_USER_AGENT'])) or $ip !== $_SERVER['REMOTE_ADDR']) {
225                    throw new Exception("Bad OGAgent: ip=$ip, sender=".$_SERVER['REMOTE_ADDR'].", agent=".$_SERVER['HTTP_USER_AGENT']);
226                }
227                // Check if client is included in the server database.
228                $cmd->CreaParametro("@ip", $ip, 0);
229                $cmd->texto = <<<EOD
230SELECT ordenadores.idordenador, ordenadores.nombreordenador, remotepc.urllogout,
231       remotepc.reserved > NOW() AS reserved
232  FROM remotepc
233 RIGHT JOIN ordenadores ON remotepc.id=ordenadores.idordenador
234 WHERE ordenadores.ip=@ip
235 LIMIT 1;
236EOD;
237                $rs=new Recordset;
238                $rs->Comando=&$cmd;
239                if ($rs->Abrir()) {
240                        // Read query data.
241                        $rs->Primero();
242                        $id = $rs->campos['idordenador'];
243                        $url = $rs->campos['urllogout'];
244                        $reserved = $rs->campos['reserved'];
245                        $rs->Cerrar();
246                        if (!is_null($id)) {
247                                // Log activity, respond to client and continue processing.
248                                writeLog("User logged out: ip=$ip, user=$user.");
249                        } else {
250                                throw new Exception("Client is not in the database: ip=$ip, user=$user");
251                        }
252                        // Redirect notification to UDS server, if needed.
253                        if ($reserved == 1 and !is_null($url)) {
254                                $redirto[0]['url'] = $url;
255                                $redirto[0]['get'] = $app->request()->getBody();
256                                $result = multiRequest($redirto);
257                                // ... (check response)
258                                //if ($result[0]['code'] != 200) {
259                                // ...
260                        }
261                } else {
262                        throw new Exception("Database error");
263                }
264        } catch (Exception $e) {
265                // Communication error.
266                $response["message"] = $e->getMessage();
267                writeLog($app->request()->getResourceUri().": ERROR: ".$response["message"]);
268                jsonResponse(400, $response);
269        }
270        $response = "";
271        jsonResponse(200, $response);
272    }
273);
274
275
Note: See TracBrowser for help on using the repository browser.