Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Client/Auth/WebsocketAuthenticationProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@ protected function getToken(ConnectionInterface $connection)
}

if (null === $token) {
$token = new AnonymousToken($this->firewalls[0], 'anon-' . $connection->WAMP->sessionId);
if (!$this->tokenStorage->getToken()) {
$token = new AnonymousToken($this->firewalls[0], 'anon-' . $connection->WAMP->sessionId);
} else {
$token = $this->tokenStorage->getToken();
}
}

if ($this->tokenStorage->getToken() !== $token) {
Expand Down
5 changes: 5 additions & 0 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ public function getConfigTreeBuilder()
->end()
->end()
->end()
->arrayNode('handshake_middleware')
->prototype('scalar')
->example('@some_service # have to extends Gos\Bundle\WebSocketBundle\Server\App\Stack\HandshakeMiddlewareAbstract')
->end()
->end()
->end()
->end()
->arrayNode('rpc')
Expand Down
10 changes: 10 additions & 0 deletions DependencyInjection/GosWebSocketExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ public function load(array $configs, ContainerBuilder $container)
}
}

if (!empty($configs['server']['handshake_middleware'])) {
$HandshakeMiddlewareRegistryDef = $container->getDefinition('gos_web_socket.handshake_middleware.registry');

foreach ($configs['server']['handshake_middleware'] as $middleware) {
$HandshakeMiddlewareRegistryDef->addMethodCall('addMiddleware', [new Reference(ltrim($middleware, '@'))]);
}
}



$container->setParameter('web_socket_server.client_storage.ttl', $configs['client']['storage']['ttl']);
$container->setParameter('web_socket_server.client_storage.prefix', $configs['client']['storage']['prefix']);

Expand Down
9 changes: 4 additions & 5 deletions Event/ClientEventListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Gos\Bundle\WebSocketBundle\Event;

use Gos\Bundle\WebSocketBundle\Client\Auth\WebsocketAuthenticationProvider;
use Gos\Bundle\WebSocketBundle\Client\Auth\WebsocketAuthenticationProviderInterface;
use Gos\Bundle\WebSocketBundle\Client\ClientStorageInterface;
use Gos\Bundle\WebSocketBundle\Client\Exception\ClientNotFoundException;
use Psr\Log\LoggerInterface;
Expand Down Expand Up @@ -31,12 +32,12 @@ class ClientEventListener

/**
* @param ClientStorageInterface $clientStorage
* @param WebsocketAuthenticationProvider $authenticationProvider
* @param WebsocketAuthenticationProviderInterface $authenticationProvider
* @param LoggerInterface|null $logger
*/
public function __construct(
ClientStorageInterface $clientStorage,
WebsocketAuthenticationProvider $authenticationProvider,
WebsocketAuthenticationProviderInterface $authenticationProvider,
LoggerInterface $logger = null
) {
$this->clientStorage = $clientStorage;
Expand Down Expand Up @@ -124,8 +125,6 @@ public function onClientError(ClientErrorEvent $event)
*/
public function onClientRejected(ClientRejectedEvent $event)
{
$this->logger->warning('Client rejected, bad origin', [
'origin' => $event->getOrigin(),
]);
$this->logger->warning('Client rejected, ' . $event->getMsg());
}
}
12 changes: 6 additions & 6 deletions Event/ClientRejectedEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,29 @@ class ClientRejectedEvent extends Event
/**
* @var string
*/
protected $origin;
protected $msg;

/**
* @var RequestInterface
*/
protected $request;

/**
* @param string $origin
* @param string $msg
* @param RequestInterface $request
*/
public function __construct($origin, RequestInterface $request = null)
public function __construct($msg, RequestInterface $request = null)
{
$this->origin = $origin;
$this->msg = $msg;
$this->request = $request;
}

/**
* @return string
*/
public function getOrigin()
public function getMsg()
{
return $this->origin;
return $this->msg;
}

/**
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Resources
* [Performance Bench](Resources/docs/Performance.md)
* [Push integration](Resources/docs/Pusher.md)
* [SSL configuration](Resources/docs/Ssl.md)
* [Handshake Middleware For Server](Resources/docs/HandshakeMiddleware.md)

Code Cookbook
--------------
Expand Down
4 changes: 4 additions & 0 deletions Resources/config/services/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ services:
- '%web_socket_origin_check%'
- '@gos_web_socket.wamp.topic_manager'
- '@gos_web_socket.server_push_handler.registry'
- '@gos_web_socket.handshake_middleware.registry'
- '@?monolog.logger.websocket'
tags:
- { name: gos_web_socket.server }
Expand Down Expand Up @@ -85,6 +86,9 @@ services:
gos_web_socket.origins.registry:
class: Gos\Bundle\WebSocketBundle\Server\App\Registry\OriginRegistry

gos_web_socket.handshake_middleware.registry:
class: Gos\Bundle\WebSocketBundle\Server\App\Registry\HandshakeMiddlewareRegistry

gos_web_socket_server.wamp_application:
class: Gos\Bundle\WebSocketBundle\Server\App\WampApplication
public: false
Expand Down
3 changes: 3 additions & 0 deletions Resources/docs/ConfigurationReference.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ gos_web_socket:
- @AcmeBundle/Resources/config/pubsub/routing.yml
context:
tokenSeparator: "/"
handshake_middleware: []
# - @some_service

rpc: []
topics: []
periodic: []
Expand Down
4 changes: 2 additions & 2 deletions Resources/docs/Events.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ class AcmeClientEventListener
*/
public function onClientRejected(ClientRejectedEvent $event)
{
$origin = $event->getOrigin;
$msg = $event->getMsg();

echo 'connection rejected from '. $origin . PHP_EOL;
echo $msg . PHP_EOL;
}
}
```
Expand Down
126 changes: 126 additions & 0 deletions Resources/docs/HandshakeMiddleware.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# HandshakeMiddleware

You can add any middleware as service to server with your business logic


**Bundle Configuration**

```yaml
# Gos Web Socket Bundle
gos_web_socket:
server:
handshake_middleware:
- @some_service # have to extends Gos\Bundle\WebSocketBundle\Server\App\Stack\HandshakeMiddlewareAbstract
```



### Handshake middleware example for OAuth

```php
<?php

namespace WebSocketBundle\Service\Middleware;

use Gos\Bundle\WebSocketBundle\Event\ClientRejectedEvent;
use Gos\Bundle\WebSocketBundle\Event\Events;
use Gos\Bundle\WebSocketBundle\Server\App\Stack\HandshakeMiddlewareAbstract;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\Response;
use OAuth2\OAuth2;
use OAuth2\OAuth2AuthenticateException;
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;


class OAuthMiddleware extends HandshakeMiddlewareAbstract
{
/**
* @var OAuth2
*/
protected $oAuthService;

/**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;

/**
* @var array
*/
protected $firewalls;

/**
* @var SecurityContextInterface|TokenStorageInterface
*/
protected $tokenStorage;

/**
* OAuthMiddleware constructor.
* @param EventDispatcherInterface $eventDispatcher
* @param OAuth2 $oAuthService
* @param array $firewalls
*/
public function __construct(
EventDispatcherInterface $eventDispatcher,
OAuth2 $oAuthService,
$firewalls = array(),
$tokenStorage
)
{
$this->oAuthService = $oAuthService;
$this->eventDispatcher = $eventDispatcher;
$this->firewalls = $firewalls;
$this->tokenStorage = $tokenStorage;
}

/**
* @param ConnectionInterface $conn
* @param RequestInterface|null $request
*
* @return void
*/
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null)
{
try {
$accessToken = $this->oAuthService->verifyAccessToken($request->getQuery()->get('access_token'));
} catch (OAuth2AuthenticateException $e) {
$this->eventDispatcher->dispatch(
Events::CLIENT_REJECTED,
new ClientRejectedEvent($e->getMessage(), $request)
);

$this->close($conn, 403);
return ;
}

$user = $accessToken->getUser();
$token = new AnonymousToken(
$request->getQuery()->get('access_token'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if the request object is null? and what if the access token is given in header?

$user,
$user->getRoles()
);
$this->tokenStorage->setToken($token);

return $this->_component->onOpen($conn, $request);
}

/**
* Close a connection with an HTTP response.
*
* @param \Ratchet\ConnectionInterface $conn
* @param int $code HTTP status code
*/
protected function close(ConnectionInterface $conn, $code = 400)
{
$response = new Response($code, [
'X-Powered-By' => \Ratchet\VERSION,
]);

$conn->send((string)$response);
$conn->close();
}
}
```
37 changes: 37 additions & 0 deletions Server/App/Registry/HandshakeMiddlewareRegistry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Gos\Bundle\WebSocketBundle\Server\App\Registry;

use Gos\Bundle\WebSocketBundle\Server\App\Stack\HandshakeMiddlewareAbstract;

/**
* @author Tkachew <[email protected]>
*/
class HandshakeMiddlewareRegistry
{
/**
* @var HandshakeMiddlewareAbstract[]
*/
protected $middlewares;

public function __construct()
{
$this->middlewares = [];
}

/**
* @param HandshakeMiddlewareAbstract $middleware
*/
public function addMiddleware(HandshakeMiddlewareAbstract $middleware)
{
$this->middlewares[] = $middleware;
}

/**
* @return HandshakeMiddlewareAbstract[]
*/
public function getMiddlewares()
{
return $this->middlewares;
}
}
73 changes: 73 additions & 0 deletions Server/App/Stack/Factory/Middleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

namespace Gos\Bundle\WebSocketBundle\Server\App\Stack\Factory;

use Gos\Bundle\WebSocketBundle\Event\ClientRejectedEvent;
use Gos\Bundle\WebSocketBundle\Event\Events;
use Gos\Bundle\WebSocketBundle\Server\App\Stack\HandshakeMiddlewareAbstract;
use Guzzle\Http\Message\RequestInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServerInterface;
use Ratchet\MessageComponentInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**
* @author Johann Saunier <[email protected]>
*/
class Middleware implements HttpServerInterface
{
/**
* @var \Ratchet\MessageComponentInterface
*/
protected $_component;

/**
* @var HandshakeMiddlewareAbstract
*/
protected $_middleware;

/**
* @param MessageComponentInterface $component
* @param HandshakeMiddlewareAbstract $middleware
*/
public function __construct(
MessageComponentInterface $component,
HandshakeMiddlewareAbstract $middleware
) {
$this->_component = $component;
$this->_middleware = $middleware;
$this->_middleware->setComponent($component);
}

/**
* {@inheritdoc}
*/
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null)
{
return $this->_middleware->onOpen($conn, $request);
}

/**
* {@inheritdoc}
*/
public function onMessage(ConnectionInterface $from, $msg)
{
return $this->_middleware->onMessage($from, $msg);
}

/**
* {@inheritdoc}
*/
public function onClose(ConnectionInterface $conn)
{
return $this->_middleware->onClose($conn);
}

/**
* {@inheritdoc}
*/
public function onError(ConnectionInterface $conn, \Exception $e)
{
return $this->_middleware->onError($conn, $e);
}
}
Loading