Esempio n. 1
0
 /**
  * @param \Thruway\Event\MessageEvent $messageEvent
  */
 public function handleMessage(MessageEvent $messageEvent)
 {
     if (!$this->isAuthorizedTo($messageEvent->session, $messageEvent->message)) {
         $messageEvent->session->sendMessage(ErrorMessage::createErrorMessageFromMessage($messageEvent->message, "wamp.error.not_authorized"));
         $messageEvent->stopPropagation();
     }
 }
Esempio n. 2
0
 /**
  * handle received message
  *
  * @param \Thruway\AbstractSession $session
  * @param \Thruway\Message\Message $msg
  * @return void
  */
 public function onMessage(AbstractSession $session, Message $msg)
 {
     if ($msg instanceof PublishedMessage) {
         $this->processPublished($msg);
     } elseif ($msg instanceof ErrorMessage) {
         $this->processError($msg);
     } else {
         $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($msg));
     }
 }
Esempio n. 3
0
 /**
  * @param Session $session
  * @param Message $msg
  */
 public function onMessage(Session $session, Message $msg)
 {
     if (!$session->isAuthenticated()) {
         if ($msg instanceof HelloMessage) {
             $this->manager->debug("got hello");
             // send welcome message
             if ($this->sessions->contains($session)) {
                 $this->manager->error("Connection tried to rejoin realm when it is already joined to the realm.");
                 $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($msg));
                 // TODO should shut down session here
             } else {
                 $this->sessions->attach($session);
                 $session->setRealm($this);
                 $session->setState(Session::STATE_UP);
                 // this should probably be after authentication
                 if ($this->getAuthenticationManager() !== null) {
                     $this->getAuthenticationManager()->onAuthenticationMessage($this, $session, $msg);
                 } else {
                     $session->setAuthenticated(true);
                     $session->setAuthenticationDetails(AuthenticationDetails::createAnonymous());
                     // the broker and dealer should give us this information
                     $roles = array("broker" => new \stdClass(), "dealer" => new \stdClass());
                     $session->sendMessage(new WelcomeMessage($session->getSessionId(), array("roles" => $roles)));
                 }
             }
         } else {
             if ($msg instanceof AuthenticateMessage) {
                 if ($this->getAuthenticationManager() !== null) {
                     $this->getAuthenticationManager()->onAuthenticationMessage($this, $session, $msg);
                 } else {
                     // TODO: should shut down here probably
                     $this->manager->error("Authenticate sent to realm without auth manager.");
                 }
             } else {
                 $this->manager->error("Unhandled message sent to unauthenticated realm: " . $msg->getMsgCode());
                 $session->sendMessage(new AbortMessage(new \stdClass(), "wamp.error.not_authorized"));
                 $session->shutdown();
             }
         }
     } else {
         $handled = false;
         /* @var $role AbstractRole */
         foreach ($this->roles as $role) {
             if ($role->handlesMessage($msg)) {
                 $role->onMessage($session, $msg);
                 $handled = true;
                 break;
             }
         }
         if (!$handled) {
             $this->manager->warning("Unhandled message sent to \"{$this->getRealmName()}\": {$msg->getSerializedMessage()}");
         }
     }
 }
Esempio n. 4
0
 /**
  * @param AbstractSession $session
  * @param Message $msg
  * @return mixed
  */
 public function onMessage(AbstractSession $session, Message $msg)
 {
     if ($msg instanceof SubscribedMessage) {
         $this->processSubscribed($session, $msg);
     } elseif ($msg instanceof UnsubscribedMessage) {
         $this->processUnsubscribed($session, $msg);
     } elseif ($msg instanceof EventMessage) {
         $this->processEvent($session, $msg);
     } else {
         $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($msg));
     }
 }
Esempio n. 5
0
 /**
  *  Process a result as a promise
  *
  * @param \React\Promise\Promise $promise
  * @param \Thruway\Message\InvocationMessage $msg
  * @param \Thruway\ClientSession $session
  * @param array $registration
  */
 private function processResultAsPromise(Promise $promise, InvocationMessage $msg, ClientSession $session, $registration)
 {
     $promise->then(function ($promiseResults) use($msg, $session) {
         $options = new \stdClass();
         if ($promiseResults instanceof Result) {
             $yieldMsg = new YieldMessage($msg->getRequestId(), $options, $promiseResults->getArguments(), $promiseResults->getArgumentsKw());
         } else {
             $promiseResults = is_array($promiseResults) ? $promiseResults : [$promiseResults];
             $promiseResults = !$this::is_list($promiseResults) ? [$promiseResults] : $promiseResults;
             $yieldMsg = new YieldMessage($msg->getRequestId(), $options, $promiseResults);
         }
         $session->sendMessage($yieldMsg);
     }, function () use($msg, $session, $registration) {
         $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg);
         $errorMsg->setErrorURI($registration['procedure_name'] . '.error');
         $session->sendMessage($errorMsg);
     }, function ($results) use($msg, $session, $registration) {
         $options = ["progress" => true];
         if ($results instanceof Result) {
             $yieldMsg = new YieldMessage($msg->getRequestId(), $options, $results->getArguments(), $results->getArgumentsKw());
         } else {
             $results = is_array($results) ? $results : [$results];
             $results = !$this::is_list($results) ? [$results] : $results;
             $yieldMsg = new YieldMessage($msg->getRequestId(), $options, $results);
         }
         $session->sendMessage($yieldMsg);
     });
 }
Esempio n. 6
0
 /**
  * Process call
  *
  * @param \Thruway\Session $session
  * @param Call $call
  * @throws \Exception
  * @return bool | Call
  */
 public function processCall(Session $session, Call $call)
 {
     // find a registration to call
     if (count($this->registrations) == 0) {
         $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($call->getCallMessage(), 'wamp.error.no_such_procedure'));
         return false;
     }
     // just send it to the first one if we don't allow multiple registrations
     if (!$this->getAllowMultipleRegistrations()) {
         $this->registrations[0]->processCall($call);
     } else {
         $this->callQueue->enqueue($call);
         $this->processQueue();
     }
     return true;
 }
Esempio n. 7
0
 private function processInvocationError(Session $session, ErrorMessage $msg)
 {
     $call = $this->getCallByRequestId($msg->getRequestId());
     if (!$call) {
         $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg);
         $this->manager->error('No call for invocation error message: ' . $msg->getRequestId());
         // TODO: do we send a message back to the callee?
         $errorMsg->setErrorURI('wamp.error.no_such_procedure');
         $session->sendMessage($errorMsg);
         return false;
     }
     $this->calls->detach($call);
     $errorMsg = ErrorMessage::createErrorMessageFromMessage($call->getCallMessage());
     $errorMsg->setErrorURI($msg->getErrorURI());
     $errorMsg->setArguments($msg->getArguments());
     $errorMsg->setArgumentsKw($msg->getArgumentsKw());
     $call->getCallerSession()->sendMessage($errorMsg);
 }
Esempio n. 8
0
 /**
  * Process All Messages if the session has been authenticated
  *
  * @param \Thruway\Session $session
  * @param \Thruway\Message\Message $msg
  */
 private function processAuthenticated(Session $session, Message $msg)
 {
     // authorization stuff here
     if ($msg instanceof ActionMessageInterface) {
         if (!$this->getAuthorizationManager()->isAuthorizedTo($session, $msg)) {
             Logger::alert($this, "Permission denied: " . $msg->getActionName() . " " . $msg->getUri() . " for " . $session->getAuthenticationDetails()->getAuthId());
             $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($msg, "wamp.error.not_authorized"));
             return;
         }
     }
     $handled = false;
     foreach ($this->roles as $role) {
         if ($role->handlesMessage($msg)) {
             $role->onMessage($session, $msg);
             $handled = true;
             break;
         }
     }
     if (!$handled) {
         Logger::warning($this, "Unhandled message sent to \"{$this->getRealmName()}\"");
     }
 }
Esempio n. 9
0
 /**
  * @param Session $session
  * @param ErrorMessage $msg
  */
 private function processInterruptError(Session $session, ErrorMessage $msg)
 {
     $call = isset($this->callInterruptIndex[$msg->getRequestId()]) ? $this->callInterruptIndex[$msg->getRequestId()] : null;
     if (!$call) {
         Logger::warning($this, "Interrupt error with no corresponding interrupt index");
         return;
     }
     $errorMsgToCaller = ErrorMessage::createErrorMessageFromMessage($call->getCancelMessage());
     $errorMsgToCaller->setErrorURI($msg->getErrorURI());
     $callerSession = $call->getCallerSession();
     $callerSession->sendMessage($errorMsgToCaller);
     $call->getRegistration()->removeCall($call);
     $this->removeCall($call);
 }
Esempio n. 10
0
 /**
  * processCancel processes cancel message from the caller.
  * Return true if the Call should be removed from active calls
  *
  * @param Session $session
  * @param CancelMessage $msg
  * @return bool
  */
 public function processCancel(Session $session, CancelMessage $msg)
 {
     if ($this->getCallerSession() !== $session) {
         Logger::warning($this, "session attempted to cancel call they did not own.");
         return false;
     }
     if ($this->getCalleeSession() === null) {
         // this call has not been sent to a callee yet (it is in a queue)
         // we can just kill it and say it was canceled
         $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg, "wamp.error.canceled");
         $details = $errorMsg->getDetails() ?: (object) [];
         $details->_thruway_removed_from_queue = true;
         $session->sendMessage($errorMsg);
         return true;
     }
     $details = (object) [];
     if ($this->getCalleeSession()->getHelloMessage() instanceof HelloMessage) {
         $details = $this->getCalleeSession()->getHelloMessage()->getDetails();
     }
     $calleeSupportsCancel = false;
     if (isset($details->roles->callee->features->call_canceling) && is_scalar($details->roles->callee->features->call_canceling)) {
         $calleeSupportsCancel = (bool) $details->roles->callee->features->call_canceling;
     }
     if (!$calleeSupportsCancel) {
         $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg);
         $errorMsg->setErrorURI('wamp.error.not_supported');
         $session->sendMessage($errorMsg);
         return false;
     }
     $this->setCancelMessage($msg);
     $this->canceling = true;
     $calleeSession = $this->getCalleeSession();
     $interruptMessage = new InterruptMessage($this->getInvocationRequestId(), (object) []);
     $calleeSession->sendMessage($interruptMessage);
     $this->setInterruptMessage($interruptMessage);
     if (isset($msg->getOptions()->mode) && is_scalar($msg->getOptions()->mode) && $msg->getOptions()->mode == "killnowait") {
         $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg, "wamp.error.canceled");
         $session->sendMessage($errorMsg);
         return true;
     }
     return false;
 }
Esempio n. 11
0
 public function testInvocationError()
 {
     $dealer = new \Thruway\Role\Dealer();
     $callerTransport = new \Thruway\Transport\DummyTransport();
     $callerSession = new Session($callerTransport);
     $calleeTransport = new \Thruway\Transport\DummyTransport();
     $calleeSession = new Session($calleeTransport);
     // register from callee
     $registerMsg = new \Thruway\Message\RegisterMessage(1, new stdClass(), 'test_proc_name');
     $dealer->handleRegisterMessage(new \Thruway\Event\MessageEvent($calleeSession, $registerMsg));
     $this->assertInstanceOf('\\Thruway\\Message\\RegisteredMessage', $calleeTransport->getLastMessageSent());
     // call from one session
     $callRequestId = \Thruway\Common\Utils::getUniqueId();
     $callMsg = new \Thruway\Message\CallMessage($callRequestId, new stdClass(), 'test_proc_name');
     $dealer->handleCallMessage(new \Thruway\Event\MessageEvent($callerSession, $callMsg));
     $this->assertInstanceOf('\\Thruway\\Message\\InvocationMessage', $calleeTransport->getLastMessageSent());
     $errorMsg = \Thruway\Message\ErrorMessage::createErrorMessageFromMessage($calleeTransport->getLastMessageSent(), 'the.error.uri');
     $dealer->handleErrorMessage(new \Thruway\Event\MessageEvent($calleeSession, $errorMsg));
     /** @var \Thruway\Message\ErrorMessage $returnedError */
     $returnedError = $callerTransport->getLastMessageSent();
     $this->assertInstanceOf('\\Thruway\\Message\\ErrorMessage', $returnedError);
     $this->assertEquals(Message::MSG_CALL, $returnedError->getErrorMsgCode());
     $this->assertEquals($callRequestId, $returnedError->getErrorRequestId());
     $this->assertEquals('the.error.uri', $returnedError->getErrorURI());
 }
Esempio n. 12
0
 /**
  * @param Session $session
  * @param UnsubscribeMessage $msg
  * @return UnsubscribedMessage
  */
 public function processUnsubscribe(Session $session, UnsubscribeMessage $msg)
 {
     $subscription = $this->getSubscriptionById($msg->getSubscriptionId());
     if (!$subscription || !isset($this->topics[$subscription->getTopic()])) {
         $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg);
         $session->sendMessage($errorMsg->setErrorURI('wamp.error.no_such_subscription'));
     }
     $topicName = $subscription->getTopic();
     $subscribers = $this->topics[$topicName];
     /* @var $subscriber Session */
     foreach ($this->topics[$topicName] as $key => $subscriber) {
         if ($subscriber == $session) {
             unset($subscribers[$key]);
         }
     }
     $this->subscriptions->detach($subscription);
     $session->sendMessage(new UnsubscribedMessage($msg->getRequestId()));
 }
Esempio n. 13
0
 /**
  * Process Unsubscribe message
  *
  * @param \Thruway\Session $session
  * @param \Thruway\Message\UnsubscribeMessage $msg
  */
 protected function processUnsubscribe(Session $session, UnsubscribeMessage $msg)
 {
     $subscription = false;
     // should probably be more efficient about this - maybe later
     /** @var SubscriptionGroup $subscriptionGroup */
     foreach ($this->subscriptionGroups as $subscriptionGroup) {
         $result = $subscriptionGroup->processUnsubscribe($session, $msg);
         if ($result !== false) {
             $subscription = $result;
         }
     }
     if ($subscription === false) {
         $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg);
         $session->sendMessage($errorMsg->setErrorURI('wamp.error.no_such_subscription'));
         return;
     }
 }
Esempio n. 14
0
 /**
  * This will send error messages on all pending calls
  * This is used when a session disconnects before completing a call
  */
 public function errorAllPendingCalls()
 {
     foreach ($this->calls as $call) {
         $call->getCallerSession()->sendMessage(ErrorMessage::createErrorMessageFromMessage($call->getCallMessage(), 'wamp.error.canceled'));
     }
 }
Esempio n. 15
0
 /**
  * @param ClientSession $session
  * @param InvocationMessage $msg
  */
 public function processInvocation(ClientSession $session, InvocationMessage $msg)
 {
     foreach ($this->registrations as $key => $registration) {
         if (!isset($registration["registration_id"])) {
             $this->logger->info("Registration_id not set for " . $registration['procedure_name'] . "\n");
         } else {
             if ($registration["registration_id"] === $msg->getRegistrationId()) {
                 if ($registration['callback'] === null) {
                     // this is where calls end up if the client has called unregister but
                     // have not yet received confirmation from the router about the
                     // unregistration
                     $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($msg, "thruway.error.unregistering"));
                     return;
                 }
                 $results = $registration["callback"]($msg->getArguments(), $msg->getArgumentsKw(), $msg->getDetails());
                 if ($results instanceof Promise) {
                     // the result is a promise - hook up stuff as a callback
                     $results->then(function ($promiseResults) use($msg, $session) {
                         $promiseResults = is_array($promiseResults) ? $promiseResults : [$promiseResults];
                         $promiseResults = !$this::is_list($promiseResults) ? [$promiseResults] : $promiseResults;
                         $options = new \stdClass();
                         $yieldMsg = new YieldMessage($msg->getRequestId(), $options, $promiseResults);
                         $session->sendMessage($yieldMsg);
                     }, function ($errorUri = null, $errorArgs = null, $errorArgsKw = null) use($msg, $session, $registration) {
                         $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg);
                         if ($errorUri !== null) {
                             $errorMsg->setErrorURI($registration['procedure_name'] . '.error');
                         } else {
                             $errorMsg->setErrorURI("thruway.invocation.error");
                         }
                         if (is_array($errorArgs)) {
                             $errorMsg->setArguments($errorArgs);
                         }
                         if (is_array($errorArgsKw)) {
                             $errorMsg->setArgumentsKw($errorArgsKw);
                         }
                         $session->sendMessage($errorMsg);
                     });
                 } else {
                     $results = !$this::is_list($results) ? [$results] : $results;
                     $options = new \stdClass();
                     $yieldMsg = new YieldMessage($msg->getRequestId(), $options, $results);
                     $session->sendMessage($yieldMsg);
                 }
                 break;
             }
         }
     }
 }
 public function handleHelloMessage(Realm $realm, Session $session, HelloMessage $msg)
 {
     $requestedMethods = $msg->getAuthMethods();
     $sentMessage = false;
     // go through our authMethods and see which one matches first
     foreach ($this->authMethods as $authMethod => $authMethodInfo) {
         if (in_array($authMethod, $requestedMethods) && (in_array($realm->getRealmName(), $authMethodInfo['auth_realms']) || in_array("*", $authMethodInfo['auth_realms']))) {
             // we can agree on something
             $authDetails = new AuthenticationDetails();
             $authDetails->setAuthMethod($authMethod);
             $helloDetails = $msg->getDetails();
             if (isset($helloDetails['authid'])) {
                 $authDetails->setAuthId($helloDetails['authid']);
             }
             $session->setAuthenticationDetails($authDetails);
             $sessionInfo = array("sessionId" => $session->getSessionId(), "realm" => $realm->getRealmName());
             $this->session->call($authMethodInfo['handlers']['onhello'], array($msg, $sessionInfo))->then(function ($res) use($session, $msg) {
                 // this is handling the return of the onhello RPC call
                 if (!is_array($res)) {
                     $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($msg));
                     return;
                 }
                 if (count($res) < 2) {
                     $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($msg));
                     return;
                 }
                 if ($res[0] == "CHALLENGE") {
                     // TODO: validate challenge message
                     $authMethod = $res[1]['challenge_method'];
                     $challenge = $res[1]['challenge'];
                     $session->getAuthenticationDetails()->setChallenge($challenge);
                     $session->getAuthenticationDetails()->setChallengeDetails($res[1]);
                     $session->sendMessage(new ChallengeMessage($authMethod, $session->getAuthenticationDetails()->getChallengeDetails()));
                 } else {
                     if ($res[0] == "NOCHALLENGE") {
                         $session->sendMessage(new WelcomeMessage($session->getSessionId(), array("authid" => $res[1]["authid"], "authmethod" => $session->getAuthenticationDetails()->getAuthMethod())));
                     } else {
                         if ($res[0] == "ERROR") {
                             $session->sendMessage(new AbortMessage(new \stdClass(), "authentication_failure"));
                         } else {
                             $session->sendMessage(new AbortMessage(new \stdClass(), "authentication_failure"));
                         }
                     }
                 }
             });
             $sentMessage = true;
         }
     }
     /*
      * If we've gotten this far without sending a message, it means that no auth methods were sent by the client or the auth method sent
      * by the client hasn't been registered for this realm, so we need to check if there are any auth providers registered for the realm.
      * If there are auth provides registered then Abort. Otherwise we can send a welcome message.
      */
     if (!$sentMessage) {
         if ($this->realmHasAuthProvider($realm->getRealmName())) {
             $session->sendMessage(new AbortMessage(new \stdClass(), "realm_authorization_failure"));
         } else {
             //Logged in as anonymous
             $session->setAuthenticationDetails(AuthenticationDetails::createAnonymous());
             $roles = array("broker" => new \stdClass(), "dealer" => new \stdClass());
             $session->sendMessage(new WelcomeMessage($session->getSessionId(), array("roles" => $roles)));
             $session->setAuthenticated(true);
         }
     }
 }