コード例 #1
0
ファイル: dealer.py プロジェクト: Shareed2k/AutobahnPython
   def processRegister(self, session, register):
      """
      Implements :func:`autobahn.wamp.interfaces.IDealer.processRegister`
      """
      assert(session in self._session_to_registrations)

      ## check procedure URI
      ##
      if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(register.procedure)) or \
         (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(register.procedure)):

         reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.INVALID_URI, ["register for invalid procedure URI '{}'".format(register.procedure)])

      else:

         if not register.procedure in self._procs_to_regs:
            registration_id = util.id()
            self._procs_to_regs[register.procedure] = (registration_id, session, register.discloseCaller)
            self._regs_to_procs[registration_id] = register.procedure

            self._session_to_registrations[session].add(registration_id)

            reply = message.Registered(register.request, registration_id)
         else:
            reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.PROCEDURE_ALREADY_EXISTS, ["register for already registered procedure URI '{}'".format(register.procedure)])

      session._transport.send(reply)
コード例 #2
0
ファイル: checkconfig.py プロジェクト: ilovejs/crossbar
def check_or_raise_uri(value, message):
   if type(value) != six.text_type:
      raise Exception("{}: invalid type {} for URI".format(message, type(value)))
   #if not _URI_PAT_LOOSE_NON_EMPTY.match(value):
   if not _URI_PAT_STRICT_NON_EMPTY.match(value):
      raise Exception("{}: invalid value '{}' for URI".format(message, value))
   return value
コード例 #3
0
   def processCall(self, session, call):
      """
      Implements :func:`autobahn.wamp.interfaces.IDealer.processCall`
      """
      assert(session in self._session_to_registrations)

      ## check procedure URI
      ##
      if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(call.procedure)) or \
         (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(call.procedure)):

         reply = message.Error(message.Register.MESSAGE_TYPE, call.request, ApplicationError.INVALID_URI, ["call with invalid procedure URI '{}'".format(call.procedure)])
         session._transport.send(reply)

      else:

         if call.procedure in self._procs_to_regs:

            d = maybeDeferred(self._router.authorize, session, call.procedure, IRouter.ACTION_CALL)

            def on_authorize(authorized):
               if authorized:
                  registration_id, endpoint_session, discloseCaller = self._procs_to_regs[call.procedure]

                  request_id = util.id()

                  if discloseCaller or call.discloseMe:
                     caller = session._session_id
                     authid = session._authid
                     authrole = session._authrole
                     authmethod = session._authmethod
                  else:
                     caller = None
                     authid = None
                     authrole = None
                     authmethod = None

                  invocation = message.Invocation(request_id,
                                                  registration_id,
                                                  args = call.args,
                                                  kwargs = call.kwargs,
                                                  timeout = call.timeout,
                                                  receive_progress = call.receive_progress,
                                                  caller = caller,
                                                  authid = authid,
                                                  authrole = authrole,
                                                  authmethod = authmethod)

                  self._invocations[request_id] = (call, session)
                  endpoint_session._transport.send(invocation)
               else:
                  reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.NOT_AUTHORIZED, ["session is not authorized to call procedure '{}'".format(call.procedure)])
                  session._transport.send(reply)                 

            d.addCallback(on_authorize)

         else:
            reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.NO_SUCH_PROCEDURE, ["no procedure '{}' registered".format(call.procedure)])
            session._transport.send(reply)
コード例 #4
0
    def processCall(self, session, call):
        """
      Implements :func:`autobahn.wamp.interfaces.IDealer.processCall`
      """
        assert (session in self._session_to_registrations)

        ## check procedure URI
        ##
        if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(call.procedure)) or \
           (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(call.procedure)):

            reply = message.Error(
                message.Register.MESSAGE_TYPE, call.request,
                ApplicationError.INVALID_URI, [
                    "call with invalid procedure URI '{}'".format(
                        call.procedure)
                ])
            session._transport.send(reply)

        else:

            if call.procedure in self._procs_to_regs:
                registration_id, endpoint_session, discloseCaller = self._procs_to_regs[
                    call.procedure]

                request_id = util.id()

                if discloseCaller or call.discloseMe:
                    caller = session._session_id
                    authid = session._authid
                    authrole = session._authrole
                    authmethod = session._authmethod
                else:
                    caller = None
                    authid = None
                    authrole = None
                    authmethod = None

                invocation = message.Invocation(
                    request_id,
                    registration_id,
                    args=call.args,
                    kwargs=call.kwargs,
                    timeout=call.timeout,
                    receive_progress=call.receive_progress,
                    caller=caller,
                    authid=authid,
                    authrole=authrole,
                    authmethod=authmethod)

                self._invocations[request_id] = (call, session)
                endpoint_session._transport.send(invocation)
            else:
                reply = message.Error(
                    message.Call.MESSAGE_TYPE, call.request,
                    ApplicationError.NO_SUCH_PROCEDURE,
                    ["no procedure '{}' registered".format(call.procedure)])
                session._transport.send(reply)
コード例 #5
0
   def processSubscribe(self, session, subscribe):
      """
      Implements :func:`autobahn.wamp.interfaces.IBroker.processSubscribe`
      """
      #assert(session in self._session_to_subscriptions)

      ## check topic URI
      ##
      if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(subscribe.topic)) or \
         (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(subscribe.topic)):

         reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.INVALID_URI, ["subscribe for invalid topic URI '{0}'".format(subscribe.topic)])
         session._transport.send(reply)

      else:

         ## authorize action
         ##
         d = self._as_future(self._router.authorize, session, subscribe.topic, IRouter.ACTION_SUBSCRIBE)

         def on_authorize_success(authorized):
            if not authorized:

               reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.NOT_AUTHORIZED, ["session is not authorized to subscribe to topic '{0}'".format(subscribe.topic)])

            else:

               if not subscribe.topic in self._topic_to_sessions:
                  subscription = util.id()
                  self._topic_to_sessions[subscribe.topic] = (subscription, set())

               subscription, subscribers = self._topic_to_sessions[subscribe.topic]

               if not session in subscribers:
                  subscribers.add(session)

               if not subscription in self._subscription_to_sessions:
                  self._subscription_to_sessions[subscription] = (subscribe.topic, set())

               _, subscribers = self._subscription_to_sessions[subscription]
               if not session in subscribers:
                  subscribers.add(session)

               if not subscription in self._session_to_subscriptions[session]:
                  self._session_to_subscriptions[session].add(subscription)

               reply = message.Subscribed(subscribe.request, subscription)

            session._transport.send(reply)

         def on_authorize_error(err):
            reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.AUTHORIZATION_FAILED, ["failed to authorize session for subscribing to topic URI '{0}': {1}".format(subscribe.topic, err.value)])
            session._transport.send(reply)

         self._add_future_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #6
0
ファイル: broker.py プロジェクト: BigSab/AutobahnPython
   def processSubscribe(self, session, subscribe):
      """
      Implements :func:`autobahn.wamp.interfaces.IBroker.processSubscribe`
      """
      #assert(session in self._session_to_subscriptions)

      ## check topic URI
      ##
      if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(subscribe.topic)) or \
         (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(subscribe.topic)):

         reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.INVALID_URI, ["subscribe for invalid topic URI '{0}'".format(subscribe.topic)])
         session._transport.send(reply)

      else:

         ## authorize action
         ##
         d = self._as_future(self._router.authorize, session, subscribe.topic, IRouter.ACTION_SUBSCRIBE)

         def on_authorize_success(authorized):
            if not authorized:

               reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.NOT_AUTHORIZED, ["session is not authorized to subscribe to topic '{0}'".format(subscribe.topic)])

            else:

               if not subscribe.topic in self._topic_to_sessions:
                  subscription = util.id()
                  self._topic_to_sessions[subscribe.topic] = (subscription, set())

               subscription, subscribers = self._topic_to_sessions[subscribe.topic]

               if not session in subscribers:
                  subscribers.add(session)

               if not subscription in self._subscription_to_sessions:
                  self._subscription_to_sessions[subscription] = (subscribe.topic, set())

               _, subscribers = self._subscription_to_sessions[subscription]
               if not session in subscribers:
                  subscribers.add(session)

               if not subscription in self._session_to_subscriptions[session]:
                  self._session_to_subscriptions[session].add(subscription)

               reply = message.Subscribed(subscribe.request, subscription)

            session._transport.send(reply)

         def on_authorize_error(err):
            reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.AUTHORIZATION_FAILED, ["failed to authorize session for subscribing to topic URI '{0}': {1}".format(subscribe.topic, err.value)])
            session._transport.send(reply)

         self._add_future_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #7
0
    def processSubscribe(self, session, subscribe):
        """
      Implements :func:`autobahn.wamp.interfaces.IBroker.processSubscribe`
      """
        assert (session in self._session_to_subscriptions)

        ## check topic URI
        ##
        if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(subscribe.topic)) or \
           (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(subscribe.topic)):

            reply = message.Error(
                message.Subscribe.MESSAGE_TYPE, subscribe.request,
                ApplicationError.INVALID_URI, [
                    "subscribe for invalid topic URI '{}'".format(
                        subscribe.topic)
                ])

        else:

            if not subscribe.topic in self._topic_to_sessions:
                subscription = util.id()
                self._topic_to_sessions[subscribe.topic] = (subscription,
                                                            set())

            subscription, subscribers = self._topic_to_sessions[
                subscribe.topic]

            if not session in subscribers:
                subscribers.add(session)

            if not subscription in self._subscription_to_sessions:
                self._subscription_to_sessions[subscription] = (
                    subscribe.topic, set())

            _, subscribers = self._subscription_to_sessions[subscription]
            if not session in subscribers:
                subscribers.add(session)

            if not subscription in self._session_to_subscriptions[session]:
                self._session_to_subscriptions[session].add(subscription)

            reply = message.Subscribed(subscribe.request, subscription)

        session._transport.send(reply)
コード例 #8
0
   def processRegister(self, session, register):
      """
      Implements :func:`autobahn.wamp.interfaces.IDealer.processRegister`
      """
      assert(session in self._session_to_registrations)

      ## check procedure URI
      ##
      if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(register.procedure)) or \
         (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(register.procedure)):

         reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.INVALID_URI, ["register for invalid procedure URI '{0}'".format(register.procedure)])
         session._transport.send(reply)

      else:

         if not register.procedure in self._procs_to_regs:

            ## authorize action
            ##
            d = self._as_future(self._router.authorize, session, register.procedure, IRouter.ACTION_REGISTER)

            def on_authorize_success(authorized):
               if authorized:
                  registration_id = util.id()
                  self._procs_to_regs[register.procedure] = (registration_id, session, register.discloseCaller, register.discloseCallerTransport)
                  self._regs_to_procs[registration_id] = register.procedure

                  self._session_to_registrations[session].add(registration_id)

                  reply = message.Registered(register.request, registration_id)
               else:
                  reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.NOT_AUTHORIZED, ["session is not authorized to register procedure '{0}'".format(register.procedure)])

               session._transport.send(reply)

            def on_authorize_error(err):
               reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.AUTHORIZATION_FAILED, ["failed to authorize session for registering procedure '{0}': {1}".format(register.procedure, err.value)])
               session._transport.send(reply)

            self._add_future_callbacks(d, on_authorize_success, on_authorize_error)

         else:
            reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.PROCEDURE_ALREADY_EXISTS, ["register for already registered procedure '{0}'".format(register.procedure)])
            session._transport.send(reply)
コード例 #9
0
ファイル: dealer.py プロジェクト: kampka/AutobahnPython
   def processRegister(self, session, register):
      """
      Implements :func:`autobahn.wamp.interfaces.IDealer.processRegister`
      """
      assert(session in self._session_to_registrations)

      ## check procedure URI
      ##
      if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(register.procedure)) or \
         (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(register.procedure)):

         reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.INVALID_URI, ["register for invalid procedure URI '{0}'".format(register.procedure)])
         session._transport.send(reply)

      else:

         if not register.procedure in self._procs_to_regs:

            ## authorize action
            ##
            d = self.as_future(self._router.authorize, session, register.procedure, IRouter.ACTION_REGISTER)

            def on_authorize_success(authorized):
               if authorized:
                  registration_id = util.id()
                  self._procs_to_regs[register.procedure] = (registration_id, session, register.discloseCaller, register.discloseCallerTransport)
                  self._regs_to_procs[registration_id] = register.procedure

                  self._session_to_registrations[session].add(registration_id)

                  reply = message.Registered(register.request, registration_id)
               else:
                  reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.NOT_AUTHORIZED, ["session is not authorized to register procedure '{0}'".format(register.procedure)])

               session._transport.send(reply)

            def on_authorize_error(err):
               reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.AUTHORIZATION_FAILED, ["failed to authorize session for registering procedure '{0}': {1}".format(register.procedure, err.value)])
               session._transport.send(reply)

            self.add_future_callbacks(d, on_authorize_success, on_authorize_error)

         else:
            reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.PROCEDURE_ALREADY_EXISTS, ["register for already registered procedure '{0}'".format(register.procedure)])
            session._transport.send(reply)
コード例 #10
0
ファイル: broker.py プロジェクト: powerswitch/AutobahnPython
    def processSubscribe(self, session, subscribe):
        """
      Implements :func:`autobahn.wamp.interfaces.IBroker.processSubscribe`
      """
        assert session in self._session_to_subscriptions

        ## check topic URI
        ##
        if (not self._option_uri_strict and not _URI_PAT_LOOSE_NON_EMPTY.match(subscribe.topic)) or (
            self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(subscribe.topic)
        ):

            reply = message.Error(
                message.Subscribe.MESSAGE_TYPE,
                subscribe.request,
                ApplicationError.INVALID_URI,
                ["subscribe for invalid topic URI '{}'".format(subscribe.topic)],
            )

        else:

            if not subscribe.topic in self._topic_to_sessions:
                subscription = util.id()
                self._topic_to_sessions[subscribe.topic] = (subscription, set())

            subscription, subscribers = self._topic_to_sessions[subscribe.topic]

            if not session in subscribers:
                subscribers.add(session)

            if not subscription in self._subscription_to_sessions:
                self._subscription_to_sessions[subscription] = (subscribe.topic, set())

            _, subscribers = self._subscription_to_sessions[subscription]
            if not session in subscribers:
                subscribers.add(session)

            if not subscription in self._session_to_subscriptions[session]:
                self._session_to_subscriptions[session].add(subscription)

            reply = message.Subscribed(subscribe.request, subscription)

        session._transport.send(reply)
コード例 #11
0
    def processRegister(self, session, register):
        """
      Implements :func:`autobahn.wamp.interfaces.IDealer.processRegister`
      """
        assert (session in self._session_to_registrations)

        ## check procedure URI
        ##
        if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(register.procedure)) or \
           (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(register.procedure)):

            reply = message.Error(
                message.Register.MESSAGE_TYPE, register.request,
                ApplicationError.INVALID_URI, [
                    "register for invalid procedure URI '{}'".format(
                        register.procedure)
                ])

        else:

            if not register.procedure in self._procs_to_regs:
                registration_id = util.id()
                self._procs_to_regs[register.procedure] = (
                    registration_id, session, register.discloseCaller)
                self._regs_to_procs[registration_id] = register.procedure

                self._session_to_registrations[session].add(registration_id)

                reply = message.Registered(register.request, registration_id)
            else:
                reply = message.Error(
                    message.Register.MESSAGE_TYPE, register.request,
                    ApplicationError.PROCEDURE_ALREADY_EXISTS, [
                        "register for already registered procedure URI '{}'".
                        format(register.procedure)
                    ])

        session._transport.send(reply)
コード例 #12
0
ファイル: broker.py プロジェクト: crossbario/crossbar
    def processSubscribe(self, session, subscribe):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processSubscribe`
        """
        if self._router.is_traced:
            if not subscribe.correlation_id:
                subscribe.correlation_id = self._router.new_correlation_id()
                subscribe.correlation_is_anchor = True
                subscribe.correlation_is_last = False
            if not subscribe.correlation_uri:
                subscribe.correlation_uri = subscribe.topic
            self._router._factory._worker._maybe_trace_rx_msg(session, subscribe)

        # check topic URI: for SUBSCRIBE, must be valid URI (either strict or loose), and all
        # URI components must be non-empty for normal subscriptions, may be empty for
        # wildcard subscriptions and must be non-empty for all but the last component for
        # prefix subscriptions
        #
        if self._option_uri_strict:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_STRICT_EMPTY.match(subscribe.topic)
            elif subscribe.match == u"prefix":
                uri_is_valid = _URI_PAT_STRICT_LAST_EMPTY.match(subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(subscribe.topic)
        else:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_LOOSE_EMPTY.match(subscribe.topic)
            elif subscribe.match == u"prefix":
                uri_is_valid = _URI_PAT_LOOSE_LAST_EMPTY.match(subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(subscribe.topic)

        if not uri_is_valid:
            reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.INVALID_URI, [u"subscribe for invalid topic URI '{0}'".format(subscribe.topic)])
            reply.correlation_id = subscribe.correlation_id
            reply.correlation_uri = subscribe.topic
            reply.correlation_is_anchor = False
            reply.correlation_is_last = True
            self._router.send(session, reply)
            return

        # authorize SUBSCRIBE action
        #
        d = self._router.authorize(session, subscribe.topic, u'subscribe', options=subscribe.marshal_options())

        def on_authorize_success(authorization):
            if not authorization[u'allow']:
                # error reply since session is not authorized to subscribe
                #
                replies = [message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.NOT_AUTHORIZED, [u"session is not authorized to subscribe to topic '{0}'".format(subscribe.topic)])]
                replies[0].correlation_id = subscribe.correlation_id
                replies[0].correlation_uri = subscribe.topic
                replies[0].correlation_is_anchor = False
                replies[0].correlation_is_last = True

            else:
                # ok, session authorized to subscribe. now get the subscription
                #
                subscription, was_already_subscribed, is_first_subscriber = self._subscription_map.add_observer(session, subscribe.topic, subscribe.match, extra=SubscriptionExtra())

                if not was_already_subscribed:
                    self._session_to_subscriptions[session].add(subscription)

                # publish WAMP meta events, if we have a service session, but
                # not for the meta API itself!
                #
                if self._router._realm and \
                   self._router._realm.session and \
                   not subscription.uri.startswith(u'wamp.') and \
                   (is_first_subscriber or not was_already_subscribed):

                    has_follow_up_messages = True

                    exclude_authid = None
                    if subscribe.forward_for:
                        exclude_authid = [ff['authid'] for ff in subscribe.forward_for]

                    def _publish():
                        service_session = self._router._realm.session

                        if exclude_authid or self._router.is_traced:
                            options = types.PublishOptions(
                                correlation_id=subscribe.correlation_id,
                                correlation_is_anchor=False,
                                correlation_is_last=False,
                                exclude_authid=exclude_authid,
                            )
                        else:
                            options = None

                        if is_first_subscriber:
                            subscription_details = {
                                u'id': subscription.id,
                                u'created': subscription.created,
                                u'uri': subscription.uri,
                                u'match': subscription.match,
                            }
                            service_session.publish(
                                u'wamp.subscription.on_create',
                                session._session_id,
                                subscription_details,
                                options=options,
                            )

                        if not was_already_subscribed:
                            if options:
                                options.correlation_is_last = True

                            service_session.publish(
                                u'wamp.subscription.on_subscribe',
                                session._session_id,
                                subscription.id,
                                options=options,
                            )
                    # we postpone actual sending of meta events until we return to this client session
                    self._reactor.callLater(0, _publish)

                else:
                    has_follow_up_messages = False

                # check for retained events
                #
                def _get_retained_event():

                    if subscription.extra.retained_events:
                        retained_events = list(subscription.extra.retained_events)
                        retained_events.reverse()

                        for retained_event in retained_events:
                            authorized = False

                            if not retained_event.publish.exclude and not retained_event.publish.eligible:
                                authorized = True
                            elif session._session_id in retained_event.publish.eligible and session._session_id not in retained_event.publish.exclude:
                                authorized = True

                            if authorized:
                                publication = util.id()

                                if retained_event.publish.payload:
                                    msg = message.Event(subscription.id,
                                                        publication,
                                                        payload=retained_event.publish.payload,
                                                        enc_algo=retained_event.publish.enc_algo,
                                                        enc_key=retained_event.publish.enc_key,
                                                        enc_serializer=retained_event.publish.enc_serializer,
                                                        publisher=retained_event.publisher,
                                                        publisher_authid=retained_event.publisher_authid,
                                                        publisher_authrole=retained_event.publisher_authrole,
                                                        retained=True)
                                else:
                                    msg = message.Event(subscription.id,
                                                        publication,
                                                        args=retained_event.publish.args,
                                                        kwargs=retained_event.publish.kwargs,
                                                        publisher=retained_event.publisher,
                                                        publisher_authid=retained_event.publisher_authid,
                                                        publisher_authrole=retained_event.publisher_authrole,
                                                        retained=True)

                                msg.correlation_id = subscribe.correlation_id
                                msg.correlation_uri = subscribe.topic
                                msg.correlation_is_anchor = False
                                msg.correlation_is_last = False

                                return [msg]
                    return []

                # acknowledge subscribe with subscription ID
                #
                replies = [message.Subscribed(subscribe.request, subscription.id)]
                replies[0].correlation_id = subscribe.correlation_id
                replies[0].correlation_uri = subscribe.topic
                replies[0].correlation_is_anchor = False
                replies[0].correlation_is_last = False
                if subscribe.get_retained:
                    replies.extend(_get_retained_event())

                replies[-1].correlation_is_last = not has_follow_up_messages

            # send out reply to subscribe requestor
            #
            [self._router.send(session, reply) for reply in replies]

        def on_authorize_error(err):
            """
            the call to authorize the action _itself_ failed (note this is
            different from the call to authorize succeed, but the
            authorization being denied)
            """
            self.log.failure("Authorization of 'subscribe' for '{uri}' failed",
                             uri=subscribe.topic, failure=err)
            reply = message.Error(
                message.Subscribe.MESSAGE_TYPE,
                subscribe.request,
                ApplicationError.AUTHORIZATION_FAILED,
                [u"failed to authorize session for subscribing to topic URI '{0}': {1}".format(subscribe.topic, err.value)]
            )
            reply.correlation_id = subscribe.correlation_id
            reply.correlation_uri = subscribe.topic
            reply.correlation_is_anchor = False
            reply.correlation_is_last = True
            self._router.send(session, reply)

        txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #13
0
ファイル: dealer.py プロジェクト: kampka/AutobahnPython
   def processCall(self, session, call):
      """
      Implements :func:`autobahn.wamp.interfaces.IDealer.processCall`
      """
      assert(session in self._session_to_registrations)

      ## check procedure URI
      ##
      if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(call.procedure)) or \
         (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(call.procedure)):

         reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.INVALID_URI, ["call with invalid procedure URI '{0}'".format(call.procedure)])
         session._transport.send(reply)

      else:

         if call.procedure in self._procs_to_regs:

            ## validate payload
            ##
            try:
               self._router.validate('call', call.procedure, call.args, call.kwargs)
            except Exception as e:
               reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.INVALID_ARGUMENT, ["call of procedure '{0}' with invalid application payload: {1}".format(call.procedure, e)])
               session._transport.send(reply)
               return

            ## authorize action
            ##
            d = self.as_future(self._router.authorize, session, call.procedure, IRouter.ACTION_CALL)

            def on_authorize_success(authorized):
               if authorized:
                  registration_id, endpoint_session, discloseCaller, discloseCallerTransport = self._procs_to_regs[call.procedure]

                  request_id = util.id()

                  if discloseCaller or call.discloseMe:
                     caller = session._session_id
                     caller_transport = None
                     authid = session._authid
                     authrole = session._authrole
                     authmethod = session._authmethod
                     if discloseCallerTransport and hasattr(session._transport, '_transport_info'):
                        caller_transport = session._transport._transport_info
                  else:
                     caller = None
                     caller_transport = None
                     authid = None
                     authrole = None
                     authmethod = None

                  invocation = message.Invocation(request_id,
                                                  registration_id,
                                                  args = call.args,
                                                  kwargs = call.kwargs,
                                                  timeout = call.timeout,
                                                  receive_progress = call.receive_progress,
                                                  caller = caller,
                                                  caller_transport = caller_transport,
                                                  authid = authid,
                                                  authrole = authrole,
                                                  authmethod = authmethod)

                  self._invocations[request_id] = (call, session)
                  endpoint_session._transport.send(invocation)
               else:
                  reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.NOT_AUTHORIZED, ["session is not authorized to call procedure '{0}'".format(call.procedure)])
                  session._transport.send(reply)                 

            def on_authorize_error(err):
               reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.AUTHORIZATION_FAILED, ["failed to authorize session for calling procedure '{0}': {1}".format(call.procedure, err.value)])
               session._transport.send(reply)

            self.add_future_callbacks(d, on_authorize_success, on_authorize_error)

         else:
            reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.NO_SUCH_PROCEDURE, ["no procedure '{0}' registered".format(call.procedure)])
            session._transport.send(reply)
コード例 #14
0
ファイル: dealer.py プロジェクト: oberstet/crossbar
    def processCall(self, session, call):
        """
        Implements :func:`crossbar.router.interfaces.IDealer.processCall`
        """
        # check procedure URI: for CALL, must be valid URI (either strict or loose), and
        # all URI components must be non-empty
        if self._option_uri_strict:
            uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(call.procedure)
        else:
            uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(call.procedure)

        if not uri_is_valid:
            reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.INVALID_URI, [u"call with invalid procedure URI '{0}' (URI strict checking {1})".format(call.procedure, self._option_uri_strict)])
            self._router.send(session, reply)
            return

        # get registrations active on the procedure called
        #
        registration = self._registration_map.best_matching_observation(call.procedure)

        if registration:

            # validate payload (skip in "payload_transparency" mode)
            #
            if call.payload is None:
                try:
                    self._router.validate(u'call', call.procedure, call.args, call.kwargs)
                except Exception as e:
                    reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.INVALID_ARGUMENT, [u"call of procedure '{0}' with invalid application payload: {1}".format(call.procedure, e)])
                    self._router.send(session, reply)
                    return

            # authorize CALL action
            #
            d = self._router.authorize(session, call.procedure, u'call')

            def on_authorize_success(authorization):
                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorization[u'allow']:
                    reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.NOT_AUTHORIZED, [u"session is not authorized to call procedure '{0}'".format(call.procedure)])
                    self._router.send(session, reply)

                else:
                    self._call(session, call, registration, authorization)

            def on_authorize_error(err):
                """
                the call to authorize the action _itself_ failed (note this is
                different from the call to authorize succeed, but the
                authorization being denied)
                """
                self.log.failure("Authorization of 'call' for '{uri}' failed", uri=call.procedure, failure=err)
                reply = message.Error(
                    message.Call.MESSAGE_TYPE,
                    call.request,
                    ApplicationError.AUTHORIZATION_FAILED,
                    [u"failed to authorize session for calling procedure '{0}': {1}".format(call.procedure, err.value)]
                )
                self._router.send(session, reply)

            txaio.add_callbacks(d, on_authorize_success, on_authorize_error)

        else:
            reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.NO_SUCH_PROCEDURE, [u"no callee registered for procedure <{0}>".format(call.procedure)])
            self._router.send(session, reply)
コード例 #15
0
   def processCall(self, session, call):
      """
      Implements :func:`autobahn.wamp.interfaces.IDealer.processCall`
      """
      assert(session in self._session_to_registrations)

      ## check procedure URI
      ##
      if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(call.procedure)) or \
         (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(call.procedure)):

         reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.INVALID_URI, ["call with invalid procedure URI '{0}'".format(call.procedure)])
         session._transport.send(reply)

      else:

         if call.procedure in self._procs_to_regs:

            ## validate payload
            ##
            try:
               self._router.validate('call', call.procedure, call.args, call.kwargs)
            except Exception as e:
               reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.INVALID_ARGUMENT, ["call of procedure '{0}' with invalid application payload: {1}".format(call.procedure, e)])
               session._transport.send(reply)
               return

            ## authorize action
            ##
            d = self._as_future(self._router.authorize, session, call.procedure, IRouter.ACTION_CALL)

            def on_authorize_success(authorized):
               if authorized:
                  registration_id, endpoint_session, discloseCaller, discloseCallerTransport = self._procs_to_regs[call.procedure]

                  request_id = util.id()

                  if discloseCaller or call.discloseMe:
                     caller = session._session_id
                     caller_transport = None
                     authid = session._authid
                     authrole = session._authrole
                     authmethod = session._authmethod
                     if discloseCallerTransport and hasattr(session._transport, '_transport_info'):
                        caller_transport = session._transport._transport_info
                  else:
                     caller = None
                     caller_transport = None
                     authid = None
                     authrole = None
                     authmethod = None

                  invocation = message.Invocation(request_id,
                                                  registration_id,
                                                  args = call.args,
                                                  kwargs = call.kwargs,
                                                  timeout = call.timeout,
                                                  receive_progress = call.receive_progress,
                                                  caller = caller,
                                                  caller_transport = caller_transport,
                                                  authid = authid,
                                                  authrole = authrole,
                                                  authmethod = authmethod)

                  self._invocations[request_id] = (call, session)
                  endpoint_session._transport.send(invocation)
               else:
                  reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.NOT_AUTHORIZED, ["session is not authorized to call procedure '{0}'".format(call.procedure)])
                  session._transport.send(reply)                 

            def on_authorize_error(err):
               reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.AUTHORIZATION_FAILED, ["failed to authorize session for calling procedure '{0}': {1}".format(call.procedure, err.value)])
               session._transport.send(reply)

            self._add_future_callbacks(d, on_authorize_success, on_authorize_error)

         else:
            reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.NO_SUCH_PROCEDURE, ["no procedure '{0}' registered".format(call.procedure)])
            session._transport.send(reply)
コード例 #16
0
    def processSubscribe(self, session, subscribe):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processSubscribe`
        """
        if self._router.is_traced:
            if not subscribe.correlation_id:
                subscribe.correlation_id = self._router.new_correlation_id()
                subscribe.correlation_is_anchor = True
                subscribe.correlation_is_last = False
            if not subscribe.correlation_uri:
                subscribe.correlation_uri = subscribe.topic

        # check topic URI: for SUBSCRIBE, must be valid URI (either strict or loose), and all
        # URI components must be non-empty for normal subscriptions, may be empty for
        # wildcard subscriptions and must be non-empty for all but the last component for
        # prefix subscriptions
        #
        if self._option_uri_strict:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_STRICT_EMPTY.match(subscribe.topic)
            elif subscribe.match == u"prefix":
                uri_is_valid = _URI_PAT_STRICT_LAST_EMPTY.match(
                    subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(subscribe.topic)
        else:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_LOOSE_EMPTY.match(subscribe.topic)
            elif subscribe.match == u"prefix":
                uri_is_valid = _URI_PAT_LOOSE_LAST_EMPTY.match(subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(subscribe.topic)

        if not uri_is_valid:
            reply = message.Error(
                message.Subscribe.MESSAGE_TYPE, subscribe.request,
                ApplicationError.INVALID_URI, [
                    u"subscribe for invalid topic URI '{0}'".format(
                        subscribe.topic)
                ])
            reply.correlation_id = subscribe.correlation_id
            reply.correlation_uri = subscribe.topic
            reply.correlation_is_anchor = False
            reply.correlation_is_last = True
            self._router.send(session, reply)
            return

        # authorize SUBSCRIBE action
        #
        d = self._router.authorize(session,
                                   subscribe.topic,
                                   u'subscribe',
                                   options=subscribe.marshal_options())

        def on_authorize_success(authorization):
            if not authorization[u'allow']:
                # error reply since session is not authorized to subscribe
                #
                replies = [
                    message.Error(
                        message.Subscribe.MESSAGE_TYPE, subscribe.request,
                        ApplicationError.NOT_AUTHORIZED, [
                            u"session is not authorized to subscribe to topic '{0}'"
                            .format(subscribe.topic)
                        ])
                ]
                replies[0].correlation_id = subscribe.correlation_id
                replies[0].correlation_uri = subscribe.topic
                replies[0].correlation_is_anchor = False
                replies[0].correlation_is_last = True

            else:
                # ok, session authorized to subscribe. now get the subscription
                #
                subscription, was_already_subscribed, is_first_subscriber = self._subscription_map.add_observer(
                    session,
                    subscribe.topic,
                    subscribe.match,
                    extra=SubscriptionExtra())

                if not was_already_subscribed:
                    self._session_to_subscriptions[session].add(subscription)

                # publish WAMP meta events, if we have a service session, but
                # not for the meta API itself!
                #
                if self._router._realm and \
                   self._router._realm.session and \
                   not subscription.uri.startswith(u'wamp.') and \
                   (is_first_subscriber or not was_already_subscribed):

                    has_follow_up_messages = True

                    def _publish():
                        service_session = self._router._realm.session
                        options = types.PublishOptions(
                            correlation_id=subscribe.correlation_id,
                            correlation_is_anchor=False,
                            correlation_is_last=False,
                        )
                        if is_first_subscriber:
                            subscription_details = {
                                u'id': subscription.id,
                                u'created': subscription.created,
                                u'uri': subscription.uri,
                                u'match': subscription.match,
                            }
                            service_session.publish(
                                u'wamp.subscription.on_create',
                                session._session_id,
                                subscription_details,
                                options=options,
                            )
                        if not was_already_subscribed:
                            options.correlation_is_last = True
                            service_session.publish(
                                u'wamp.subscription.on_subscribe',
                                session._session_id,
                                subscription.id,
                                options=options,
                            )

                    # we postpone actual sending of meta events until we return to this client session
                    self._reactor.callLater(0, _publish)

                else:
                    has_follow_up_messages = False

                # check for retained events
                #
                def _get_retained_event():

                    if subscription.extra.retained_events:
                        retained_events = list(
                            subscription.extra.retained_events)
                        retained_events.reverse()

                        for retained_event in retained_events:
                            authorized = False

                            if not retained_event.publish.exclude and not retained_event.publish.eligible:
                                authorized = True
                            elif session._session_id in retained_event.publish.eligible and session._session_id not in retained_event.publish.exclude:
                                authorized = True

                            if authorized:
                                publication = util.id()

                                if retained_event.publish.payload:
                                    msg = message.Event(
                                        subscription.id,
                                        publication,
                                        payload=retained_event.publish.payload,
                                        enc_algo=retained_event.publish.
                                        enc_algo,
                                        enc_key=retained_event.publish.enc_key,
                                        enc_serializer=retained_event.publish.
                                        enc_serializer,
                                        publisher=retained_event.publisher,
                                        publisher_authid=retained_event.
                                        publisher_authid,
                                        publisher_authrole=retained_event.
                                        publisher_authrole,
                                        retained=True)
                                else:
                                    msg = message.Event(
                                        subscription.id,
                                        publication,
                                        args=retained_event.publish.args,
                                        kwargs=retained_event.publish.kwargs,
                                        publisher=retained_event.publisher,
                                        publisher_authid=retained_event.
                                        publisher_authid,
                                        publisher_authrole=retained_event.
                                        publisher_authrole,
                                        retained=True)

                                msg.correlation_id = subscribe.correlation_id
                                msg.correlation_uri = subscribe.topic
                                msg.correlation_is_anchor = False
                                msg.correlation_is_last = False

                                return [msg]
                    return []

                # acknowledge subscribe with subscription ID
                #
                replies = [
                    message.Subscribed(subscribe.request, subscription.id)
                ]
                replies[0].correlation_id = subscribe.correlation_id
                replies[0].correlation_uri = subscribe.topic
                replies[0].correlation_is_anchor = False
                replies[0].correlation_is_last = False
                if subscribe.get_retained:
                    replies.extend(_get_retained_event())

                replies[-1].correlation_is_last = not has_follow_up_messages

            # send out reply to subscribe requestor
            #
            [self._router.send(session, reply) for reply in replies]

        def on_authorize_error(err):
            """
            the call to authorize the action _itself_ failed (note this is
            different from the call to authorize succeed, but the
            authorization being denied)
            """
            self.log.failure("Authorization of 'subscribe' for '{uri}' failed",
                             uri=subscribe.topic,
                             failure=err)
            reply = message.Error(
                message.Subscribe.MESSAGE_TYPE, subscribe.request,
                ApplicationError.AUTHORIZATION_FAILED, [
                    u"failed to authorize session for subscribing to topic URI '{0}': {1}"
                    .format(subscribe.topic, err.value)
                ])
            reply.correlation_id = subscribe.correlation_id
            reply.correlation_uri = subscribe.topic
            reply.correlation_is_anchor = False
            reply.correlation_is_last = True
            self._router.send(session, reply)

        txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #17
0
    def processSubscribe(self, session, subscribe):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processSubscribe`
        """
        # check topic URI: for SUBSCRIBE, must be valid URI (either strict or loose), and all
        # URI components must be non-empty for normal subscriptions, may be empty for
        # wildcard subscriptions and must be non-empty for all but the last component for
        # prefix subscriptions
        #
        if self._option_uri_strict:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_STRICT_EMPTY.match(subscribe.topic)
            elif subscribe.match == u"prefix":
                uri_is_valid = _URI_PAT_STRICT_LAST_EMPTY.match(
                    subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(subscribe.topic)
        else:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_LOOSE_EMPTY.match(subscribe.topic)
            elif subscribe.match == u"prefix":
                uri_is_valid = _URI_PAT_LOOSE_LAST_EMPTY.match(subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(subscribe.topic)

        if not uri_is_valid:
            reply = message.Error(
                message.Subscribe.MESSAGE_TYPE, subscribe.request,
                ApplicationError.INVALID_URI, [
                    u"subscribe for invalid topic URI '{0}'".format(
                        subscribe.topic)
                ])
            self._router.send(session, reply)
            return

        # authorize SUBSCRIBE action
        #
        d = self._router.authorize(session, subscribe.topic, u'subscribe')

        def on_authorize_success(authorization):
            if not authorization[u'allow']:
                # error reply since session is not authorized to subscribe
                #
                reply = message.Error(
                    message.Subscribe.MESSAGE_TYPE, subscribe.request,
                    ApplicationError.NOT_AUTHORIZED, [
                        u"session is not authorized to subscribe to topic '{0}'"
                        .format(subscribe.topic)
                    ])

            else:
                # ok, session authorized to subscribe. now get the subscription
                #
                subscription, was_already_subscribed, is_first_subscriber = self._subscription_map.add_observer(
                    session, subscribe.topic, subscribe.match)

                if not was_already_subscribed:
                    self._session_to_subscriptions[session].add(subscription)

                # publish WAMP meta events
                #
                if self._router._realm:
                    service_session = self._router._realm.session
                    if service_session and not subscription.uri.startswith(
                            u'wamp.'):
                        if is_first_subscriber:
                            subscription_details = {
                                u'id': subscription.id,
                                u'created': subscription.created,
                                u'uri': subscription.uri,
                                u'match': subscription.match,
                            }
                            service_session.publish(
                                u'wamp.subscription.on_create',
                                session._session_id, subscription_details)
                        if not was_already_subscribed:
                            service_session.publish(
                                u'wamp.subscription.on_subscribe',
                                session._session_id, subscription.id)

                # acknowledge subscribe with subscription ID
                #
                reply = message.Subscribed(subscribe.request, subscription.id)

            # send out reply to subscribe requestor
            #
            self._router.send(session, reply)

        def on_authorize_error(err):
            """
            the call to authorize the action _itself_ failed (note this is
            different from the call to authorize succeed, but the
            authorization being denied)
            """
            # XXX same as another code-block, can we collapse?
            self.log.failure(err)
            reply = message.Error(
                message.Subscribe.MESSAGE_TYPE, subscribe.request,
                ApplicationError.AUTHORIZATION_FAILED, [
                    u"failed to authorize session for subscribing to topic URI '{0}': {1}"
                    .format(subscribe.topic, err.value)
                ])
            self._router.send(session, reply)

        txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #18
0
    def processRegister(self, session, register):
        """
        Implements :func:`crossbar.router.interfaces.IDealer.processRegister`
        """
        # check topic URI: for SUBSCRIBE, must be valid URI (either strict or loose), and all
        # URI components must be non-empty other than for wildcard subscriptions
        #
        if self._option_uri_strict:
            if register.match == u"wildcard":
                uri_is_valid = _URI_PAT_STRICT_EMPTY.match(register.procedure)
            elif register.match == u"prefix":
                uri_is_valid = _URI_PAT_STRICT_LAST_EMPTY.match(
                    register.procedure)
            elif register.match == u"exact":
                uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(
                    register.procedure)
            else:
                # should not arrive here
                raise Exception("logic error")
        else:
            if register.match == u"wildcard":
                uri_is_valid = _URI_PAT_LOOSE_EMPTY.match(register.procedure)
            elif register.match == u"prefix":
                uri_is_valid = _URI_PAT_LOOSE_LAST_EMPTY.match(
                    register.procedure)
            elif register.match == u"exact":
                uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(
                    register.procedure)
            else:
                # should not arrive here
                raise Exception("logic error")

        if not uri_is_valid:
            reply = message.Error(
                message.Register.MESSAGE_TYPE, register.request,
                ApplicationError.INVALID_URI, [
                    u"register for invalid procedure URI '{0}' (URI strict checking {1})"
                    .format(register.procedure, self._option_uri_strict)
                ])
            self._router.send(session, reply)
            return

        # disallow registration of procedures starting with "wamp." other than for
        # trusted sessions (that are sessions built into Crossbar.io routing core)
        #
        if session._authrole is not None and session._authrole != u"trusted":
            is_restricted = register.procedure.startswith(u"wamp.")
            if is_restricted:
                reply = message.Error(
                    message.Register.MESSAGE_TYPE, register.request,
                    ApplicationError.INVALID_URI, [
                        u"register for restricted procedure URI '{0}')".format(
                            register.procedure)
                    ])
                self._router.send(session, reply)
                return

        # get existing registration for procedure / matching strategy - if any
        #
        registration = self._registration_map.get_observation(
            register.procedure, register.match)
        if registration:

            # there is an existing registration, and that has an invocation strategy that only allows a single callee
            # on a the given registration
            #
            if registration.extra.invoke == message.Register.INVOKE_SINGLE:
                reply = message.Error(
                    message.Register.MESSAGE_TYPE, register.request,
                    ApplicationError.PROCEDURE_ALREADY_EXISTS, [
                        u"register for already registered procedure '{0}'".
                        format(register.procedure)
                    ])
                self._router.send(session, reply)
                return

            # there is an existing registration, and that has an invokation strategy different from the one
            # requested by the new callee
            #
            if registration.extra.invoke != register.invoke:
                reply = message.Error(
                    message.Register.MESSAGE_TYPE, register.request,
                    ApplicationError.
                    PROCEDURE_EXISTS_INVOCATION_POLICY_CONFLICT, [
                        u"register for already registered procedure '{0}' with conflicting invocation policy (has {1} and {2} was requested)"
                        .format(register.procedure, registration.extra.invoke,
                                register.invoke)
                    ])
                self._router.send(session, reply)
                return

        # authorize REGISTER action
        #
        d = self._router.authorize(session,
                                   register.procedure,
                                   u'register',
                                   options=register.marshal_options())

        def on_authorize_success(authorization):
            if not authorization[u'allow']:
                # error reply since session is not authorized to register
                #
                reply = message.Error(
                    message.Register.MESSAGE_TYPE, register.request,
                    ApplicationError.NOT_AUTHORIZED, [
                        u"session is not authorized to register procedure '{0}'"
                        .format(register.procedure)
                    ])

            else:
                # ok, session authorized to register. now get the registration
                #
                registration_extra = RegistrationExtra(register.invoke)
                registration_callee_extra = RegistrationCalleeExtra(
                    register.concurrency)
                registration, was_already_registered, is_first_callee = self._registration_map.add_observer(
                    session, register.procedure, register.match,
                    registration_extra, registration_callee_extra)

                if not was_already_registered:
                    self._session_to_registrations[session].add(registration)

                # publish WAMP meta events
                #
                if self._router._realm:
                    service_session = self._router._realm.session
                    if service_session and not registration.uri.startswith(
                            u'wamp.'):
                        if is_first_callee:
                            registration_details = {
                                u'id': registration.id,
                                u'created': registration.created,
                                u'uri': registration.uri,
                                u'match': registration.match,
                                u'invoke': registration.extra.invoke,
                            }
                            service_session.publish(
                                u'wamp.registration.on_create',
                                session._session_id, registration_details)
                        if not was_already_registered:
                            service_session.publish(
                                u'wamp.registration.on_register',
                                session._session_id, registration.id)

                # acknowledge register with registration ID
                #
                reply = message.Registered(register.request, registration.id)

            # send out reply to register requestor
            #
            self._router.send(session, reply)

        def on_authorize_error(err):
            """
            the call to authorize the action _itself_ failed (note this is
            different from the call to authorize succeed, but the
            authorization being denied)
            """
            self.log.failure("Authorization of 'register' for '{uri}' failed",
                             uri=register.procedure,
                             failure=err)
            reply = message.Error(
                message.Register.MESSAGE_TYPE, register.request,
                ApplicationError.AUTHORIZATION_FAILED, [
                    u"failed to authorize session for registering procedure '{0}': {1}"
                    .format(register.procedure, err.value)
                ])
            self._router.send(session, reply)

        txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #19
0
ファイル: dealer.py プロジェクト: abhimanyu-siwach/crossbar
    def processRegister(self, session, register):
        """
        Implements :func:`crossbar.router.interfaces.IDealer.processRegister`
        """
        # check topic URI: for SUBSCRIBE, must be valid URI (either strict or loose), and all
        # URI components must be non-empty other than for wildcard subscriptions
        #
        if self._option_uri_strict:
            if register.match == u"wildcard":
                uri_is_valid = _URI_PAT_STRICT_EMPTY.match(register.procedure)
            else:
                uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(register.procedure)
        else:
            if register.match == u"wildcard":
                uri_is_valid = _URI_PAT_LOOSE_EMPTY.match(register.procedure)
            else:
                uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(register.procedure)

        if not uri_is_valid:
            reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.INVALID_URI, [u"register for invalid procedure URI '{0}' (URI strict checking {1})".format(register.procedure, self._option_uri_strict)])
            self._router.send(session, reply)
            return

        # disallow registration of procedures starting with "wamp." and  "crossbar." other than for
        # trusted sessions (that are sessions built into Crossbar.io)
        #
        if session._authrole is not None and session._authrole != u"trusted":
            is_restricted = register.procedure.startswith(u"wamp.") or register.procedure.startswith(u"crossbar.")
            if is_restricted:
                reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.INVALID_URI, [u"register for restricted procedure URI '{0}')".format(register.procedure)])
                self._router.send(session, reply)
                return

        # get existing registration for procedure / matching strategy - if any
        #
        registration = self._registration_map.get_observation(register.procedure, register.match)
        if registration:

            # there is an existing registration, and that has an invocation strategy that only allows a single callee
            # on a the given registration
            #
            if registration.extra.invoke == message.Register.INVOKE_SINGLE:
                reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.PROCEDURE_ALREADY_EXISTS, [u"register for already registered procedure '{0}'".format(register.procedure)])
                self._router.send(session, reply)
                return

            # there is an existing registration, and that has an invokation strategy different from the one
            # requested by the new callee
            #
            if registration.extra.invoke != register.invoke:
                reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.PROCEDURE_EXISTS_INVOCATION_POLICY_CONFLICT, [u"register for already registered procedure '{0}' with conflicting invocation policy (has {1} and {2} was requested)".format(register.procedure, registration.extra.invoke, register.invoke)])
                self._router.send(session, reply)
                return

        # authorize action
        #
        d = txaio.as_future(self._router.authorize, session, register.procedure, RouterAction.ACTION_REGISTER)

        def on_authorize_success(authorized):
            if not authorized:
                # error reply since session is not authorized to register
                #
                reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.NOT_AUTHORIZED, [u"session is not authorized to register procedure '{0}'".format(register.procedure)])

            else:
                # ok, session authorized to register. now get the registration
                #
                registration_extra = RegistrationExtra(register.invoke)
                registration, was_already_registered, is_first_callee = self._registration_map.add_observer(session, register.procedure, register.match, registration_extra)

                if not was_already_registered:
                    self._session_to_registrations[session].add(registration)

                # publish WAMP meta events
                #
                if self._router._realm:
                    service_session = self._router._realm.session
                    if service_session and not registration.uri.startswith(u'wamp.'):
                        if is_first_callee:
                            registration_details = {
                                'id': registration.id,
                                'created': registration.created,
                                'uri': registration.uri,
                                'match': registration.match,
                                'invoke': registration.extra.invoke,
                            }
                            service_session.publish(u'wamp.registration.on_create', session._session_id, registration_details)
                        if not was_already_registered:
                            service_session.publish(u'wamp.registration.on_register', session._session_id, registration.id)

                # acknowledge register with registration ID
                #
                reply = message.Registered(register.request, registration.id)

            # send out reply to register requestor
            #
            self._router.send(session, reply)

        def on_authorize_error(err):
            """
            the call to authorize the action _itself_ failed (note this is
            different from the call to authorize succeed, but the
            authorization being denied)
            """
            self.log.failure(err)
            reply = message.Error(
                message.Register.MESSAGE_TYPE,
                register.request,
                ApplicationError.AUTHORIZATION_FAILED,
                [u"failed to authorize session for registering procedure '{0}': {1}".format(register.procedure, err.value)]
            )
            self._router.send(session, reply)

        txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #20
0
ファイル: broker.py プロジェクト: cosmospham/crossbar
    def processPublish(self, session, publish):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processPublish`
        """
        # check topic URI: for PUBLISH, must be valid URI (either strict or loose), and
        # all URI components must be non-empty
        if self._option_uri_strict:
            uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(publish.topic)
        else:
            uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(publish.topic)

        if not uri_is_valid:
            if publish.acknowledge:
                reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_URI, [u"publish with invalid topic URI '{0}' (URI strict checking {1})".format(publish.topic, self._option_uri_strict)])
                session._transport.send(reply)
            return

        # disallow publication to topics starting with "wamp." and
        # "crossbar." other than for trusted session (that are sessions
        # built into Crossbar.io)
        if session._authrole is not None and session._authrole != u"trusted":
            if publish.topic.startswith(u"wamp.") or publish.topic.startswith(u"crossbar."):
                if publish.acknowledge:
                    reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_URI, [u"publish with restricted topic URI '{0}'".format(publish.topic)])
                    session._transport.send(reply)
                return

        # get subscriptions active on the topic published to
        #
        subscriptions = self._subscription_map.match_observations(publish.topic)

        # go on if there are any active subscriptions or the publish is to be acknowledged
        # otherwise there isn't anything to do anyway.
        #
        if subscriptions or publish.acknowledge:

            # validate payload
            #
            try:
                self._router.validate('event', publish.topic, publish.args, publish.kwargs)
            except Exception as e:
                if publish.acknowledge:
                    reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_ARGUMENT, [u"publish to topic URI '{0}' with invalid application payload: {1}".format(publish.topic, e)])
                    session._transport.send(reply)
                return

            # authorize PUBLISH action
            #
            d = txaio.as_future(self._router.authorize, session, publish.topic, RouterAction.ACTION_PUBLISH)

            def on_authorize_success(authorized):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorized:

                    if publish.acknowledge:
                        reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.NOT_AUTHORIZED, [u"session not authorized to publish to topic '{0}'".format(publish.topic)])
                        session._transport.send(reply)

                else:

                    # new ID for the publication
                    #
                    publication = util.id()

                    # send publish acknowledge immediately when requested
                    #
                    if publish.acknowledge:
                        msg = message.Published(publish.request, publication)
                        session._transport.send(msg)

                    # publisher disclosure
                    #
                    if publish.disclose_me:
                        publisher = session._session_id
                    else:
                        publisher = None

                    # skip publisher
                    #
                    if publish.exclude_me is None or publish.exclude_me:
                        me_also = False
                    else:
                        me_also = True

                    # iterate over all subscriptions ..
                    #
                    for subscription in subscriptions:

                        # initial list of receivers are all subscribers on a subscription ..
                        #
                        receivers = subscription.observers

                        # filter by "eligible" receivers
                        #
                        if publish.eligible:

                            # map eligible session IDs to eligible sessions
                            eligible = []
                            for session_id in publish.eligible:
                                if session_id in self._router._session_id_to_session:
                                    eligible.append(self._router._session_id_to_session[session_id])

                            # filter receivers for eligible sessions
                            receivers = set(eligible) & receivers

                        # remove "excluded" receivers
                        #
                        if publish.exclude:

                            # map excluded session IDs to excluded sessions
                            exclude = []
                            for s in publish.exclude:
                                if s in self._router._session_id_to_session:
                                    exclude.append(self._router._session_id_to_session[s])

                            # filter receivers for excluded sessions
                            if exclude:
                                receivers = receivers - set(exclude)

                        # if receivers is non-empty, dispatch event ..
                        #
                        if receivers:

                            # for pattern-based subscriptions, the EVENT must contain
                            # the actual topic being published to
                            #
                            if subscription.match != message.Subscribe.MATCH_EXACT:
                                topic = publish.topic
                            else:
                                topic = None

                            msg = message.Event(subscription.id,
                                                publication,
                                                args=publish.args,
                                                kwargs=publish.kwargs,
                                                publisher=publisher,
                                                topic=topic)
                            for receiver in receivers:
                                if me_also or receiver != session:
                                    # the receiving subscriber session might have been lost in the meantime ..
                                    if receiver._transport:
                                        receiver._transport.send(msg)

            def on_authorize_error(err):
                """
                the call to authorize the action _itself_ failed (note this is
                different from the call to authorize succeed, but the
                authorization being denied)
                """
                self.log.failure(err)
                if publish.acknowledge:
                    reply = message.Error(
                        message.Publish.MESSAGE_TYPE,
                        publish.request,
                        ApplicationError.AUTHORIZATION_FAILED,
                        [u"failed to authorize session for publishing to topic URI '{0}': {1}".format(publish.topic, err.value)]
                    )
                    session._transport.send(reply)

            txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #21
0
ファイル: broker.py プロジェクト: rvdmei/crossbar
    def processPublish(self, session, publish):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processPublish`
        """
        # check topic URI: for PUBLISH, must be valid URI (either strict or loose), and
        # all URI components must be non-empty
        if self._option_uri_strict:
            uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(publish.topic)
        else:
            uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(publish.topic)

        if not uri_is_valid:
            if publish.acknowledge:
                reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_URI, [u"publish with invalid topic URI '{0}' (URI strict checking {1})".format(publish.topic, self._option_uri_strict)])
                self._router.send(session, reply)
            return

        # disallow publication to topics starting with "wamp." and "crossbar." other than for
        # trusted sessions (that are sessions built into Crossbar.io)
        #
        if session._authrole is not None and session._authrole != u"trusted":
            is_restricted = publish.topic.startswith(u"wamp.") or publish.topic.startswith(u"crossbar.")
            if is_restricted:
                if publish.acknowledge:
                    reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_URI, [u"publish with restricted topic URI '{0}'".format(publish.topic)])
                    self._router.send(session, reply)
                return

        # get subscriptions active on the topic published to
        #
        subscriptions = self._subscription_map.match_observations(publish.topic)

        # check if the event is being persisted by checking if we ourself are among the observers
        # on _any_ matching subscription
        # we've been previously added to observer lists on subscriptions ultimately from
        # node configuration and during the broker starts up.
        store_event = False
        if self._event_store:
            for subscription in subscriptions:
                if self._event_store in subscription.observers:
                    store_event = True
                    break
        if store_event:
            self.log.debug('Persisting event on topic "{topic}"', topic=publish.topic)

        # check if the event is to be retained by inspecting the 'retain' flag
        retain_event = False
        if publish.retain:
            retain_event = True

        # go on if (otherwise there isn't anything to do anyway):
        #
        #   - there are any active subscriptions OR
        #   - the publish is to be acknowledged OR
        #   - the event is to be persisted OR
        #   - the event is to be retained
        #
        if subscriptions or publish.acknowledge or store_event or retain_event:

            # If it's a MQTT publish, we need to adjust the arguments.
            if getattr(publish, "_mqtt_publish", False):
                from crossbar.adapter.mqtt.wamp import mqtt_payload_transform
                tfd = mqtt_payload_transform(self._router._mqtt_payload_format,
                                             publish.payload)

                if not tfd:
                    # If we have no message to give, drop it entirely
                    return
                else:
                    publish.payload = None
                    publish.args, publish.kwargs = tfd

            # validate payload
            #
            if publish.payload is None:
                try:
                    self._router.validate('event', publish.topic, publish.args, publish.kwargs)
                except Exception as e:
                    if publish.acknowledge:
                        reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_ARGUMENT, [u"publish to topic URI '{0}' with invalid application payload: {1}".format(publish.topic, e)])
                        self._router.send(session, reply)
                    return

            # authorize PUBLISH action
            #
            d = self._router.authorize(session, publish.topic, u'publish')

            def on_authorize_success(authorization):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorization[u'allow']:

                    if publish.acknowledge:
                        reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.NOT_AUTHORIZED, [u"session not authorized to publish to topic '{0}'".format(publish.topic)])
                        self._router.send(session, reply)

                else:

                    # new ID for the publication
                    #
                    publication = util.id()

                    # persist event (this is done only once, regardless of the number of subscriptions
                    # the event matches on)
                    #
                    if store_event:
                        self._event_store.store_event(session._session_id, publication, publish.topic, publish.args, publish.kwargs)

                    # retain event on the topic
                    #
                    if retain_event:
                        observation = self._subscription_map.get_observation(publish.topic)

                        if not observation:
                            # No observation, lets make a new one
                            observation = self._subscription_map.create_observation(publish.topic, extra=SubscriptionExtra())

                        if observation.extra.retained_events:
                            if not publish.eligible and not publish.exclude:
                                observation.extra.retained_events = [publish]
                            else:
                                observation.extra.retained_events.append(publish)
                        else:
                            observation.extra.retained_events = [publish]

                    # send publish acknowledge immediately when requested
                    #
                    if publish.acknowledge:
                        reply = message.Published(publish.request, publication)
                        self._router.send(session, reply)

                    # publisher disclosure
                    #
                    if authorization[u'disclose']:
                        disclose = True
                    elif (publish.topic.startswith(u"wamp.") or
                          publish.topic.startswith(u"crossbar.")):
                        disclose = True
                    else:
                        disclose = False

                    if disclose:
                        publisher = session._session_id
                        publisher_authid = session._authid
                        publisher_authrole = session._authrole
                    else:
                        publisher = None
                        publisher_authid = None
                        publisher_authrole = None

                    # skip publisher
                    #
                    if publish.exclude_me is None or publish.exclude_me:
                        me_also = False
                    else:
                        me_also = True

                    # iterate over all subscriptions ..
                    #
                    for subscription in subscriptions:

                        # persist event history, but check if it is persisted on the individual subscription!
                        #
                        if store_event and self._event_store in subscription.observers:
                            self._event_store.store_event_history(publication, subscription.id)

                        # initial list of receivers are all subscribers on a subscription ..
                        #
                        receivers = subscription.observers

                        # filter by "eligible" receivers
                        #
                        if publish.eligible:

                            # map eligible session IDs to eligible sessions
                            eligible = []
                            for session_id in publish.eligible:
                                if session_id in self._router._session_id_to_session:
                                    eligible.append(self._router._session_id_to_session[session_id])

                            # filter receivers for eligible sessions
                            receivers = set(eligible) & receivers

                        # remove "excluded" receivers
                        #
                        if publish.exclude:

                            # map excluded session IDs to excluded sessions
                            exclude = []
                            for s in publish.exclude:
                                if s in self._router._session_id_to_session:
                                    exclude.append(self._router._session_id_to_session[s])

                            # filter receivers for excluded sessions
                            if exclude:
                                receivers = receivers - set(exclude)

                        # if receivers is non-empty, dispatch event ..
                        #
                        receivers_cnt = len(receivers) - (1 if self in receivers else 0)
                        if receivers_cnt:

                            # for pattern-based subscriptions, the EVENT must contain
                            # the actual topic being published to
                            #
                            if subscription.match != message.Subscribe.MATCH_EXACT:
                                topic = publish.topic
                            else:
                                topic = None

                            if publish.payload:
                                msg = message.Event(subscription.id,
                                                    publication,
                                                    payload=publish.payload,
                                                    publisher=publisher,
                                                    publisher_authid=publisher_authid,
                                                    publisher_authrole=publisher_authrole,
                                                    topic=topic,
                                                    enc_algo=publish.enc_algo,
                                                    enc_key=publish.enc_key,
                                                    enc_serializer=publish.enc_serializer)
                            else:
                                msg = message.Event(subscription.id,
                                                    publication,
                                                    args=publish.args,
                                                    kwargs=publish.kwargs,
                                                    publisher=publisher,
                                                    publisher_authid=publisher_authid,
                                                    publisher_authrole=publisher_authrole,
                                                    topic=topic)
                            for receiver in receivers:
                                if (me_also or receiver != session) and receiver != self._event_store:
                                    # the receiving subscriber session
                                    # might have no transport, or no
                                    # longer be joined
                                    if receiver._session_id and receiver._transport:
                                        self._router.send(receiver, msg)

            def on_authorize_error(err):
                """
                the call to authorize the action _itself_ failed (note this is
                different from the call to authorize succeed, but the
                authorization being denied)
                """
                self.log.failure("Authorization failed", failure=err)
                if publish.acknowledge:
                    reply = message.Error(
                        message.Publish.MESSAGE_TYPE,
                        publish.request,
                        ApplicationError.AUTHORIZATION_FAILED,
                        [u"failed to authorize session for publishing to topic URI '{0}': {1}".format(publish.topic, err.value)]
                    )
                    self._router.send(session, reply)

            txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #22
0
ファイル: broker.py プロジェクト: pavlenko-volodymyr/crossbar
    def processSubscribe(self, session, subscribe):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processSubscribe`
        """
        # check topic URI: for SUBSCRIBE, must be valid URI (either strict or loose), and all
        # URI components must be non-empty other than for wildcard subscriptions
        #
        if self._option_uri_strict:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_STRICT_EMPTY.match(subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(subscribe.topic)
        else:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_LOOSE_EMPTY.match(subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(subscribe.topic)

        if not uri_is_valid:
            reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.INVALID_URI, ["subscribe for invalid topic URI '{0}'".format(subscribe.topic)])
            session._transport.send(reply)
            return

        # authorize action
        #
        d = self._as_future(self._router.authorize, session, subscribe.topic, IRouter.ACTION_SUBSCRIBE)

        def on_authorize_success(authorized):
            if not authorized:
                # error reply since session is not authorized to subscribe
                #
                reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.NOT_AUTHORIZED, ["session is not authorized to subscribe to topic '{0}'".format(subscribe.topic)])

            else:
                # ok, session authorized to subscribe. now get the subscription
                #
                subscription, was_already_subscribed, is_first_subscriber = self._subscription_map.add_observer(session, subscribe.topic, subscribe.match)

                if not was_already_subscribed:
                    self._session_to_subscriptions[session].add(subscription)

                # publish WAMP meta events
                #
                if self._router._realm:
                    service_session = self._router._realm.session
                    if service_session and not subscription.uri.startswith(u'wamp.'):
                        if is_first_subscriber:
                            subscription_details = {
                                'id': subscription.id,
                                'created': subscription.created,
                                'uri': subscription.uri,
                                'match': subscription.match,
                            }
                            service_session.publish(u'wamp.subscription.on_create', session._session_id, subscription_details)
                        if not was_already_subscribed:
                            service_session.publish(u'wamp.subscription.on_subscribe', session._session_id, subscription.id)

                # acknowledge subscribe with subscription ID
                #
                reply = message.Subscribed(subscribe.request, subscription.id)

            # send out reply to subscribe requestor
            #
            session._transport.send(reply)

        def on_authorize_error(err):
            # the call to authorize the action _itself_ failed (note this is different from the
            # call to authorize succeed, but the authorization being denied)
            #
            reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.AUTHORIZATION_FAILED, ["failed to authorize session for subscribing to topic URI '{0}': {1}".format(subscribe.topic, err.value)])
            session._transport.send(reply)

        self._add_future_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #23
0
    def processPublish(self, session, publish):
        """
      Implements :func:`autobahn.wamp.interfaces.IBroker.processPublish`
      """
        assert (session in self._session_to_subscriptions)

        ## check topic URI
        ##
        if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(publish.topic)) or \
           (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(publish.topic)):

            if publish.acknowledge:
                reply = message.Error(
                    message.Publish.MESSAGE_TYPE, publish.request,
                    ApplicationError.INVALID_URI, [
                        "publish with invalid topic URI '{}'".format(
                            publish.topic)
                    ])
                session._transport.send(reply)

            return

        if publish.topic in self._topic_to_sessions and self._topic_to_sessions[
                publish.topic]:

            ## initial list of receivers are all subscribers ..
            ##
            subscription, receivers = self._topic_to_sessions[publish.topic]

            ## filter by "eligible" receivers
            ##
            if publish.eligible:
                eligible = []
                for s in publish.eligible:
                    if s in self._session_id_to_session:
                        eligible.append(self._session_id_to_session[s])
                if eligible:
                    receivers = set(eligible) & receivers

            ## remove "excluded" receivers
            ##
            if publish.exclude:
                exclude = []
                for s in publish.exclude:
                    if s in self._session_id_to_session:
                        exclude.append(self._session_id_to_session[s])
                if exclude:
                    receivers = receivers - set(exclude)

            ## remove publisher
            ##
            if publish.excludeMe is None or publish.excludeMe:
                #   receivers.discard(session) # bad: this would modify our actual subscriber list
                me_also = False
            else:
                me_also = True

        else:
            subscription, receivers, me_also = None, [], False

        publication = util.id()

        ## send publish acknowledge when requested
        ##
        if publish.acknowledge:
            msg = message.Published(publish.request, publication)
            session._transport.send(msg)

        ## if receivers is non-empty, dispatch event ..
        ##
        if receivers:
            if publish.discloseMe:
                publisher = session._session_id
            else:
                publisher = None
            msg = message.Event(subscription,
                                publication,
                                args=publish.args,
                                kwargs=publish.kwargs,
                                publisher=publisher)
            for receiver in receivers:
                if me_also or receiver != session:
                    ## the subscribing session might have been lost in the meantime ..
                    if receiver._transport:
                        receiver._transport.send(msg)
コード例 #24
0
ファイル: broker.py プロジェクト: BigSab/AutobahnPython
   def processPublish(self, session, publish):
      """
      Implements :func:`autobahn.wamp.interfaces.IBroker.processPublish`
      """      
      #assert(session in self._session_to_subscriptions)

      ## check topic URI
      ##
      if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(publish.topic)) or \
         (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(publish.topic)):

         if publish.acknowledge:
            reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_URI, ["publish with invalid topic URI '{0}'".format(publish.topic)])
            session._transport.send(reply)

         return

      if publish.topic in self._topic_to_sessions or publish.acknowledge:

         ## validate payload
         ##
         try:
            self._router.validate('event', publish.topic, publish.args, publish.kwargs)
         except Exception as e:
            reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_ARGUMENT, ["publish to topic URI '{0}' with invalid application payload: {1}".format(publish.topic, e)])
            session._transport.send(reply)
            return

         ## authorize action
         ##
         d = self._as_future(self._router.authorize, session, publish.topic, IRouter.ACTION_PUBLISH)

         def on_authorize_success(authorized):

            if not authorized:

               if publish.acknowledge:
                  reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.NOT_AUTHORIZED, ["session not authorized to publish to topic '{0}'".format(publish.topic)])
                  session._transport.send(reply)

            else:

               ## continue processing if either a) there are subscribers to the topic or b) the publish is to be acknowledged
               ##
               if publish.topic in self._topic_to_sessions and self._topic_to_sessions[publish.topic]:

                  ## initial list of receivers are all subscribers ..
                  ##
                  subscription, receivers = self._topic_to_sessions[publish.topic]

                  ## filter by "eligible" receivers
                  ##
                  if publish.eligible:
                     eligible = []
                     for s in publish.eligible:
                        if s in self._session_id_to_session:
                           eligible.append(self._session_id_to_session[s])
                     
                     receivers = set(eligible) & receivers

                  ## remove "excluded" receivers
                  ##
                  if publish.exclude:
                     exclude = []
                     for s in publish.exclude:
                        if s in self._session_id_to_session:
                           exclude.append(self._session_id_to_session[s])
                     if exclude:
                        receivers = receivers - set(exclude)

                  ## remove publisher
                  ##
                  if publish.excludeMe is None or publish.excludeMe:
                  #   receivers.discard(session) # bad: this would modify our actual subscriber list
                     me_also = False
                  else:
                     me_also = True

               else:
                  subscription, receivers, me_also = None, [], False

               publication = util.id()

               ## send publish acknowledge when requested
               ##
               if publish.acknowledge:
                  msg = message.Published(publish.request, publication)
                  session._transport.send(msg)

               ## if receivers is non-empty, dispatch event ..
               ##
               if receivers:
                  if publish.discloseMe:
                     publisher = session._session_id
                  else:
                     publisher = None
                  msg = message.Event(subscription,
                                      publication,
                                      args = publish.args,
                                      kwargs = publish.kwargs,
                                      publisher = publisher)
                  for receiver in receivers:
                     if me_also or receiver != session:
                        ## the subscribing session might have been lost in the meantime ..
                        if receiver._transport:
                           receiver._transport.send(msg)

         def on_authorize_error(err):
            if publish.acknowledge:
               reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.AUTHORIZATION_FAILED, ["failed to authorize session for publishing to topic URI '{0}': {1}".format(publish.topic, err.value)])
               session._transport.send(reply)

         self._add_future_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #25
0
ファイル: broker.py プロジェクト: agronholm/crossbar
    def processPublish(self, session, publish):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processPublish`
        """
        # check topic URI: for PUBLISH, must be valid URI (either strict or loose), and
        # all URI components must be non-empty
        if self._option_uri_strict:
            uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(publish.topic)
        else:
            uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(publish.topic)

        if not uri_is_valid:
            if publish.acknowledge:
                reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_URI, [u"publish with invalid topic URI '{0}' (URI strict checking {1})".format(publish.topic, self._option_uri_strict)])
                self._router.send(session, reply)
            return

        # disallow publication to topics starting with "wamp." and "crossbar." other than for
        # trusted sessions (that are sessions built into Crossbar.io)
        #
        if session._authrole is not None and session._authrole != u"trusted":
            is_restricted = publish.topic.startswith(u"wamp.") or publish.topic.startswith(u"crossbar.")
            if is_restricted:
                if publish.acknowledge:
                    reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_URI, [u"publish with restricted topic URI '{0}'".format(publish.topic)])
                    self._router.send(session, reply)
                return

        # get subscriptions active on the topic published to
        #
        subscriptions = self._subscription_map.match_observations(publish.topic)

        # check if the event is being persisted by checking if we ourself are among the observers
        # on _any_ matching subscription
        # we've been previously added to observer lists on subscriptions ultimately from
        # node configuration and during the broker starts up.
        store_event = False
        if self._event_store:
            for subscription in subscriptions:
                if self._event_store in subscription.observers:
                    store_event = True
                    break
        if store_event:
            self.log.debug('Persisting event on topic "{topic}"', topic=publish.topic)

        # go on if (otherwise there isn't anything to do anyway):
        #
        #   - there are any active subscriptions OR
        #   - the publish is to be acknowledged OR
        #   - the event is to be persisted
        #
        if subscriptions or publish.acknowledge or store_event:

            # validate payload
            #
            if publish.payload is None:
                try:
                    self._router.validate('event', publish.topic, publish.args, publish.kwargs)
                except Exception as e:
                    if publish.acknowledge:
                        reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_ARGUMENT, [u"publish to topic URI '{0}' with invalid application payload: {1}".format(publish.topic, e)])
                        self._router.send(session, reply)
                    return

            # authorize PUBLISH action
            #
            d = self._router.authorize(session, publish.topic, u'publish')

            def on_authorize_success(authorization):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorization[u'allow']:

                    if publish.acknowledge:
                        reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.NOT_AUTHORIZED, [u"session not authorized to publish to topic '{0}'".format(publish.topic)])
                        self._router.send(session, reply)

                else:

                    # new ID for the publication
                    #
                    publication = util.id()

                    # persist event (this is done only once, regardless of the number of subscriptions
                    # the event matches on)
                    #
                    if store_event:
                        self._event_store.store_event(session._session_id, publication, publish.topic, publish.args, publish.kwargs)

                    # send publish acknowledge immediately when requested
                    #
                    if publish.acknowledge:
                        reply = message.Published(publish.request, publication)
                        self._router.send(session, reply)

                    # publisher disclosure
                    #
                    if authorization[u'disclose']:
                        publisher = session._session_id
                        publisher_authid = session._authid
                        publisher_authrole = session._authrole
                    else:
                        publisher = None
                        publisher_authid = None
                        publisher_authrole = None

                    # skip publisher
                    #
                    if publish.exclude_me is None or publish.exclude_me:
                        me_also = False
                    else:
                        me_also = True

                    # iterate over all subscriptions ..
                    #
                    for subscription in subscriptions:

                        # persist event history, but check if it is persisted on the individual subscription!
                        #
                        if store_event and self._event_store in subscription.observers:
                            self._event_store.store_event_history(publication, subscription.id)

                        # initial list of receivers are all subscribers on a subscription ..
                        #
                        receivers = subscription.observers

                        # filter by "eligible" receivers
                        #
                        if publish.eligible:

                            # map eligible session IDs to eligible sessions
                            eligible = []
                            for session_id in publish.eligible:
                                if session_id in self._router._session_id_to_session:
                                    eligible.append(self._router._session_id_to_session[session_id])

                            # filter receivers for eligible sessions
                            receivers = set(eligible) & receivers

                        # remove "excluded" receivers
                        #
                        if publish.exclude:

                            # map excluded session IDs to excluded sessions
                            exclude = []
                            for s in publish.exclude:
                                if s in self._router._session_id_to_session:
                                    exclude.append(self._router._session_id_to_session[s])

                            # filter receivers for excluded sessions
                            if exclude:
                                receivers = receivers - set(exclude)

                        # if receivers is non-empty, dispatch event ..
                        #
                        receivers_cnt = len(receivers) - (1 if self in receivers else 0)
                        if receivers_cnt:

                            # for pattern-based subscriptions, the EVENT must contain
                            # the actual topic being published to
                            #
                            if subscription.match != message.Subscribe.MATCH_EXACT:
                                topic = publish.topic
                            else:
                                topic = None

                            if publish.payload:
                                msg = message.Event(subscription.id,
                                                    publication,
                                                    payload=publish.payload,
                                                    publisher=publisher,
                                                    publisher_authid=publisher_authid,
                                                    publisher_authrole=publisher_authrole,
                                                    topic=topic,
                                                    enc_algo=publish.enc_algo,
                                                    enc_key=publish.enc_key,
                                                    enc_serializer=publish.enc_serializer)
                            else:
                                msg = message.Event(subscription.id,
                                                    publication,
                                                    args=publish.args,
                                                    kwargs=publish.kwargs,
                                                    publisher=publisher,
                                                    publisher_authid=publisher_authid,
                                                    publisher_authrole=publisher_authrole,
                                                    topic=topic)
                            for receiver in receivers:
                                if (me_also or receiver != session) and receiver != self._event_store:
                                    # the receiving subscriber session
                                    # might have no transport, or no
                                    # longer be joined
                                    if receiver._session_id and receiver._transport:
                                        self._router.send(receiver, msg)

            def on_authorize_error(err):
                """
                the call to authorize the action _itself_ failed (note this is
                different from the call to authorize succeed, but the
                authorization being denied)
                """
                self.log.failure("Authorization failed", failure=err)
                if publish.acknowledge:
                    reply = message.Error(
                        message.Publish.MESSAGE_TYPE,
                        publish.request,
                        ApplicationError.AUTHORIZATION_FAILED,
                        [u"failed to authorize session for publishing to topic URI '{0}': {1}".format(publish.topic, err.value)]
                    )
                    self._router.send(session, reply)

            txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #26
0
ファイル: broker.py プロジェクト: crossbario/crossbar
    def processPublish(self, session, publish):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processPublish`
        """
        if self._router.is_traced:
            if not publish.correlation_id:
                publish.correlation_id = self._router.new_correlation_id()
                publish.correlation_is_anchor = True
            if not publish.correlation_uri:
                publish.correlation_uri = publish.topic

        # check topic URI: for PUBLISH, must be valid URI (either strict or loose), and
        # all URI components must be non-empty
        if self._option_uri_strict:
            uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(publish.topic)
        else:
            uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(publish.topic)

        if not uri_is_valid:
            if publish.acknowledge:
                if self._router.is_traced:
                    publish.correlation_is_last = False
                    self._router._factory._worker._maybe_trace_rx_msg(session, publish)

                reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_URI, [u"publish with invalid topic URI '{0}' (URI strict checking {1})".format(publish.topic, self._option_uri_strict)])
                reply.correlation_id = publish.correlation_id
                reply.correlation_uri = publish.topic
                reply.correlation_is_anchor = False
                reply.correlation_is_last = True
                self._router.send(session, reply)

            else:
                if self._router.is_traced:
                    publish.correlation_is_last = True
                    self._router._factory._worker._maybe_trace_rx_msg(session, publish)
            return

        # disallow publication to topics starting with "wamp." other than for
        # trusted sessions (that are sessions built into Crossbar.io routing core)
        #
        if session._authrole is not None and session._authrole != u"trusted":
            is_restricted = publish.topic.startswith(u"wamp.")
            if is_restricted:
                if publish.acknowledge:
                    if self._router.is_traced:
                        publish.correlation_is_last = False
                        self._router._factory._worker._maybe_trace_rx_msg(session, publish)

                    reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_URI, [u"publish with restricted topic URI '{0}'".format(publish.topic)])
                    reply.correlation_id = publish.correlation_id
                    reply.correlation_uri = publish.topic
                    reply.correlation_is_anchor = False
                    reply.correlation_is_last = True
                    self._router.send(session, reply)

                else:
                    if self._router.is_traced:
                        publish.correlation_is_last = True
                        self._router._factory._worker._maybe_trace_rx_msg(session, publish)

                return

        # get subscriptions active on the topic published to
        #
        subscriptions = self._subscription_map.match_observations(publish.topic)

        # check if the event is being persisted by checking if we ourself are among the observers
        # on _any_ matching subscription
        # we've been previously added to observer lists on subscriptions ultimately from
        # node configuration and during the broker starts up.
        store_event = False
        if self._event_store:
            for subscription in subscriptions:
                if self._event_store in subscription.observers:
                    store_event = True
                    break
        if store_event:
            self.log.debug('Persisting event on topic "{topic}"', topic=publish.topic)

        # check if the event is to be retained by inspecting the 'retain' flag
        retain_event = False
        if publish.retain:
            retain_event = True

        # go on if (otherwise there isn't anything to do anyway):
        #
        #   - there are any active subscriptions OR
        #   - the publish is to be acknowledged OR
        #   - the event is to be persisted OR
        #   - the event is to be retained
        #
        if not (subscriptions or publish.acknowledge or store_event or retain_event):

            # the received PUBLISH message is the only one received/sent
            # for this WAMP action, so mark it as "last" (there is another code path below!)
            if self._router.is_traced:
                if publish.correlation_is_last is None:
                    publish.correlation_is_last = True
                self._router._factory._worker._maybe_trace_rx_msg(session, publish)

        else:

            # validate payload
            #
            if publish.payload is None:
                try:
                    self._router.validate('event', publish.topic, publish.args, publish.kwargs)
                except Exception as e:
                    if publish.acknowledge:
                        if self._router.is_traced:
                            publish.correlation_is_last = False
                            self._router._factory._worker._maybe_trace_rx_msg(session, publish)

                        reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_ARGUMENT, [u"publish to topic URI '{0}' with invalid application payload: {1}".format(publish.topic, e)])
                        reply.correlation_id = publish.correlation_id
                        reply.correlation_uri = publish.topic
                        reply.correlation_is_anchor = False
                        reply.correlation_is_last = True
                        self._router.send(session, reply)
                    else:
                        if self._router.is_traced:
                            publish.correlation_is_last = True
                            self._router._factory._worker._maybe_trace_rx_msg(session, publish)

                    return

            # authorize PUBLISH action
            #
            d = self._router.authorize(session, publish.topic, u'publish', options=publish.marshal_options())

            def on_authorize_success(authorization):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorization[u'allow']:

                    if publish.acknowledge:
                        if self._router.is_traced:
                            publish.correlation_is_last = False
                            self._router._factory._worker._maybe_trace_rx_msg(session, publish)

                        reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.NOT_AUTHORIZED, [u"session not authorized to publish to topic '{0}'".format(publish.topic)])
                        reply.correlation_id = publish.correlation_id
                        reply.correlation_uri = publish.topic
                        reply.correlation_is_anchor = False
                        reply.correlation_is_last = True
                        self._router.send(session, reply)

                    else:
                        if self._router.is_traced:
                            publish.correlation_is_last = True
                            self._router._factory._worker._maybe_trace_rx_msg(session, publish)

                else:

                    # new ID for the publication
                    #
                    publication = util.id()

                    # publisher disclosure
                    #
                    if authorization[u'disclose']:
                        disclose = True
                    elif (publish.topic.startswith(u"wamp.") or publish.topic.startswith(u"crossbar.")):
                        disclose = True
                    else:
                        disclose = False

                    forward_for = None
                    if disclose:
                        if publish.forward_for:
                            publisher = publish.forward_for[0]['session']
                            publisher_authid = publish.forward_for[0]['authid']
                            publisher_authrole = publish.forward_for[0]['authrole']
                            forward_for = publish.forward_for + [
                                {
                                    'session': session._session_id,
                                    'authid': session._authid,
                                    'authrole': session._authrole,
                                }
                            ]
                        else:
                            publisher = session._session_id
                            publisher_authid = session._authid
                            publisher_authrole = session._authrole
                    else:
                        publisher = None
                        publisher_authid = None
                        publisher_authrole = None

                    # skip publisher
                    #
                    if publish.exclude_me is None or publish.exclude_me:
                        me_also = False
                    else:
                        me_also = True

                    # persist event (this is done only once, regardless of the number of subscriptions
                    # the event matches on)
                    #
                    if store_event:
                        self._event_store.store_event(session, publication, publish)

                    # retain event on the topic
                    #
                    if retain_event:
                        retained_event = RetainedEvent(publish, publisher, publisher_authid, publisher_authrole)

                        observation = self._subscription_map.get_observation(publish.topic)

                        if not observation:
                            # No observation, lets make a new one
                            observation = self._subscription_map.create_observation(publish.topic, extra=SubscriptionExtra())
                        else:
                            # this can happen if event-history is
                            # enabled on the topic: the event-store
                            # creates an observation before any client
                            # could possible hit the code above
                            if observation.extra is None:
                                observation.extra = SubscriptionExtra()
                            elif not isinstance(observation.extra, SubscriptionExtra):
                                raise Exception(
                                    "incorrect 'extra' for '{}'".format(publish.topic)
                                )

                        if observation.extra.retained_events:
                            if not publish.eligible and not publish.exclude:
                                observation.extra.retained_events = [retained_event]
                            else:
                                observation.extra.retained_events.append(retained_event)
                        else:
                            observation.extra.retained_events = [retained_event]

                    subscription_to_receivers = {}
                    total_receivers_cnt = 0

                    # iterate over all subscriptions and determine actual receivers of the event
                    # under the respective subscription. also persist events (independent of whether
                    # there is any actual receiver right now on the subscription)
                    #
                    for subscription in subscriptions:

                        # initial list of receivers are all subscribers on a subscription ..
                        #
                        receivers = subscription.observers
                        receivers = self._filter_publish_receivers(receivers, publish)

                        # if receivers is non-empty, dispatch event ..
                        #
                        receivers_cnt = len(receivers) - (1 if self in receivers else 0)
                        if receivers_cnt:

                            total_receivers_cnt += receivers_cnt
                            subscription_to_receivers[subscription] = receivers

                    # send publish acknowledge before dispatching
                    #
                    if publish.acknowledge:
                        if self._router.is_traced:
                            publish.correlation_is_last = False
                            self._router._factory._worker._maybe_trace_rx_msg(session, publish)

                        reply = message.Published(publish.request, publication)
                        reply.correlation_id = publish.correlation_id
                        reply.correlation_uri = publish.topic
                        reply.correlation_is_anchor = False
                        reply.correlation_is_last = total_receivers_cnt == 0
                        self._router.send(session, reply)
                    else:
                        if self._router.is_traced and publish.correlation_is_last is None:
                            if total_receivers_cnt == 0:
                                publish.correlation_is_last = True
                            else:
                                publish.correlation_is_last = False

                    # now actually dispatch the events!
                    # for chunked dispatching, this will be filled with deferreds for each chunk
                    # processed. when the complete list of deferreds is done, that means the
                    # event has been sent out to all applicable receivers
                    all_dl = []

                    if total_receivers_cnt:

                        # list of receivers that should have received the event, but we could not
                        # send the event, since the receiver has disappeared in the meantime
                        vanished_receivers = []

                        for subscription, receivers in subscription_to_receivers.items():

                            storing_event = store_event and self._event_store in subscription.observers

                            self.log.debug('dispatching for subscription={subscription}, storing_event={storing_event}',
                                           subscription=subscription, storing_event=storing_event)

                            # for pattern-based subscriptions, the EVENT must contain
                            # the actual topic being published to
                            #
                            if subscription.match != message.Subscribe.MATCH_EXACT:
                                topic = publish.topic
                            else:
                                topic = None

                            if publish.payload:
                                msg = message.Event(subscription.id,
                                                    publication,
                                                    payload=publish.payload,
                                                    publisher=publisher,
                                                    publisher_authid=publisher_authid,
                                                    publisher_authrole=publisher_authrole,
                                                    topic=topic,
                                                    enc_algo=publish.enc_algo,
                                                    enc_key=publish.enc_key,
                                                    enc_serializer=publish.enc_serializer,
                                                    forward_for=forward_for)
                            else:
                                msg = message.Event(subscription.id,
                                                    publication,
                                                    args=publish.args,
                                                    kwargs=publish.kwargs,
                                                    publisher=publisher,
                                                    publisher_authid=publisher_authid,
                                                    publisher_authrole=publisher_authrole,
                                                    topic=topic,
                                                    forward_for=forward_for)

                            # if the publish message had a correlation ID, this will also be the
                            # correlation ID of the event message sent out
                            msg.correlation_id = publish.correlation_id
                            msg.correlation_uri = publish.topic
                            msg.correlation_is_anchor = False
                            msg.correlation_is_last = False

                            chunk_size = self._options.event_dispatching_chunk_size

                            if chunk_size and len(receivers) > chunk_size:
                                self.log.debug('chunked dispatching to {receivers_size} with chunk_size={chunk_size}',
                                               receivers_size=len(receivers), chunk_size=chunk_size)
                            else:
                                self.log.debug('unchunked dispatching to {receivers_size} receivers',
                                               receivers_size=len(receivers))

                            # note that we're using one code-path for both chunked and unchunked
                            # dispatches; the *first* chunk is always done "synchronously" (before
                            # the first call-later) so "un-chunked mode" really just means we know
                            # we'll be done right now and NOT do a call_later...

                            # a Deferred that fires when all chunks are done
                            all_d = txaio.create_future()
                            all_dl.append(all_d)

                            # all the event messages are the same except for the last one, which
                            # needs to have the "is_last" flag set if we're doing a trace
                            if self._router.is_traced:
                                last_msg = copy.deepcopy(msg)
                                last_msg.correlation_id = msg.correlation_id
                                last_msg.correlation_uri = msg.correlation_uri
                                last_msg.correlation_is_anchor = False
                                last_msg.correlation_is_last = True

                            def _notify_some(receivers):

                                # we do a first pass over the proposed chunk of receivers
                                # because not all of them will have a transport, and if this
                                # will be the last chunk of receivers we need to figure out
                                # which event is last...
                                receivers_this_chunk = []
                                for receiver in receivers[:chunk_size]:
                                    if receiver._session_id and receiver._transport:
                                        receivers_this_chunk.append(receiver)
                                    else:
                                        vanished_receivers.append(receiver)

                                receivers = receivers[chunk_size:]

                                # XXX note there's still going to be some edge-cases here .. if
                                # we are NOT the last chunk, but all the next chunk's receivers
                                # (could be only 1 in that chunk!) vanish before we run our next
                                # batch, then a "last" event will never go out ...

                                # we now actually do the deliveries, but now we know which
                                # receiver is the last one
                                if receivers or not self._router.is_traced:

                                    # NOT the last chunk (or we're not traced so don't care)
                                    for receiver in receivers_this_chunk:

                                        # send out WAMP msg to peer
                                        self._router.send(receiver, msg)
                                        if self._event_store or storing_event:
                                            self._event_store.store_event_history(publication, subscription.id, receiver)
                                else:
                                    # last chunk, so last receiver gets the different message
                                    for receiver in receivers_this_chunk[:-1]:
                                        self._router.send(receiver, msg)
                                        if self._event_store or storing_event:
                                            self._event_store.store_event_history(publication, subscription.id, receiver)

                                    # FIXME: I don't get the following comment and code path. when, how? and what to
                                    # do about event store? => storing_event
                                    #
                                    # we might have zero valid receivers
                                    if receivers_this_chunk:
                                        self._router.send(receivers_this_chunk[-1], last_msg)
                                        # FIXME: => storing_event

                                if receivers:
                                    # still more to do ..
                                    return txaio.call_later(0, _notify_some, receivers)
                                else:
                                    # all done! resolve all_d, which represents all receivers
                                    # to a single subscription matching the event
                                    txaio.resolve(all_d, None)

                            _notify_some([
                                recv for recv in receivers
                                if (me_also or recv != session) and recv != self._event_store
                            ])

                    return txaio.gather(all_dl)

            def on_authorize_error(err):
                """
                the call to authorize the action _itself_ failed (note this is
                different from the call to authorize succeed, but the
                authorization being denied)
                """
                self.log.failure("Authorization failed", failure=err)
                if publish.acknowledge:

                    if self._router.is_traced:
                        publish.correlation_is_last = False
                        self._router._factory._worker._maybe_trace_rx_msg(session, publish)

                    reply = message.Error(
                        message.Publish.MESSAGE_TYPE,
                        publish.request,
                        ApplicationError.AUTHORIZATION_FAILED,
                        [u"failed to authorize session for publishing to topic URI '{0}': {1}".format(publish.topic, err.value)]
                    )
                    reply.correlation_id = publish.correlation_id
                    reply.correlation_uri = publish.topic
                    reply.correlation_is_anchor = False
                    self._router.send(session, reply)
                else:
                    if self._router.is_traced:
                        publish.correlation_is_last = True
                        self._router._factory._worker._maybe_trace_rx_msg(session, publish)

            txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #27
0
ファイル: broker.py プロジェクト: oberstet/crossbar
    def processSubscribe(self, session, subscribe):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processSubscribe`
        """
        # check topic URI: for SUBSCRIBE, must be valid URI (either strict or loose), and all
        # URI components must be non-empty for normal subscriptions, may be empty for
        # wildcard subscriptions and must be non-empty for all but the last component for
        # prefix subscriptions
        #
        if self._option_uri_strict:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_STRICT_EMPTY.match(subscribe.topic)
            elif subscribe.match == u"prefix":
                uri_is_valid = _URI_PAT_STRICT_LAST_EMPTY.match(subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(subscribe.topic)
        else:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_LOOSE_EMPTY.match(subscribe.topic)
            elif subscribe.match == u"prefix":
                uri_is_valid = _URI_PAT_LOOSE_LAST_EMPTY.match(subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(subscribe.topic)

        if not uri_is_valid:
            reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.INVALID_URI, [u"subscribe for invalid topic URI '{0}'".format(subscribe.topic)])
            self._router.send(session, reply)
            return

        # authorize SUBSCRIBE action
        #
        d = self._router.authorize(session, subscribe.topic, u'subscribe')

        def on_authorize_success(authorization):
            if not authorization[u'allow']:
                # error reply since session is not authorized to subscribe
                #
                replies = [message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.NOT_AUTHORIZED, [u"session is not authorized to subscribe to topic '{0}'".format(subscribe.topic)])]

            else:
                # ok, session authorized to subscribe. now get the subscription
                #
                subscription, was_already_subscribed, is_first_subscriber = self._subscription_map.add_observer(session, subscribe.topic, subscribe.match, extra=SubscriptionExtra())

                if not was_already_subscribed:
                    self._session_to_subscriptions[session].add(subscription)

                # publish WAMP meta events
                #
                if self._router._realm:
                    service_session = self._router._realm.session
                    if service_session and not subscription.uri.startswith(u'wamp.'):
                        if is_first_subscriber:
                            subscription_details = {
                                u'id': subscription.id,
                                u'created': subscription.created,
                                u'uri': subscription.uri,
                                u'match': subscription.match,
                            }
                            service_session.publish(u'wamp.subscription.on_create', session._session_id, subscription_details)
                        if not was_already_subscribed:
                            service_session.publish(u'wamp.subscription.on_subscribe', session._session_id, subscription.id)

                # check for retained events
                #
                def _get_retained_event():

                    if subscription.extra.retained_events:
                        retained_events = list(subscription.extra.retained_events)
                        retained_events.reverse()

                        for publish in retained_events:
                            authorised = False

                            if not publish.exclude and not publish.eligible:
                                authorised = True
                            elif session._session_id in publish.eligible and session._session_id not in publish.exclude:
                                authorised = True

                            if authorised:
                                publication = util.id()

                                if publish.payload:
                                    msg = message.Event(subscription.id,
                                                        publication,
                                                        payload=publish.payload,
                                                        retained=True,
                                                        enc_algo=publish.enc_algo,
                                                        enc_key=publish.enc_key,
                                                        enc_serializer=publish.enc_serializer)
                                else:
                                    msg = message.Event(subscription.id,
                                                        publication,
                                                        args=publish.args,
                                                        kwargs=publish.kwargs,
                                                        retained=True)

                                return [msg]
                    return []

                # acknowledge subscribe with subscription ID
                #
                replies = [message.Subscribed(subscribe.request, subscription.id)]
                if subscribe.get_retained:
                    replies.extend(_get_retained_event())

            # send out reply to subscribe requestor
            #
            [self._router.send(session, reply) for reply in replies]

        def on_authorize_error(err):
            """
            the call to authorize the action _itself_ failed (note this is
            different from the call to authorize succeed, but the
            authorization being denied)
            """
            # XXX same as another code-block, can we collapse?
            self.log.failure("Authorization failed", failure=err)
            reply = message.Error(
                message.Subscribe.MESSAGE_TYPE,
                subscribe.request,
                ApplicationError.AUTHORIZATION_FAILED,
                [u"failed to authorize session for subscribing to topic URI '{0}': {1}".format(subscribe.topic, err.value)]
            )
            self._router.send(session, reply)

        txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #28
0
    def processCall(self, session, call):
        """
        Implements :func:`crossbar.router.interfaces.IDealer.processCall`
        """
        # check procedure URI: for CALL, must be valid URI (either strict or loose), and
        # all URI components must be non-empty
        if self._option_uri_strict:
            uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(call.procedure)
        else:
            uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(call.procedure)

        if not uri_is_valid:
            reply = message.Error(
                message.Call.MESSAGE_TYPE, call.request,
                ApplicationError.INVALID_URI, [
                    u"call with invalid procedure URI '{0}' (URI strict checking {1})"
                    .format(call.procedure, self._option_uri_strict)
                ])
            self._router.send(session, reply)
            return

        # get registrations active on the procedure called
        #
        registration = self._registration_map.best_matching_observation(
            call.procedure)

        if registration:

            # validate payload (skip in "payload_transparency" mode)
            #
            if call.payload is None:
                try:
                    self._router.validate(u'call', call.procedure, call.args,
                                          call.kwargs)
                except Exception as e:
                    reply = message.Error(
                        message.Call.MESSAGE_TYPE, call.request,
                        ApplicationError.INVALID_ARGUMENT, [
                            u"call of procedure '{0}' with invalid application payload: {1}"
                            .format(call.procedure, e)
                        ])
                    self._router.send(session, reply)
                    return

            # authorize CALL action
            #
            d = self._router.authorize(session,
                                       call.procedure,
                                       u'call',
                                       options=call.marshal_options())

            def on_authorize_success(authorization):
                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorization[u'allow']:
                    reply = message.Error(
                        message.Call.MESSAGE_TYPE, call.request,
                        ApplicationError.NOT_AUTHORIZED, [
                            u"session is not authorized to call procedure '{0}'"
                            .format(call.procedure)
                        ])
                    self._router.send(session, reply)

                else:
                    self._call(session, call, registration, authorization)

            def on_authorize_error(err):
                """
                the call to authorize the action _itself_ failed (note this is
                different from the call to authorize succeed, but the
                authorization being denied)
                """
                self.log.failure("Authorization of 'call' for '{uri}' failed",
                                 uri=call.procedure,
                                 failure=err)
                reply = message.Error(
                    message.Call.MESSAGE_TYPE, call.request,
                    ApplicationError.AUTHORIZATION_FAILED, [
                        u"failed to authorize session for calling procedure '{0}': {1}"
                        .format(call.procedure, err.value)
                    ])
                self._router.send(session, reply)

            txaio.add_callbacks(d, on_authorize_success, on_authorize_error)

        else:
            reply = message.Error(
                message.Call.MESSAGE_TYPE, call.request,
                ApplicationError.NO_SUCH_PROCEDURE, [
                    u"no callee registered for procedure <{0}>".format(
                        call.procedure)
                ])
            self._router.send(session, reply)
コード例 #29
0
    def processCall(self, session, call):
        """
        Implements :func:`crossbar.router.interfaces.IDealer.processCall`
        """
        # check procedure URI: for CALL, must be valid URI (either strict or loose), and
        # all URI components must be non-empty
        if self._option_uri_strict:
            uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(call.procedure)
        else:
            uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(call.procedure)

        if not uri_is_valid:
            reply = message.Error(
                message.Call.MESSAGE_TYPE, call.request,
                ApplicationError.INVALID_URI, [
                    u"call with invalid procedure URI '{0}' (URI strict checking {1})"
                    .format(call.procedure, self._option_uri_strict)
                ])
            self._router.send(session, reply)
            return

        # get registrations active on the procedure called
        #
        registration = self._registration_map.best_matching_observation(
            call.procedure)

        if registration:

            # validate payload (skip in "payload_transparency" mode)
            #
            if call.payload is None:
                try:
                    self._router.validate(u'call', call.procedure, call.args,
                                          call.kwargs)
                except Exception as e:
                    reply = message.Error(
                        message.Call.MESSAGE_TYPE, call.request,
                        ApplicationError.INVALID_ARGUMENT, [
                            u"call of procedure '{0}' with invalid application payload: {1}"
                            .format(call.procedure, e)
                        ])
                    self._router.send(session, reply)
                    return

            # authorize CALL action
            #
            d = self._router.authorize(session, call.procedure, u'call')

            def on_authorize_success(authorization):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorization[u'allow']:
                    reply = message.Error(
                        message.Call.MESSAGE_TYPE, call.request,
                        ApplicationError.NOT_AUTHORIZED, [
                            u"session is not authorized to call procedure '{0}'"
                            .format(call.procedure)
                        ])
                    self._router.send(session, reply)

                else:

                    # determine callee according to invocation policy
                    #
                    if registration.extra.invoke == message.Register.INVOKE_SINGLE:
                        callee = registration.observers[0]

                    elif registration.extra.invoke == message.Register.INVOKE_FIRST:
                        callee = registration.observers[0]

                    elif registration.extra.invoke == message.Register.INVOKE_LAST:
                        callee = registration.observers[
                            len(registration.observers) - 1]

                    elif registration.extra.invoke == message.Register.INVOKE_ROUNDROBIN:
                        callee = registration.observers[
                            registration.extra.roundrobin_current %
                            len(registration.observers)]
                        registration.extra.roundrobin_current += 1

                    elif registration.extra.invoke == message.Register.INVOKE_RANDOM:
                        callee = registration.observers[random.randint(
                            0,
                            len(registration.observers) - 1)]

                    else:
                        # should not arrive here
                        raise Exception(u"logic error")

                    # new ID for the invocation
                    #
                    invocation_request_id = self._request_id_gen.next()

                    # caller disclosure
                    #
                    if authorization[u'disclose']:
                        caller = session._session_id
                        caller_authid = session._authid
                        caller_authrole = session._authrole
                    else:
                        caller = None
                        caller_authid = None
                        caller_authrole = None

                    # for pattern-based registrations, the INVOCATION must contain
                    # the actual procedure being called
                    #
                    if registration.match != message.Register.MATCH_EXACT:
                        procedure = call.procedure
                    else:
                        procedure = None

                    if call.payload:
                        invocation = message.Invocation(
                            invocation_request_id,
                            registration.id,
                            payload=call.payload,
                            timeout=call.timeout,
                            receive_progress=call.receive_progress,
                            caller=caller,
                            caller_authid=caller_authid,
                            caller_authrole=caller_authrole,
                            procedure=procedure,
                            enc_algo=call.enc_algo,
                            enc_key=call.enc_key,
                            enc_serializer=call.enc_serializer)
                    else:
                        invocation = message.Invocation(
                            invocation_request_id,
                            registration.id,
                            args=call.args,
                            kwargs=call.kwargs,
                            timeout=call.timeout,
                            receive_progress=call.receive_progress,
                            caller=caller,
                            caller_authid=caller_authid,
                            caller_authrole=caller_authrole,
                            procedure=procedure)

                    self._invocations[
                        invocation_request_id] = InvocationRequest(
                            invocation_request_id, session, call)
                    self._router.send(callee, invocation)

            def on_authorize_error(err):
                """
                the call to authorize the action _itself_ failed (note this is
                different from the call to authorize succeed, but the
                authorization being denied)
                """
                self.log.failure(err)
                reply = message.Error(
                    message.Call.MESSAGE_TYPE, call.request,
                    ApplicationError.AUTHORIZATION_FAILED, [
                        u"failed to authorize session for calling procedure '{0}': {1}"
                        .format(call.procedure, err.value)
                    ])
                self._router.send(session, reply)

            txaio.add_callbacks(d, on_authorize_success, on_authorize_error)

        else:
            reply = message.Error(
                message.Call.MESSAGE_TYPE, call.request,
                ApplicationError.NO_SUCH_PROCEDURE, [
                    u"no callee registered for procedure <{0}>".format(
                        call.procedure)
                ])
            self._router.send(session, reply)
コード例 #30
0
ファイル: broker.py プロジェクト: Shareed2k/AutobahnPython
   def processPublish(self, session, publish):
      """
      Implements :func:`autobahn.wamp.interfaces.IBroker.processPublish`
      """
      assert(session in self._session_to_subscriptions)

      ## check topic URI
      ##
      if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(publish.topic)) or \
         (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(publish.topic)):

         if publish.acknowledge:
            reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.INVALID_URI, ["publish with invalid topic URI '{}'".format(publish.topic)])
            session._transport.send(reply)

         return

      if publish.topic in self._topic_to_sessions and self._topic_to_sessions[publish.topic]:

         ## initial list of receivers are all subscribers ..
         ##
         subscription, receivers = self._topic_to_sessions[publish.topic]

         ## filter by "eligible" receivers
         ##
         if publish.eligible:
            eligible = []
            for s in publish.eligible:
               if s in self._session_id_to_session:
                  eligible.append(self._session_id_to_session[s])
            if eligible:
               receivers = set(eligible) & receivers

         ## remove "excluded" receivers
         ##
         if publish.exclude:
            exclude = []
            for s in publish.exclude:
               if s in self._session_id_to_session:
                  exclude.append(self._session_id_to_session[s])
            if exclude:
               receivers = receivers - set(exclude)

         ## remove publisher
         ##
         if publish.excludeMe is None or publish.excludeMe:
         #   receivers.discard(session) # bad: this would modify our actual subscriber list
            me_also = False
         else:
            me_also = True

      else:
         subscription, receivers, me_also = None, [], False

      publication = util.id()

      ## send publish acknowledge when requested
      ##
      if publish.acknowledge:
         msg = message.Published(publish.request, publication)
         session._transport.send(msg)

      ## if receivers is non-empty, dispatch event ..
      ##
      if receivers:
         if publish.discloseMe:
            publisher = session._session_id
         else:
            publisher = None
         msg = message.Event(subscription,
                             publication,
                             args = publish.args,
                             kwargs = publish.kwargs,
                             publisher = publisher)
         for receiver in receivers:
            if me_also or receiver != session:
               receiver._transport.send(msg)
コード例 #31
0
    def processPublish(self, session, publish):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processPublish`
        """
        if self._router.is_traced:
            if not publish.correlation_id:
                publish.correlation_id = self._router.new_correlation_id()
                publish.correlation_is_anchor = True
            if not publish.correlation_uri:
                publish.correlation_uri = publish.topic

        # check topic URI: for PUBLISH, must be valid URI (either strict or loose), and
        # all URI components must be non-empty
        if self._option_uri_strict:
            uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(publish.topic)
        else:
            uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(publish.topic)

        if not uri_is_valid:
            if publish.acknowledge:
                reply = message.Error(
                    message.Publish.MESSAGE_TYPE, publish.request,
                    ApplicationError.INVALID_URI, [
                        u"publish with invalid topic URI '{0}' (URI strict checking {1})"
                        .format(publish.topic, self._option_uri_strict)
                    ])
                reply.correlation_id = publish.correlation_id
                reply.correlation_uri = publish.topic
                reply.correlation_is_anchor = False
                reply.correlation_is_last = True
                self._router.send(session, reply)
            return

        # disallow publication to topics starting with "wamp." other than for
        # trusted sessions (that are sessions built into Crossbar.io routing core)
        #
        if session._authrole is not None and session._authrole != u"trusted":
            is_restricted = publish.topic.startswith(u"wamp.")
            if is_restricted:
                if publish.acknowledge:
                    reply = message.Error(
                        message.Publish.MESSAGE_TYPE, publish.request,
                        ApplicationError.INVALID_URI, [
                            u"publish with restricted topic URI '{0}'".format(
                                publish.topic)
                        ])
                    reply.correlation_id = publish.correlation_id
                    reply.correlation_uri = publish.topic
                    reply.correlation_is_anchor = False
                    reply.correlation_is_last = True
                    self._router.send(session, reply)
                return

        # get subscriptions active on the topic published to
        #
        subscriptions = self._subscription_map.match_observations(
            publish.topic)

        # check if the event is being persisted by checking if we ourself are among the observers
        # on _any_ matching subscription
        # we've been previously added to observer lists on subscriptions ultimately from
        # node configuration and during the broker starts up.
        store_event = False
        if self._event_store:
            for subscription in subscriptions:
                if self._event_store in subscription.observers:
                    store_event = True
                    break
        if store_event:
            self.log.debug('Persisting event on topic "{topic}"',
                           topic=publish.topic)

        # check if the event is to be retained by inspecting the 'retain' flag
        retain_event = False
        if publish.retain:
            retain_event = True

        # go on if (otherwise there isn't anything to do anyway):
        #
        #   - there are any active subscriptions OR
        #   - the publish is to be acknowledged OR
        #   - the event is to be persisted OR
        #   - the event is to be retained
        #
        if not (subscriptions or publish.acknowledge or store_event
                or retain_event):

            # the received PUBLISH message is the only one received/sent
            # for this WAMP action, so mark it as "last" (there is another code path below!)
            if self._router.is_traced and publish.correlation_is_last is None:
                publish.correlation_is_last = True

        else:

            # validate payload
            #
            if publish.payload is None:
                try:
                    self._router.validate('event', publish.topic, publish.args,
                                          publish.kwargs)
                except Exception as e:
                    if publish.acknowledge:
                        reply = message.Error(
                            message.Publish.MESSAGE_TYPE, publish.request,
                            ApplicationError.INVALID_ARGUMENT, [
                                u"publish to topic URI '{0}' with invalid application payload: {1}"
                                .format(publish.topic, e)
                            ])
                        reply.correlation_id = publish.correlation_id
                        reply.correlation_uri = publish.topic
                        reply.correlation_is_anchor = False
                        reply.correlation_is_last = True
                        self._router.send(session, reply)
                    return

            # authorize PUBLISH action
            #
            d = self._router.authorize(session,
                                       publish.topic,
                                       u'publish',
                                       options=publish.marshal_options())

            def on_authorize_success(authorization):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorization[u'allow']:

                    if publish.acknowledge:
                        reply = message.Error(
                            message.Publish.MESSAGE_TYPE, publish.request,
                            ApplicationError.NOT_AUTHORIZED, [
                                u"session not authorized to publish to topic '{0}'"
                                .format(publish.topic)
                            ])
                        reply.correlation_id = publish.correlation_id
                        reply.correlation_uri = publish.topic
                        reply.correlation_is_anchor = False
                        reply.correlation_is_last = True
                        self._router.send(session, reply)

                else:

                    # new ID for the publication
                    #
                    publication = util.id()

                    # publisher disclosure
                    #
                    if authorization[u'disclose']:
                        disclose = True
                    elif (publish.topic.startswith(u"wamp.")
                          or publish.topic.startswith(u"crossbar.")):
                        disclose = True
                    else:
                        disclose = False

                    if disclose:
                        publisher = session._session_id
                        publisher_authid = session._authid
                        publisher_authrole = session._authrole
                    else:
                        publisher = None
                        publisher_authid = None
                        publisher_authrole = None

                    # skip publisher
                    #
                    if publish.exclude_me is None or publish.exclude_me:
                        me_also = False
                    else:
                        me_also = True

                    # persist event (this is done only once, regardless of the number of subscriptions
                    # the event matches on)
                    #
                    if store_event:
                        self._event_store.store_event(session._session_id,
                                                      publication,
                                                      publish.topic,
                                                      publish.args,
                                                      publish.kwargs)

                    # retain event on the topic
                    #
                    if retain_event:
                        retained_event = RetainedEvent(publish, publisher,
                                                       publisher_authid,
                                                       publisher_authrole)

                        observation = self._subscription_map.get_observation(
                            publish.topic)

                        if not observation:
                            # No observation, lets make a new one
                            observation = self._subscription_map.create_observation(
                                publish.topic, extra=SubscriptionExtra())
                        else:
                            # this can happen if event-history is
                            # enabled on the topic: the event-store
                            # creates an observation before any client
                            # could possible hit the code above
                            if observation.extra is None:
                                observation.extra = SubscriptionExtra()
                            elif not isinstance(observation.extra,
                                                SubscriptionExtra):
                                raise Exception(
                                    "incorrect 'extra' for '{}'".format(
                                        publish.topic))

                        if observation.extra.retained_events:
                            if not publish.eligible and not publish.exclude:
                                observation.extra.retained_events = [
                                    retained_event
                                ]
                            else:
                                observation.extra.retained_events.append(
                                    retained_event)
                        else:
                            observation.extra.retained_events = [
                                retained_event
                            ]

                    subscription_to_receivers = {}
                    total_receivers_cnt = 0

                    # iterate over all subscriptions and determine actual receivers of the event
                    # under the respective subscription. also persist events (independent of whether
                    # there is any actual receiver right now on the subscription)
                    #
                    for subscription in subscriptions:

                        # persist event history, but check if it is persisted on the individual subscription!
                        #
                        if store_event and self._event_store in subscription.observers:
                            self._event_store.store_event_history(
                                publication, subscription.id)

                        # initial list of receivers are all subscribers on a subscription ..
                        #
                        receivers = subscription.observers
                        receivers = self._filter_publish_receivers(
                            receivers, publish)

                        # if receivers is non-empty, dispatch event ..
                        #
                        receivers_cnt = len(receivers) - (1 if self
                                                          in receivers else 0)
                        if receivers_cnt:

                            total_receivers_cnt += receivers_cnt
                            subscription_to_receivers[subscription] = receivers

                    # send publish acknowledge before dispatching
                    #
                    if publish.acknowledge:
                        if self._router.is_traced:
                            publish.correlation_is_last = False

                        reply = message.Published(publish.request, publication)
                        reply.correlation_id = publish.correlation_id
                        reply.correlation_uri = publish.topic
                        reply.correlation_is_anchor = False
                        reply.correlation_is_last = total_receivers_cnt == 0
                        self._router.send(session, reply)
                    else:
                        if self._router.is_traced and publish.correlation_is_last is None:
                            if total_receivers_cnt == 0:
                                publish.correlation_is_last = True
                            else:
                                publish.correlation_is_last = False

                    # now actually dispatch the events!
                    # for chunked dispatching, this will be filled with deferreds for each chunk
                    # processed. when the complete list of deferreds is done, that means the
                    # event has been sent out to all applicable receivers
                    all_dl = []

                    if total_receivers_cnt:

                        # list of receivers that should have received the event, but we could not
                        # send the event, since the receiver has disappeared in the meantime
                        vanished_receivers = []

                        for subscription, receivers in subscription_to_receivers.items(
                        ):

                            self.log.debug(
                                'dispatching for subscription={subscription}',
                                subscription=subscription)

                            # for pattern-based subscriptions, the EVENT must contain
                            # the actual topic being published to
                            #
                            if subscription.match != message.Subscribe.MATCH_EXACT:
                                topic = publish.topic
                            else:
                                topic = None

                            if publish.payload:
                                msg = message.Event(
                                    subscription.id,
                                    publication,
                                    payload=publish.payload,
                                    publisher=publisher,
                                    publisher_authid=publisher_authid,
                                    publisher_authrole=publisher_authrole,
                                    topic=topic,
                                    enc_algo=publish.enc_algo,
                                    enc_key=publish.enc_key,
                                    enc_serializer=publish.enc_serializer)
                            else:
                                msg = message.Event(
                                    subscription.id,
                                    publication,
                                    args=publish.args,
                                    kwargs=publish.kwargs,
                                    publisher=publisher,
                                    publisher_authid=publisher_authid,
                                    publisher_authrole=publisher_authrole,
                                    topic=topic)

                            # if the publish message had a correlation ID, this will also be the
                            # correlation ID of the event message sent out
                            msg.correlation_id = publish.correlation_id
                            msg.correlation_uri = publish.topic
                            msg.correlation_is_anchor = False
                            msg.correlation_is_last = False

                            chunk_size = self._options.event_dispatching_chunk_size

                            if chunk_size and len(receivers) > chunk_size:
                                self.log.debug(
                                    'chunked dispatching to {receivers_size} with chunk_size={chunk_size}',
                                    receivers_size=len(receivers),
                                    chunk_size=chunk_size)
                            else:
                                self.log.debug(
                                    'unchunked dispatching to {receivers_size} receivers',
                                    receivers_size=len(receivers))

                            # note that we're using one code-path for both chunked and unchunked
                            # dispatches; the *first* chunk is always done "synchronously" (before
                            # the first call-later) so "un-chunked mode" really just means we know
                            # we'll be done right now and NOT do a call_later...

                            # a Deferred that fires when all chunks are done
                            all_d = txaio.create_future()
                            all_dl.append(all_d)

                            # all the event messages are the same except for the last one, which
                            # needs to have the "is_last" flag set if we're doing a trace
                            if self._router.is_traced:
                                last_msg = copy.deepcopy(msg)
                                last_msg.correlation_id = msg.correlation_id
                                last_msg.correlation_uri = msg.correlation_uri
                                last_msg.correlation_is_anchor = False
                                last_msg.correlation_is_last = True

                            def _notify_some(receivers):

                                # we do a first pass over the proposed chunk of receivers
                                # because not all of them will have a transport, and if this
                                # will be the last chunk of receivers we need to figure out
                                # which event is last...
                                receivers_this_chunk = []
                                for receiver in receivers[:chunk_size]:
                                    if (me_also or receiver != session
                                        ) and receiver != self._event_store:
                                        # the receiving subscriber session might have no transport,
                                        # or no longer be joined
                                        if receiver._session_id and receiver._transport:
                                            receivers_this_chunk.append(
                                                receiver)
                                        else:
                                            vanished_receivers.append(receiver)

                                receivers = receivers[chunk_size:]

                                # XXX note there's still going to be some edge-cases here .. if
                                # we are NOT the last chunk, but all the next chunk's receivers
                                # (could be only 1 in that chunk!) vanish before we run our next
                                # batch, then a "last" event will never go out ...

                                # we now actually do the deliveries, but now we know which
                                # receiver is the last one
                                if receivers or not self._router.is_traced:
                                    # NOT the last chunk (or we're not traced so don't care)
                                    for receiver in receivers_this_chunk:
                                        self._router.send(receiver, msg)
                                else:
                                    # last chunk, so last receiver gets the different message
                                    for receiver in receivers_this_chunk[:-1]:
                                        self._router.send(receiver, msg)
                                    # we might have zero valid receivers
                                    if receivers_this_chunk:
                                        self._router.send(
                                            receivers_this_chunk[-1], last_msg)

                                if receivers:
                                    # still more to do ..
                                    return txaio.call_later(
                                        0, _notify_some, receivers)
                                else:
                                    # all done! resolve all_d, which represents all receivers
                                    # to a single subscription matching the event
                                    txaio.resolve(all_d, None)

                            _notify_some(list(receivers))

                    return txaio.gather(all_dl)

            def on_authorize_error(err):
                """
                the call to authorize the action _itself_ failed (note this is
                different from the call to authorize succeed, but the
                authorization being denied)
                """
                self.log.failure("Authorization failed", failure=err)
                if publish.acknowledge:
                    reply = message.Error(
                        message.Publish.MESSAGE_TYPE, publish.request,
                        ApplicationError.AUTHORIZATION_FAILED, [
                            u"failed to authorize session for publishing to topic URI '{0}': {1}"
                            .format(publish.topic, err.value)
                        ])
                    reply.correlation_id = publish.correlation_id
                    reply.correlation_uri = publish.topic
                    reply.correlation_is_anchor = False
                    self._router.send(session, reply)

            txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #32
0
ファイル: broker.py プロジェクト: rvdmei/crossbar
    def processSubscribe(self, session, subscribe):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processSubscribe`
        """
        # check topic URI: for SUBSCRIBE, must be valid URI (either strict or loose), and all
        # URI components must be non-empty for normal subscriptions, may be empty for
        # wildcard subscriptions and must be non-empty for all but the last component for
        # prefix subscriptions
        #
        if self._option_uri_strict:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_STRICT_EMPTY.match(subscribe.topic)
            elif subscribe.match == u"prefix":
                uri_is_valid = _URI_PAT_STRICT_LAST_EMPTY.match(subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(subscribe.topic)
        else:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_LOOSE_EMPTY.match(subscribe.topic)
            elif subscribe.match == u"prefix":
                uri_is_valid = _URI_PAT_LOOSE_LAST_EMPTY.match(subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(subscribe.topic)

        if not uri_is_valid:
            reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.INVALID_URI, [u"subscribe for invalid topic URI '{0}'".format(subscribe.topic)])
            self._router.send(session, reply)
            return

        # authorize SUBSCRIBE action
        #
        d = self._router.authorize(session, subscribe.topic, u'subscribe')

        def on_authorize_success(authorization):
            if not authorization[u'allow']:
                # error reply since session is not authorized to subscribe
                #
                replies = [message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.NOT_AUTHORIZED, [u"session is not authorized to subscribe to topic '{0}'".format(subscribe.topic)])]

            else:
                # ok, session authorized to subscribe. now get the subscription
                #
                subscription, was_already_subscribed, is_first_subscriber = self._subscription_map.add_observer(session, subscribe.topic, subscribe.match, extra=SubscriptionExtra())

                if not was_already_subscribed:
                    self._session_to_subscriptions[session].add(subscription)

                # publish WAMP meta events
                #
                if self._router._realm:
                    service_session = self._router._realm.session
                    if service_session and not subscription.uri.startswith(u'wamp.'):
                        if is_first_subscriber:
                            subscription_details = {
                                u'id': subscription.id,
                                u'created': subscription.created,
                                u'uri': subscription.uri,
                                u'match': subscription.match,
                            }
                            service_session.publish(u'wamp.subscription.on_create', session._session_id, subscription_details)
                        if not was_already_subscribed:
                            service_session.publish(u'wamp.subscription.on_subscribe', session._session_id, subscription.id)

                # check for retained events
                #
                def _get_retained_event():

                    if subscription.extra.retained_events:
                        retained_events = list(subscription.extra.retained_events)
                        retained_events.reverse()

                        for publish in retained_events:
                            authorised = False

                            if not publish.exclude and not publish.eligible:
                                authorised = True
                            elif session._session_id in publish.eligible and session._session_id not in publish.exclude:
                                authorised = True

                            if authorised:
                                publication = util.id()

                                if publish.payload:
                                    msg = message.Event(subscription.id,
                                                        publication,
                                                        payload=publish.payload,
                                                        retained=True,
                                                        enc_algo=publish.enc_algo,
                                                        enc_key=publish.enc_key,
                                                        enc_serializer=publish.enc_serializer)
                                else:
                                    msg = message.Event(subscription.id,
                                                        publication,
                                                        args=publish.args,
                                                        kwargs=publish.kwargs,
                                                        retained=True)

                                return [msg]
                    return []

                # acknowledge subscribe with subscription ID
                #
                replies = [message.Subscribed(subscribe.request, subscription.id)]
                if subscribe.get_retained:
                    replies.extend(_get_retained_event())

            # send out reply to subscribe requestor
            #
            [self._router.send(session, reply) for reply in replies]

        def on_authorize_error(err):
            """
            the call to authorize the action _itself_ failed (note this is
            different from the call to authorize succeed, but the
            authorization being denied)
            """
            # XXX same as another code-block, can we collapse?
            self.log.failure("Authorization failed", failure=err)
            reply = message.Error(
                message.Subscribe.MESSAGE_TYPE,
                subscribe.request,
                ApplicationError.AUTHORIZATION_FAILED,
                [u"failed to authorize session for subscribing to topic URI '{0}': {1}".format(subscribe.topic, err.value)]
            )
            self._router.send(session, reply)

        txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #33
0
    def processPublish(self, session, publish):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processPublish`
        """
        # check topic URI: for PUBLISH, must be valid URI (either strict or loose), and
        # all URI components must be non-empty
        if self._option_uri_strict:
            uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(publish.topic)
        else:
            uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(publish.topic)

        if not uri_is_valid:
            if publish.acknowledge:
                reply = message.Error(
                    message.Publish.MESSAGE_TYPE, publish.request,
                    ApplicationError.INVALID_URI, [
                        u"publish with invalid topic URI '{0}' (URI strict checking {1})"
                        .format(publish.topic, self._option_uri_strict)
                    ])
                session._transport.send(reply)
            return

        # disallow publication to topics starting with "wamp." and "crossbar." other than for
        # trusted sessions (that are sessions built into Crossbar.io)
        #
        if session._authrole is not None and session._authrole != u"trusted":
            is_restricted = publish.topic.startswith(
                u"wamp.") or publish.topic.startswith(u"crossbar.")
            if is_restricted:
                if publish.acknowledge:
                    reply = message.Error(
                        message.Publish.MESSAGE_TYPE, publish.request,
                        ApplicationError.INVALID_URI, [
                            u"publish with restricted topic URI '{0}'".format(
                                publish.topic)
                        ])
                    session._transport.send(reply)
                return

        # get subscriptions active on the topic published to
        #
        subscriptions = self._subscription_map.match_observations(
            publish.topic)

        # check if the event is being persisted by checking if we ourself are among the observers.
        # we've been added to observer lists on subscriptions ultimately from node configuration
        # and during the broker starts up.
        store_event = False
        if self._event_store:
            for s in subscriptions:
                if self._event_store in s.observers:
                    store_event = True
                    break
        if store_event:
            self.log.debug("event on topic '{topic}'' is being persisted",
                           topic=publish.topic)

        # go on if (otherwise there isn't anything to do anyway):
        #
        #   - there are any active subscriptions OR
        #   - the publish is to be acknowledged OR
        #   - the event is to be persistet
        #
        if subscriptions or publish.acknowledge or store_event:

            # validate payload
            #
            try:
                self._router.validate('event', publish.topic, publish.args,
                                      publish.kwargs)
            except Exception as e:
                if publish.acknowledge:
                    reply = message.Error(
                        message.Publish.MESSAGE_TYPE, publish.request,
                        ApplicationError.INVALID_ARGUMENT, [
                            u"publish to topic URI '{0}' with invalid application payload: {1}"
                            .format(publish.topic, e)
                        ])
                    session._transport.send(reply)
                return

            # authorize PUBLISH action
            #
            d = txaio.as_future(self._router.authorize, session, publish.topic,
                                RouterAction.ACTION_PUBLISH)

            def on_authorize_success(authorized):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorized:

                    if publish.acknowledge:
                        reply = message.Error(
                            message.Publish.MESSAGE_TYPE, publish.request,
                            ApplicationError.NOT_AUTHORIZED, [
                                u"session not authorized to publish to topic '{0}'"
                                .format(publish.topic)
                            ])
                        session._transport.send(reply)

                else:

                    # new ID for the publication
                    #
                    publication = util.id()

                    # persist event
                    #
                    if store_event:
                        self._event_store.store_event(session._session_id,
                                                      publication,
                                                      publish.topic,
                                                      publish.args,
                                                      publish.kwargs)

                    # send publish acknowledge immediately when requested
                    #
                    if publish.acknowledge:
                        msg = message.Published(publish.request, publication)
                        session._transport.send(msg)

                    # publisher disclosure
                    #
                    if publish.disclose_me:
                        publisher = session._session_id
                    else:
                        publisher = None

                    # skip publisher
                    #
                    if publish.exclude_me is None or publish.exclude_me:
                        me_also = False
                    else:
                        me_also = True

                    # iterate over all subscriptions ..
                    #
                    for subscription in subscriptions:

                        # persist event history
                        #
                        if store_event:
                            self._event_store.store_event_history(
                                publication, subscription.id)

                        # initial list of receivers are all subscribers on a subscription ..
                        #
                        receivers = subscription.observers

                        # filter by "eligible" receivers
                        #
                        if publish.eligible:

                            # map eligible session IDs to eligible sessions
                            eligible = []
                            for session_id in publish.eligible:
                                if session_id in self._router._session_id_to_session:
                                    eligible.append(
                                        self._router.
                                        _session_id_to_session[session_id])

                            # filter receivers for eligible sessions
                            receivers = set(eligible) & receivers

                        # remove "excluded" receivers
                        #
                        if publish.exclude:

                            # map excluded session IDs to excluded sessions
                            exclude = []
                            for s in publish.exclude:
                                if s in self._router._session_id_to_session:
                                    exclude.append(
                                        self._router._session_id_to_session[s])

                            # filter receivers for excluded sessions
                            if exclude:
                                receivers = receivers - set(exclude)

                        # if receivers is non-empty, dispatch event ..
                        #
                        receivers_cnt = len(receivers) - (1 if self
                                                          in receivers else 0)
                        if receivers_cnt:

                            # for pattern-based subscriptions, the EVENT must contain
                            # the actual topic being published to
                            #
                            if subscription.match != message.Subscribe.MATCH_EXACT:
                                topic = publish.topic
                            else:
                                topic = None

                            msg = message.Event(subscription.id,
                                                publication,
                                                args=publish.args,
                                                kwargs=publish.kwargs,
                                                publisher=publisher,
                                                topic=topic)
                            for receiver in receivers:
                                if (me_also or receiver != session
                                    ) and receiver != self._event_store:
                                    # the receiving subscriber session
                                    # might have no transport, or no
                                    # longer be joined
                                    if receiver._session_id and receiver._transport:
                                        receiver._transport.send(msg)

            def on_authorize_error(err):
                """
                the call to authorize the action _itself_ failed (note this is
                different from the call to authorize succeed, but the
                authorization being denied)
                """
                self.log.failure(err)
                if publish.acknowledge:
                    reply = message.Error(
                        message.Publish.MESSAGE_TYPE, publish.request,
                        ApplicationError.AUTHORIZATION_FAILED, [
                            u"failed to authorize session for publishing to topic URI '{0}': {1}"
                            .format(publish.topic, err.value)
                        ])
                    session._transport.send(reply)

            txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #34
0
ファイル: broker.py プロジェクト: cosmospham/crossbar
    def processSubscribe(self, session, subscribe):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processSubscribe`
        """
        # check topic URI: for SUBSCRIBE, must be valid URI (either strict or loose), and all
        # URI components must be non-empty other than for wildcard subscriptions
        #
        if self._option_uri_strict:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_STRICT_EMPTY.match(subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(subscribe.topic)
        else:
            if subscribe.match == u"wildcard":
                uri_is_valid = _URI_PAT_LOOSE_EMPTY.match(subscribe.topic)
            else:
                uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(subscribe.topic)

        if not uri_is_valid:
            reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.INVALID_URI, [u"subscribe for invalid topic URI '{0}'".format(subscribe.topic)])
            session._transport.send(reply)
            return

        # authorize action
        #
        d = txaio.as_future(self._router.authorize, session, subscribe.topic, RouterAction.ACTION_SUBSCRIBE)

        def on_authorize_success(authorized):
            if not authorized:
                # error reply since session is not authorized to subscribe
                #
                reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.NOT_AUTHORIZED, [u"session is not authorized to subscribe to topic '{0}'".format(subscribe.topic)])

            else:
                # ok, session authorized to subscribe. now get the subscription
                #
                subscription, was_already_subscribed, is_first_subscriber = self._subscription_map.add_observer(session, subscribe.topic, subscribe.match)

                if not was_already_subscribed:
                    self._session_to_subscriptions[session].add(subscription)

                # publish WAMP meta events
                #
                if self._router._realm:
                    service_session = self._router._realm.session
                    if service_session and not subscription.uri.startswith(u'wamp.'):
                        if is_first_subscriber:
                            subscription_details = {
                                'id': subscription.id,
                                'created': subscription.created,
                                'uri': subscription.uri,
                                'match': subscription.match,
                            }
                            service_session.publish(u'wamp.subscription.on_create', session._session_id, subscription_details)
                        if not was_already_subscribed:
                            service_session.publish(u'wamp.subscription.on_subscribe', session._session_id, subscription.id)

                # acknowledge subscribe with subscription ID
                #
                reply = message.Subscribed(subscribe.request, subscription.id)

            # send out reply to subscribe requestor
            #
            session._transport.send(reply)

        def on_authorize_error(err):
            """
            the call to authorize the action _itself_ failed (note this is
            different from the call to authorize succeed, but the
            authorization being denied)
            """
            # XXX same as another code-block, can we collapse?
            self.log.failure(err)
            reply = message.Error(
                message.Subscribe.MESSAGE_TYPE,
                subscribe.request,
                ApplicationError.AUTHORIZATION_FAILED,
                [u"failed to authorize session for subscribing to topic URI '{0}': {1}".format(subscribe.topic, err.value)]
            )
            session._transport.send(reply)

        txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #35
0
ファイル: broker.py プロジェクト: roeste/crossbar
    def processPublish(self, session, publish):
        """
        Implements :func:`crossbar.router.interfaces.IBroker.processPublish`
        """
        # check topic URI: for PUBLISH, must be valid URI (either strict or loose), and
        # all URI components must be non-empty
        if self._option_uri_strict:
            uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(publish.topic)
        else:
            uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(publish.topic)

        if not uri_is_valid:
            if publish.acknowledge:
                reply = message.Error(
                    message.Publish.MESSAGE_TYPE, publish.request,
                    ApplicationError.INVALID_URI, [
                        u"publish with invalid topic URI '{0}' (URI strict checking {1})"
                        .format(publish.topic, self._option_uri_strict)
                    ])
                self._router.send(session, reply)
            return

        # disallow publication to topics starting with "wamp." other than for
        # trusted sessions (that are sessions built into Crossbar.io routing core)
        #
        if session._authrole is not None and session._authrole != u"trusted":
            is_restricted = publish.topic.startswith(u"wamp.")
            if is_restricted:
                if publish.acknowledge:
                    reply = message.Error(
                        message.Publish.MESSAGE_TYPE, publish.request,
                        ApplicationError.INVALID_URI, [
                            u"publish with restricted topic URI '{0}'".format(
                                publish.topic)
                        ])
                    self._router.send(session, reply)
                return

        # get subscriptions active on the topic published to
        #
        subscriptions = self._subscription_map.match_observations(
            publish.topic)

        # check if the event is being persisted by checking if we ourself are among the observers
        # on _any_ matching subscription
        # we've been previously added to observer lists on subscriptions ultimately from
        # node configuration and during the broker starts up.
        store_event = False
        if self._event_store:
            for subscription in subscriptions:
                if self._event_store in subscription.observers:
                    store_event = True
                    break
        if store_event:
            self.log.debug('Persisting event on topic "{topic}"',
                           topic=publish.topic)

        # check if the event is to be retained by inspecting the 'retain' flag
        retain_event = False
        if publish.retain:
            retain_event = True

        # go on if (otherwise there isn't anything to do anyway):
        #
        #   - there are any active subscriptions OR
        #   - the publish is to be acknowledged OR
        #   - the event is to be persisted OR
        #   - the event is to be retained
        #
        if subscriptions or publish.acknowledge or store_event or retain_event:

            # validate payload
            #
            if publish.payload is None:
                try:
                    self._router.validate('event', publish.topic, publish.args,
                                          publish.kwargs)
                except Exception as e:
                    if publish.acknowledge:
                        reply = message.Error(
                            message.Publish.MESSAGE_TYPE, publish.request,
                            ApplicationError.INVALID_ARGUMENT, [
                                u"publish to topic URI '{0}' with invalid application payload: {1}"
                                .format(publish.topic, e)
                            ])
                        self._router.send(session, reply)
                    return

            # authorize PUBLISH action
            #
            d = self._router.authorize(session, publish.topic, u'publish')

            def on_authorize_success(authorization):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorization[u'allow']:

                    if publish.acknowledge:
                        reply = message.Error(
                            message.Publish.MESSAGE_TYPE, publish.request,
                            ApplicationError.NOT_AUTHORIZED, [
                                u"session not authorized to publish to topic '{0}'"
                                .format(publish.topic)
                            ])
                        self._router.send(session, reply)

                else:

                    # new ID for the publication
                    #
                    publication = util.id()

                    # send publish acknowledge immediately when requested
                    #
                    if publish.acknowledge:
                        reply = message.Published(publish.request, publication)
                        self._router.send(session, reply)

                    # publisher disclosure
                    #
                    if authorization[u'disclose']:
                        disclose = True
                    elif (publish.topic.startswith(u"wamp.")
                          or publish.topic.startswith(u"crossbar.")):
                        disclose = True
                    else:
                        disclose = False

                    if disclose:
                        publisher = session._session_id
                        publisher_authid = session._authid
                        publisher_authrole = session._authrole
                    else:
                        publisher = None
                        publisher_authid = None
                        publisher_authrole = None

                    # skip publisher
                    #
                    if publish.exclude_me is None or publish.exclude_me:
                        me_also = False
                    else:
                        me_also = True

                    # persist event (this is done only once, regardless of the number of subscriptions
                    # the event matches on)
                    #
                    if store_event:
                        self._event_store.store_event(session._session_id,
                                                      publication,
                                                      publish.topic,
                                                      publish.args,
                                                      publish.kwargs)

                    # retain event on the topic
                    #
                    if retain_event:
                        retained_event = RetainedEvent(publish, publisher,
                                                       publisher_authid,
                                                       publisher_authrole)

                        observation = self._subscription_map.get_observation(
                            publish.topic)

                        if not observation:
                            # No observation, lets make a new one
                            observation = self._subscription_map.create_observation(
                                publish.topic, extra=SubscriptionExtra())
                        else:
                            # this can happen if event-history is
                            # enabled on the topic: the event-store
                            # creates an observation before any client
                            # could possible hit the code above
                            if observation.extra is None:
                                observation.extra = SubscriptionExtra()
                            elif not isinstance(observation.extra,
                                                SubscriptionExtra):
                                raise Exception(
                                    "incorrect 'extra' for '{}'".format(
                                        publish.topic))

                        if observation.extra.retained_events:
                            if not publish.eligible and not publish.exclude:
                                observation.extra.retained_events = [
                                    retained_event
                                ]
                            else:
                                observation.extra.retained_events.append(
                                    retained_event)
                        else:
                            observation.extra.retained_events = [
                                retained_event
                            ]

                    all_dl = []

                    # iterate over all subscriptions ..
                    #
                    for subscription in subscriptions:

                        self.log.debug(
                            'dispatching for subscription={subscription}',
                            subscription=subscription)

                        # persist event history, but check if it is persisted on the individual subscription!
                        #
                        if store_event and self._event_store in subscription.observers:
                            self._event_store.store_event_history(
                                publication, subscription.id)

                        # initial list of receivers are all subscribers on a subscription ..
                        #
                        receivers = subscription.observers
                        receivers = self._filter_publish_receivers(
                            receivers, publish)

                        # if receivers is non-empty, dispatch event ..
                        #
                        receivers_cnt = len(receivers) - (1 if self
                                                          in receivers else 0)
                        if receivers_cnt:

                            # for pattern-based subscriptions, the EVENT must contain
                            # the actual topic being published to
                            #
                            if subscription.match != message.Subscribe.MATCH_EXACT:
                                topic = publish.topic
                            else:
                                topic = None

                            if publish.payload:
                                msg = message.Event(
                                    subscription.id,
                                    publication,
                                    payload=publish.payload,
                                    publisher=publisher,
                                    publisher_authid=publisher_authid,
                                    publisher_authrole=publisher_authrole,
                                    topic=topic,
                                    enc_algo=publish.enc_algo,
                                    enc_key=publish.enc_key,
                                    enc_serializer=publish.enc_serializer)
                            else:
                                msg = message.Event(
                                    subscription.id,
                                    publication,
                                    args=publish.args,
                                    kwargs=publish.kwargs,
                                    publisher=publisher,
                                    publisher_authid=publisher_authid,
                                    publisher_authrole=publisher_authrole,
                                    topic=topic)

                            chunk_size = self._options.event_dispatching_chunk_size

                            if chunk_size:
                                self.log.debug(
                                    'chunked dispatching to {receivers_size} with chunk_size={chunk_size}',
                                    receivers_size=len(receivers),
                                    chunk_size=chunk_size)

                                # a Deferred that fires when all chunks are done
                                all_d = txaio.create_future()
                                all_dl.append(all_d)

                                def _notify_some(receivers):
                                    for receiver in receivers[:chunk_size]:
                                        if (
                                                me_also or receiver != session
                                        ) and receiver != self._event_store:
                                            # the receiving subscriber session
                                            # might have no transport, or no
                                            # longer be joined
                                            if receiver._session_id and receiver._transport:
                                                self._router.send(
                                                    receiver, msg)
                                    receivers = receivers[chunk_size:]
                                    if len(receivers) > 0:
                                        # still more to do ..
                                        return txaio.call_later(
                                            0, _notify_some, receivers)
                                    else:
                                        # all done! resolve all_d, which represents all receivers
                                        # to a single subscription matching the event
                                        txaio.resolve(all_d, None)

                                _notify_some(list(receivers))
                            else:
                                self.log.debug(
                                    'unchunked dispatching to {receivers_size} receivers',
                                    receivers_size=len(receivers))

                                for receiver in receivers:
                                    if (me_also or receiver != session
                                        ) and receiver != self._event_store:
                                        # the receiving subscriber session
                                        # might have no transport, or no
                                        # longer be joined
                                        if receiver._session_id and receiver._transport:
                                            self._router.send(receiver, msg)

                    return txaio.gather(all_dl)

            def on_authorize_error(err):
                """
                the call to authorize the action _itself_ failed (note this is
                different from the call to authorize succeed, but the
                authorization being denied)
                """
                self.log.failure("Authorization failed", failure=err)
                if publish.acknowledge:
                    reply = message.Error(
                        message.Publish.MESSAGE_TYPE, publish.request,
                        ApplicationError.AUTHORIZATION_FAILED, [
                            u"failed to authorize session for publishing to topic URI '{0}': {1}"
                            .format(publish.topic, err.value)
                        ])
                    self._router.send(session, reply)

            txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
コード例 #36
0
ファイル: dealer.py プロジェクト: abhimanyu-siwach/crossbar
    def processCall(self, session, call):
        """
        Implements :func:`crossbar.router.interfaces.IDealer.processCall`
        """
        # check procedure URI: for CALL, must be valid URI (either strict or loose), and
        # all URI components must be non-empty
        if self._option_uri_strict:
            uri_is_valid = _URI_PAT_STRICT_NON_EMPTY.match(call.procedure)
        else:
            uri_is_valid = _URI_PAT_LOOSE_NON_EMPTY.match(call.procedure)

        if not uri_is_valid:
            reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.INVALID_URI, [u"call with invalid procedure URI '{0}' (URI strict checking {1})".format(call.procedure, self._option_uri_strict)])
            self._router.send(session, reply)
            return

        # get registrations active on the procedure called
        #
        registration = self._registration_map.best_matching_observation(call.procedure)

        if registration:

            # validate payload (skip in "payload_transparency" mode)
            #
            if call.payload is None:
                try:
                    self._router.validate('call', call.procedure, call.args, call.kwargs)
                except Exception as e:
                    reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.INVALID_ARGUMENT, [u"call of procedure '{0}' with invalid application payload: {1}".format(call.procedure, e)])
                    self._router.send(session, reply)
                    return

            # authorize CALL action
            #
            d = txaio.as_future(self._router.authorize, session, call.procedure, RouterAction.ACTION_CALL)

            def on_authorize_success(authorized):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorized:
                    reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.NOT_AUTHORIZED, [u"session is not authorized to call procedure '{0}'".format(call.procedure)])
                    self._router.send(session, reply)

                else:

                    # determine callee according to invocation policy
                    #
                    if registration.extra.invoke == message.Register.INVOKE_SINGLE:
                        callee = registration.observers[0]

                    elif registration.extra.invoke == message.Register.INVOKE_FIRST:
                        callee = registration.observers[0]

                    elif registration.extra.invoke == message.Register.INVOKE_LAST:
                        callee = registration.observers[len(registration.observers) - 1]

                    elif registration.extra.invoke == message.Register.INVOKE_ROUNDROBIN:
                        callee = registration.observers[registration.extra.roundrobin_current % len(registration.observers)]
                        registration.extra.roundrobin_current += 1

                    elif registration.extra.invoke == message.Register.INVOKE_RANDOM:
                        callee = registration.observers[random.randint(0, len(registration.observers) - 1)]

                    else:
                        # should not arrive here
                        raise Exception(u"logic error")

                    # new ID for the invocation
                    #
                    invocation_request_id = self._request_id_gen.next()

                    # caller disclosure
                    #
                    if call.disclose_me:
                        caller = session._session_id
                    else:
                        caller = None

                    # for pattern-based registrations, the INVOCATION must contain
                    # the actual procedure being called
                    #
                    if registration.match != message.Register.MATCH_EXACT:
                        procedure = call.procedure
                    else:
                        procedure = None

                    if call.payload:
                        invocation = message.Invocation(invocation_request_id,
                                                        registration.id,
                                                        payload=call.payload,
                                                        timeout=call.timeout,
                                                        receive_progress=call.receive_progress,
                                                        caller=caller,
                                                        procedure=procedure,
                                                        enc_algo=call.enc_algo,
                                                        enc_key=call.enc_key,
                                                        enc_serializer=call.enc_serializer)
                    else:
                        invocation = message.Invocation(invocation_request_id,
                                                        registration.id,
                                                        args=call.args,
                                                        kwargs=call.kwargs,
                                                        timeout=call.timeout,
                                                        receive_progress=call.receive_progress,
                                                        caller=caller,
                                                        procedure=procedure)

                    self._invocations[invocation_request_id] = InvocationRequest(invocation_request_id, session, call)
                    self._router.send(callee, invocation)

            def on_authorize_error(err):
                """
                the call to authorize the action _itself_ failed (note this is
                different from the call to authorize succeed, but the
                authorization being denied)
                """
                self.log.failure(err)
                reply = message.Error(
                    message.Call.MESSAGE_TYPE,
                    call.request,
                    ApplicationError.AUTHORIZATION_FAILED,
                    [u"failed to authorize session for calling procedure '{0}': {1}".format(call.procedure, err.value)]
                )
                self._router.send(session, reply)

            txaio.add_callbacks(d, on_authorize_success, on_authorize_error)

        else:
            reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.NO_SUCH_PROCEDURE, [u"no callee registered for procedure <{0}>".format(call.procedure)])
            self._router.send(session, reply)
コード例 #37
0
    def processPublish(self, session, publish):
        """
      Implements :func:`autobahn.wamp.interfaces.IBroker.processPublish`
      """
        #assert(session in self._session_to_subscriptions)

        ## check topic URI
        ##
        if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(publish.topic)) or \
           (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(publish.topic)):

            if publish.acknowledge:
                reply = message.Error(
                    message.Publish.MESSAGE_TYPE, publish.request,
                    ApplicationError.INVALID_URI, [
                        "publish with invalid topic URI '{0}'".format(
                            publish.topic)
                    ])
                session._transport.send(reply)

            return

        if publish.topic in self._topic_to_sessions or publish.acknowledge:

            ## validate payload
            ##
            try:
                self._router.validate('event', publish.topic, publish.args,
                                      publish.kwargs)
            except Exception as e:
                reply = message.Error(
                    message.Publish.MESSAGE_TYPE, publish.request,
                    ApplicationError.INVALID_ARGUMENT, [
                        "publish to topic URI '{0}' with invalid application payload: {1}"
                        .format(publish.topic, e)
                    ])
                session._transport.send(reply)
                return

            ## authorize action
            ##
            d = self._as_future(self._router.authorize, session, publish.topic,
                                IRouter.ACTION_PUBLISH)

            def on_authorize_success(authorized):

                if not authorized:

                    if publish.acknowledge:
                        reply = message.Error(
                            message.Publish.MESSAGE_TYPE, publish.request,
                            ApplicationError.NOT_AUTHORIZED, [
                                "session not authorized to publish to topic '{0}'"
                                .format(publish.topic)
                            ])
                        session._transport.send(reply)

                else:

                    ## continue processing if either a) there are subscribers to the topic or b) the publish is to be acknowledged
                    ##
                    if publish.topic in self._topic_to_sessions and self._topic_to_sessions[
                            publish.topic]:

                        ## initial list of receivers are all subscribers ..
                        ##
                        subscription, receivers = self._topic_to_sessions[
                            publish.topic]

                        ## filter by "eligible" receivers
                        ##
                        if publish.eligible:
                            eligible = []
                            for s in publish.eligible:
                                if s in self._session_id_to_session:
                                    eligible.append(
                                        self._session_id_to_session[s])

                            receivers = set(eligible) & receivers

                        ## remove "excluded" receivers
                        ##
                        if publish.exclude:
                            exclude = []
                            for s in publish.exclude:
                                if s in self._session_id_to_session:
                                    exclude.append(
                                        self._session_id_to_session[s])
                            if exclude:
                                receivers = receivers - set(exclude)

                        ## remove publisher
                        ##
                        if publish.excludeMe is None or publish.excludeMe:
                            #   receivers.discard(session) # bad: this would modify our actual subscriber list
                            me_also = False
                        else:
                            me_also = True

                    else:
                        subscription, receivers, me_also = None, [], False

                    publication = util.id()

                    ## send publish acknowledge when requested
                    ##
                    if publish.acknowledge:
                        msg = message.Published(publish.request, publication)
                        session._transport.send(msg)

                    ## if receivers is non-empty, dispatch event ..
                    ##
                    if receivers:
                        if publish.discloseMe:
                            publisher = session._session_id
                        else:
                            publisher = None
                        msg = message.Event(subscription,
                                            publication,
                                            args=publish.args,
                                            kwargs=publish.kwargs,
                                            publisher=publisher)
                        for receiver in receivers:
                            if me_also or receiver != session:
                                ## the subscribing session might have been lost in the meantime ..
                                if receiver._transport:
                                    receiver._transport.send(msg)

            def on_authorize_error(err):
                if publish.acknowledge:
                    reply = message.Error(
                        message.Publish.MESSAGE_TYPE, publish.request,
                        ApplicationError.AUTHORIZATION_FAILED, [
                            "failed to authorize session for publishing to topic URI '{0}': {1}"
                            .format(publish.topic, err.value)
                        ])
                    session._transport.send(reply)

            self._add_future_callbacks(d, on_authorize_success,
                                       on_authorize_error)