voryx / ThruwayBundle

Bundle for building Real-time Apps in Symfony
98 stars 47 forks source link

Setting up simple token authentication #98

Open dark-matter-matters opened 5 years ago

dark-matter-matters commented 5 years ago

Hello. This bundle looks pretty nice but it lacks a bit of documentation imho. I'd be pleased to write some if I could know how it works.

I want to secure my WS connection using a token. I have already implemented the token system on my API with a token field on User entity. The JS client already has a token when it subscribes using Autobahn.

All I need is to have access to the token sent by the client and check it before he is subscribed to the realm.

So far I tried to follow this tutorial, and tried what's referenced in issue #92 :

App\Security\AuthenticationProvider

class AuthenticationProvider extends AbstractAuthProviderClient
{
    private $logger;

    public function __construct(array $authRealms, LoopInterface $loop = null, LoggerInterface $logger)
    {
        $this->logger = $logger;
        parent::__construct($authRealms, $loop);
    }

    public function getMethodName()
    {
        return "jwt";
    }

    public function processAuthenticate($signature, $extra = null)
    {
        $this->logger->warning('Authenticating');
        if(!empty($signature)) {
            return ["SUCCESS"];
        }
        return ["FAILURE"];
    }
}

App\Security\ThruwayAuthManager

class ThruwayAuthManager extends RouterModuleClient implements RealmModuleInterface, RouterModuleInterface
{

    private $logger;

    public function __construct($realm ="realm1", LoggerInterface $logger)
    {
        $this->logger = $logger;
        parent::__construct($realm);
    }

    /**
     * Process Authenticate message
     *
     * @param mixed $signature
     * @param mixed $extra
     * @return array
     */
    public function processAuthenticate($signature, $extra = null)
    {
        $this->logger->warning('Getting signature');
        if ($signature == "letMeIn") {
            return ["SUCCESS"];
        } else {
            return ["FAILURE"];
        }
    }

    /**
     * @param MessageEvent $msg
     * @return bool
     */
    public function authorize(MessageEvent $msg)
    {
        $this->logger->warning('Message event : ', $msg->message);
        if ($msg->session->getAuthenticationDetails()->getAuthId() === 'username') {
            return true;
        }
        return false;
    }

    /**
     * Returns an array of event names this subscriber wants to listen to.
     *
     * @return array The event names to listen to
     */
    public static function getSubscribedEvents()
    {
        return [
            'new_realm' => ['handleNewRealm', 10]
        ];
    }

    /**
     * @param NewRealmEvent $newRealmEvent
     */
    public function handleNewRealm(NewRealmEvent $newRealmEvent)
    {
        $realm = $newRealmEvent->realm;

        if ($realm->getRealmName() === $this->getRealm()) {
            $realm->addModule($this);
        }
    }

    /**
     * Called by the router when it is added
     *
     * @param RouterInterface $router
     * @param LoopInterface $loop
     */
    public function initModule(RouterInterface $router, LoopInterface $loop)
    {
        // TODO: Implement initModule() method.
    }

    /** @return array */
    public function getSubscribedRealmEvents()
    {
        return [
        'PublishMessageEvent'   => ['authorize', 100],
        'SubscribeMessageEvent' => ['authorize', 100],
        'RegisterMessageEvent'  => ['authorize', 100],
        'CallMessageEvent'      => ['authorize', 100],
        ];
    }

    public function onSessionStart($session, $transport)
    {
        parent::onSessionStart($session, $transport);

        $session->subscribe('wamp.metaevent.session.on_join', [$this, 'onSessionJoin']);
        $session->subscribe('wamp.metaevent.session.on_leave', [$this, 'onSessionLeave']);
    }

    public function onSessionJoin($args, $kwArgs, $options)
    {
        $this->logger->warning('Joining session');
    }

    public function onSessionLeave($args, $kwArgs, $options)
    {
        $this->logger->warning('Leaving session');
    }
}

services.yaml

    thruway_auth_provider:
        class: App\Security\AuthenticationProvider
        public: true
        arguments:
            - ["@=parameter('voryx_thruway')['realm']"]
            - '@voryx.thruway.loop'
        tags: ['thruway.internal_client']

    thruway_auth_manager:
        class: App\Security\ThruwayAuthManager
        public: true
        tags: ['thruway.internal_client']

thruway.yaml

voryx_thruway:
  realm: 'realm1'
  url: 'ws://127.0.0.1:8080' 
  enable_logging: true
  router:
    ip: '127.0.0.1'  # the ip that the router should start on
    port: '8080'  # public facing port.  If authentication is enabled, this port will be protected
    authentication: true # true will load the AuthenticationManager
    authorization: thruway_auth_manager

I start my server using php bin/console thruway:router:start -vvv I also have a listener that publishes a message when my entity is updated, but I doubt it's relevant here. This code does not trigger any of my warning logs when a client connects. It does display messages on startup for internalClient though.

Any help would be greatly appreciated ;)