WSProxy ACL check

This commit is contained in:
fbsanchez 2019-10-18 18:55:29 +02:00
parent e24024d2f4
commit 1cf77cc8f1
6 changed files with 175 additions and 42 deletions

View File

@ -44,8 +44,11 @@ namespace PandoraFMS\WebSockets;
use \PandoraFMS\Websockets\WebSocketServer;
use \PandoraFMS\Websockets\WebSocketUser;
use \PandoraFMS\User;
require_once __DIR__.'/../functions.php';
/**
* Redirects ws communication between two endpoints.
*/
@ -86,14 +89,14 @@ class WSProxy extends WebSocketServer
*
* @var boolean
*/
protected $interative = false;
protected $interative = true;
/**
* Use a timeout of 0.1 second to search for messages..
* Use a timeout of 100 milliseconds to search for messages..
*
* @var integer
*/
public $timeout = 0.1;
public $timeout = 250;
/**
@ -120,7 +123,7 @@ class WSProxy extends WebSocketServer
$this->intPort = $to_port;
$this->intUrl = $to_url;
$this->maxBufferSize = $bufferLength;
$this->interactive = $debug;
$this->debug = $debug;
$this->userClass = '\\PandoraFMS\\Websockets\\WebSocketUser';
parent::__construct($listen_addr, $listen_port, $bufferLength);
}
@ -239,6 +242,36 @@ class WSProxy extends WebSocketServer
*/
protected function connected($user)
{
global $config;
$php_session_id = \str_replace(
'PHPSESSID=',
'',
$user->headers['cookie']
);
$user->account = new User(['phpsessionid' => $php_session_id]);
$_SERVER['REMOTE_ADDR'] = $user->address;
// Ensure user is allowed to connect.
if (\check_login(false) === false) {
$this->disconnect($user->socket);
\db_pandora_audit(
'WebSockets engine',
'Trying to access websockets engine without a valid session',
'N/A'
);
return;
}
// User exists, and session is valid.
\db_pandora_audit(
'WebSockets engine',
'WebSocket connection started',
$user->account->idUser
);
$this->stderr('ONLINE '.$user->address.'('.$user->account->idUser.')');
// Disconnect previous sessions.
$this->cleanupSocketByCookie($user);
@ -250,7 +283,7 @@ class WSProxy extends WebSocketServer
// Create a new socket connection (internal).
$intUser = $this->connectInt($this->rawHeaders);
if ($intUser === null) {
$this->disconnect($user);
$this->disconnect($user->socket);
return;
}
@ -293,8 +326,13 @@ class WSProxy extends WebSocketServer
*/
protected function processRaw($user, $buffer)
{
$this->stdout(date('D M j G:i:s').' - '.$user->id.' >> '.$user->redirect->id);
$this->stdout($this->dump($buffer));
if (!isset($user->redirect)) {
$this->disconnect($user->socket);
return false;
}
$this->stderr($user->id.' >> '.$user->redirect->id);
$this->stderr($this->dump($buffer));
$this->writeSocket($user->redirect, $buffer);
return true;
@ -304,14 +342,18 @@ class WSProxy extends WebSocketServer
/**
* Process user message. Implement.
*
* @param object $user User.
* @param string $message Message.
* @param object $user User.
* @param string $message Message.
* @param boolean $str_message String message or not.
*
* @return void
*/
protected function process($user, $message)
protected function process($user, $message, $str_message)
{
if ($str_message === true) {
$remmitent = $user->address.'('.$user->account->idUser.')';
$this->stderr($remmitent.': '.$message);
}
}
@ -324,8 +366,22 @@ class WSProxy extends WebSocketServer
*/
protected function closed($user)
{
$this->disconnect($user);
$this->disconnect($user->redirect);
if ($user->account) {
$_SERVER['REMOTE_ADDR'] = $user->address;
\db_pandora_audit(
'WebSockets engine',
'WebSocket connection finished',
$user->account->idUser
);
$this->stderr('OFFLINE '.$user->address.'('.$user->account->idUser.')');
}
// Ensure both sockets are disconnected.
$this->disconnect($user->socket);
if ($user->redirect) {
$this->disconnect($user->redirect->socket);
}
}

View File

@ -116,12 +116,19 @@ abstract class WebSocketServer
protected $heldMessages = [];
/**
* Undocumented variable
* Show output.
*
* @var array
* @var boolean
*/
protected $interactive = true;
/**
* Debug.
*
* @var boolean
*/
protected $debug = false;
/**
* Undocumented variable
*
@ -195,8 +202,8 @@ abstract class WebSocketServer
$__tmp || die('Failed: socket_listen()');
$this->sockets['m'] = $this->master;
$this->stdout("Server started\nListening on: ".$addr.':'.$port."\n");
$this->stdout('Master socket: '.$this->master."\n");
$this->stderr('Listening on: '.$addr.':'.$port);
$this->stderr('Master socket: '.$this->master."\n");
}
@ -204,12 +211,13 @@ abstract class WebSocketServer
/**
* Process user message. Implement.
*
* @param object $user User.
* @param string $message Message.
* @param object $user User.
* @param string $message Message.
* @param boolean $str_message String message or not.
*
* @return void
*/
abstract protected function process($user, $message);
abstract protected function process($user, $message, $str_message);
/**
@ -414,7 +422,7 @@ abstract class WebSocketServer
$write = null;
$this->pTick();
$this->tick();
socket_select($read, $write, $except, $this->timeout);
socket_select($read, $write, $except, 0, $this->timeout);
foreach ($read as $socket) {
if ($socket == $this->master) {
// External to master connection. New client.
@ -424,9 +432,14 @@ abstract class WebSocketServer
continue;
} else {
$this->connect($client);
$this->stdout('Client connected. '.$client);
$this->stderr('Client connected. '.$client);
}
} else {
if (!$socket) {
$this->disconnect($socket);
continue;
}
// Updates on 'read' socket.
$numBytes = socket_recv(
$socket,
@ -454,7 +467,7 @@ abstract class WebSocketServer
$this->doHandshake($user, $buffer);
} else {
if (!$this->processRaw($user, $buffer)) {
if ($this->processRaw($user, $buffer)) {
// Split packet into frame and send it to deframe.
$this->splitPacket(
$numBytes,
@ -470,7 +483,7 @@ abstract class WebSocketServer
// Remote updates.
$remotes = $this->remoteSockets;
if (count($remotes) > 0) {
socket_select($remotes, $write, $except, $this->timeout);
socket_select($remotes, $write, $except, 0, $this->timeout);
foreach ($remotes as $socket) {
// Remote updates - internal. We're client of this sockets.
if (!$socket) {
@ -492,8 +505,6 @@ abstract class WebSocketServer
);
} else {
$user = $this->getUserBySocket($socket);
echo '>>>>> EEH, recibo:['.$user->id."]\n";
echo $this->dump($buffer);
if (!$user) {
$this->disconnect($socket);
$this->stderr(
@ -571,7 +582,7 @@ abstract class WebSocketServer
if ($triggerClosed) {
$this->closed($user);
$this->stdout(
$this->stderr(
'Client disconnected. '.$user->socket
);
socket_close($user->socket);
@ -912,8 +923,10 @@ abstract class WebSocketServer
*/
public function stderr($message=null)
{
if ($this->interactive) {
echo $message."\n";
if ($this->interactive === true
&& $this->debug === true
) {
echo date('D M j G:i:s').' - '.$message."\n";
}
}
@ -1064,18 +1077,17 @@ abstract class WebSocketServer
if ($user->hasSentClose) {
$this->disconnect($user->socket);
} else {
$str_message = false;
if ((preg_match('//u', $message))
|| ($headers['opcode'] == 2)
) {
/*
* Debug purposes.
* $this->stdout("Text msg encoded UTF-8 or Binary msg\n".$message);
*/
$this->process($user, $message);
$str_message = true;
} else {
$this->stderr("not UTF-8\n");
$str_message = false;
}
$this->process($user, $message, $str_message);
}
}
@ -1152,7 +1164,7 @@ abstract class WebSocketServer
default:
/*
* TODO: fail connection.
* $this->disconnect($user);
* $this->disconnect($user->socket);
*/
$willClose = true;
@ -1371,7 +1383,7 @@ abstract class WebSocketServer
if ($len > 0) {
/*
* TODO: fail connection.
* $this->disconnect($user);
* $this->disconnect($user->socket);
*/
return true;

View File

@ -129,6 +129,20 @@ class WebSocketUser
*/
public $redirect;
/**
* Pandora FMS user account.
*
* @var User
*/
public $account;
/**
* Remote address.
*
* @var string
*/
public $address;
/**
* Initializes a websocket user.
@ -138,6 +152,7 @@ class WebSocketUser
*/
public function __construct($id, $socket)
{
socket_getpeername($socket, $this->address);
$this->id = $id;
$this->socket = $socket;
}

View File

@ -307,6 +307,7 @@ return array(
'Mpdf\\Utils\\NumericString' => $vendorDir . '/mpdf/mpdf/src/Utils/NumericString.php',
'Mpdf\\Utils\\PdfDate' => $vendorDir . '/mpdf/mpdf/src/Utils/PdfDate.php',
'Mpdf\\Utils\\UtfString' => $vendorDir . '/mpdf/mpdf/src/Utils/UtfString.php',
'PandoraFMS\\User' => $baseDir . '/include/lib/User.php',
'PandoraFMS\\WebSockets\\WSProxy' => $baseDir . '/include/lib/WSProxy.php',
'PandoraFMS\\WebSockets\\WSProxyUser' => $baseDir . '/include/lib/WSProxyUser.php',
'PandoraFMS\\Websockets\\WebSocketServer' => $baseDir . '/include/lib/WebSocketServer.php',

View File

@ -389,6 +389,7 @@ class ComposerStaticInitfdecadadce22e6dde51e9535fe4ad7aa
'Mpdf\\Utils\\NumericString' => __DIR__ . '/..' . '/mpdf/mpdf/src/Utils/NumericString.php',
'Mpdf\\Utils\\PdfDate' => __DIR__ . '/..' . '/mpdf/mpdf/src/Utils/PdfDate.php',
'Mpdf\\Utils\\UtfString' => __DIR__ . '/..' . '/mpdf/mpdf/src/Utils/UtfString.php',
'PandoraFMS\\User' => __DIR__ . '/../..' . '/include/lib/User.php',
'PandoraFMS\\WebSockets\\WSProxy' => __DIR__ . '/../..' . '/include/lib/WSProxy.php',
'PandoraFMS\\WebSockets\\WSProxyUser' => __DIR__ . '/../..' . '/include/lib/WSProxyUser.php',
'PandoraFMS\\Websockets\\WebSocketServer' => __DIR__ . '/../..' . '/include/lib/WebSocketServer.php',

View File

@ -1,4 +1,3 @@
#!/usr/bin/env php
<?php
/**
* PHP script to manage Pandora FMS websockets.
@ -31,16 +30,66 @@
require_once __DIR__.'/vendor/autoload.php';
use \PandoraFMS\WebSockets\WSProxy;
ini_set('display_errors', 1);
error_reporting(E_ALL);
// Set to true to get full output.
$debug = false;
// 1MB.
$bufferSize = 1048576;
if (file_exists(__DIR__.'/include/config.php') === false
|| is_readable(__DIR__.'/include/config.php') === false
) {
echo "Main console configuration file not found.\n";
exit;
}
// Simulate.
$_SERVER['DOCUMENT_ROOT'] = __DIR__.'/../';
// Don't start a session before this import.
// The session is configured and started inside the config process.
require_once 'include/config.php';
require_once 'include/functions.php';
require_once 'include/functions_db.php';
require_once 'include/auth/mysql.php';
// Enterprise support.
if (file_exists(ENTERPRISE_DIR.'/load_enterprise.php') === true) {
include_once ENTERPRISE_DIR.'/load_enterprise.php';
}
// Avoid direct access through browsers.
if (isset($_SERVER['REMOTE_ADDR']) === true) {
// Force redirection.
header('Location: '.ui_get_full_url('index.php'));
exit;
}
if (isset($config['ws_port']) === false) {
config_update_value('ws_port', 8081);
}
if (isset($config['gotty']) === false) {
config_update_value('gotty', '/usr/bin/gotty');
}
ini_set('display_errors', 1);
error_reporting(E_ALL);
$os = strtolower(PHP_OS);
if (substr($os, 0, 3) !== 'win') {
// Launch gotty.
$cmd = 'nohup "'.$config['gotty'].'" -a 127.0.0.1 -w /bin/bash';
$cmd .= ' >> '.__DIR__.'/pandora_console.log 2>&1 &';
shell_exec($cmd);
}
// Start Web SocketProxy.
$wsproxy = new WSProxy(
'0.0.0.0',
'8081',
$config['ws_port'],
'127.0.0.1',
'8080',
'/ws',
@ -49,7 +98,6 @@ $wsproxy = new WSProxy(
);
try {
echo "Server running \n";
$wsproxy->run();
} catch (Exception $e) {
$wsproxy->stdout($e->getMessage());