Beispiel #1
0
 /**
  * process error
  *
  * @param \Thruway\Message\ErrorMessage $msg
  */
 protected function processError(ErrorMessage $msg)
 {
     if (isset($this->publishRequests[$msg->getRequestId()])) {
         /* @var $futureResult Deferred */
         $futureResult = $this->publishRequests[$msg->getRequestId()]["future_result"];
         $futureResult->reject($msg);
         unset($this->publishRequests[$msg->getRequestId()]);
     }
 }
Beispiel #2
0
 /**
  * @param ClientSession $session
  * @param ErrorMessage $msg
  */
 public function processError(ClientSession $session, ErrorMessage $msg)
 {
     if (isset($this->publishRequests[$msg->getRequestId()])) {
         /* @var $futureResult Deferred */
         $futureResult = $this->publishRequests[$msg->getRequestId()]["future_result"];
         $futureResult->reject($msg->getErrorMsgCode());
         unset($this->publishRequests[$msg->getRequestId()]);
     }
 }
Beispiel #3
0
 /**
  * Process subscribe error
  *
  * @param \Thruway\AbstractSession $session
  * @param \Thruway\Message\ErrorMessage $msg
  */
 protected function processSubscribeError(AbstractSession $session, ErrorMessage $msg)
 {
     foreach ($this->subscriptions as $key => $subscription) {
         if ($subscription["request_id"] === $msg->getErrorRequestId()) {
             // reject the promise
             $this->subscriptions[$key]['deferred']->reject($msg);
             unset($this->subscriptions[$key]);
             break;
         }
     }
 }
Beispiel #4
0
 /**
  * Process ErrorMessage
  *
  * @param \Thruway\Message\ErrorMessage $msg
  */
 protected function processError(ErrorMessage $msg)
 {
     switch ($msg->getErrorMsgCode()) {
         case Message::MSG_CALL:
             if (isset($this->callRequests[$msg->getRequestId()])) {
                 /* @var $futureResult Deferred */
                 $futureResult = $this->callRequests[$msg->getRequestId()]['future_result'];
                 $futureResult->reject($msg);
                 unset($this->callRequests[$msg->getRequestId()]);
             }
             break;
     }
 }
Beispiel #5
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();
     }
 }
Beispiel #6
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()}");
         }
     }
 }
Beispiel #7
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));
     }
 }
Beispiel #8
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);
 }
Beispiel #9
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;
 }
Beispiel #10
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());
 }
Beispiel #11
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;
 }
Beispiel #12
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;
     }
 }
Beispiel #13
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'));
     }
 }
Beispiel #14
0
 public function __construct(ErrorMessage $error, \Exception $previous = null)
 {
     $this->errorUri = $error->getErrorURI();
     $this->errorMessage = ucfirst(implode(': ', $error->getArguments()));
     parent::__construct($this->errorMessage, $error->getMsgCode(), $previous);
 }
Beispiel #15
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()}\"");
     }
 }
Beispiel #16
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);
 }
Beispiel #17
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()));
 }
Beispiel #18
0
 /**
  * Handle error when unregister
  *
  * @param \Thruway\ClientSession $session
  * @param \Thruway\Message\ErrorMessage $msg
  */
 public function handleErrorUnregister(ClientSession $session, ErrorMessage $msg)
 {
     foreach ($this->registrations as $key => $registration) {
         if (isset($registration['unregister_request_id'])) {
             if ($registration["unregister_request_id"] === $msg->getRequestId()) {
                 /** @var Deferred $deferred */
                 $deferred = $registration['unregister_deferred'];
                 $deferred->reject($msg);
                 // I guess we get rid of the registration now?
                 unset($this->registrations[$key]);
                 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);
         }
     }
 }