Ejemplo n.º 1
0
    def detach(self, session=None) -> List[int]:
        self.log.debug('{func}(session={session})',
                       func=hltype(self.detach),
                       session=session)

        detached_session_ids = []
        if session is None:
            # detach all sessions from router
            for session in list(self._session_id_to_session.values()):
                self._detach(session)
                detached_session_ids.append(session._session_id)
        else:
            # detach single session from router
            self._detach(session)
            detached_session_ids.append(session._session_id)

        self.log.info(
            '{func} router session detached from realm "{realm}" (session={session}, '
            'detached_session_ids={detached_session_ids}, authid="{authid}", authrole="{authrole}", '
            'authmethod="{authmethod}", authprovider="{authprovider}")',
            func=hltype(self.detach),
            session=hlid(session._session_id) if session else '',
            authid=hlid(session._authid),
            authrole=hlid(session._authrole),
            authmethod=hlval(session._authmethod),
            authprovider=hlval(session._authprovider),
            detached_session_ids=hlval(len(detached_session_ids)),
            realm=hlid(session._realm))

        return detached_session_ids
Ejemplo n.º 2
0
    def delAuth(self, cbtid: str) -> bool:
        """
        Delete an existing cookie (if any), including any authentication info and the cookie itself.

        :param cbtid: Cookie value (ID)  of cookie to delete.
        :return: Flag indicating an existing cookie was deleted.
        """
        was_existing = False
        with self._db.begin(write=True) as txn:
            cookie_oid = self._schema.idx_cookies_by_value[txn, cbtid]
            if cookie_oid:
                del self._schema.cookies[txn, cookie_oid]
                was_existing = True

        if was_existing:
            self.log.info(
                '{func} cookie with cbtid="{cbtid}" did exist and was deleted',
                func=hltype(self.delAuth),
                cbtid=hlid(cbtid))
        else:
            self.log.info('{func} no cookie with cbtid="{cbtid}" exists',
                          func=hltype(self.delAuth),
                          cbtid=hlid(cbtid))

        return was_existing
Ejemplo n.º 3
0
 def authenticate(realm, authid, details):
     self.log.info(
         '{func}(realm="{realm}", authid="{authid}", details=details)',
         func=authenticate,
         realm=hlid(realm),
         authid=hlid(authid),
         details=details)
     return 'anonymous'
Ejemplo n.º 4
0
 async def onJoin(self, details):
     self.log.info('Ok, client joined on realm "{realm}" [session={session}, authid="{authid}", authrole="{authrole}"]',
                   realm=hlid(details.realm),
                   session=hlid(details.session),
                   authid=hlid(details.authid),
                   authrole=hlid(details.authrole),
                   details=details)
     if 'ready' in self.config.extra:
         txaio.resolve(self.config.extra['ready'], (self, details))
Ejemplo n.º 5
0
    def dropProto(self, cbtid: str, proto: ISession):
        """
        Remove given WebSocket connection from the set of connections associated
        with the cookie having the given ID. Return the new count of
        connections associated with the cookie.
        """
        self.log.debug('{func} removing proto {proto} from cookie "{cbtid}"',
                       func=hltype(self.dropProto),
                       proto=proto,
                       cbtid=hlid(cbtid))

        if self.exists(cbtid):
            if cbtid in self._connections:
                # remove this WebSocket connection from the set of connections
                # associated with the same cookie
                self._connections[cbtid].discard(proto)
                remaining = len(self._connections[cbtid])
                if remaining:
                    return remaining
                else:
                    del self._connections[cbtid]
        else:
            if cbtid in self._connections:
                del self._connections[cbtid]
        return 0
Ejemplo n.º 6
0
    def onJoin(self, details):
        assert self.config.extra and 'on_ready' in self.config.extra
        assert self.config.extra and 'other' in self.config.extra

        remote = self.config.extra['other']
        assert isinstance(remote, RLinkRemoteSession)

        self._exclude_authid = self.config.extra.get('exclude_authid', None)
        self._exclude_authrole = self.config.extra.get('exclude_authrole',
                                                       None)

        # setup local->remote event forwarding
        forward_events = self.config.extra.get('forward_events', False)
        if forward_events:
            yield self._setup_event_forwarding(remote)

        # setup local->remote invocation forwarding
        forward_invocations = self.config.extra.get('forward_invocations',
                                                    False)
        if forward_invocations:
            yield self._setup_invocation_forwarding(remote)

        self.log.debug(
            'Router link local session ready (forward_events={forward_events}, forward_invocations={forward_invocations}, realm={realm}, authid={authid}, authrole={authrole}, session={session}) {method}',
            method=hltype(RLinkLocalSession.onJoin),
            forward_events=hluserid(forward_events),
            forward_invocations=hluserid(forward_invocations),
            realm=hluserid(details.realm),
            authid=hluserid(details.authid),
            authrole=hluserid(details.authrole),
            session=hlid(details.session))

        on_ready = self.config.extra.get('on_ready', None)
        if on_ready and not on_ready.called:
            self.config.extra['on_ready'].callback(self)
Ejemplo n.º 7
0
    def onLeave(self, details):
        self.log.warn(
            'Router link local session down! (realm={realm}, authid={authid}, authrole={authrole}, session={session}, details={details}) {method}',
            method=hltype(RLinkLocalSession.onLeave),
            realm=hluserid(self.config.realm),
            authid=hluserid(self._authid),
            authrole=hluserid(self._authrole),
            details=details,
            session=hlid(self._session_id))

        BridgeSession.onLeave(self, details)
Ejemplo n.º 8
0
    def delAuth(self, cbtid: str) -> bool:
        """
        Delete an existing cookie (if any), including any authentication info and the cookie itself.

        :param cbtid: Cookie value (ID)  of cookie to delete.
        :return: Flag indicating an existing cookie was deleted.
        """
        if self.exists(cbtid):
            cookie = self._cookies[cbtid]
            cookie['deleted'] = util.utcnow()
            del self._cookies[cbtid]
            self._persist(cbtid, cookie, status='deleted')
            self.log.info(
                '{func} cookie with cbtid="{cbtid}" did exist and was deleted',
                func=hltype(self.delAuth),
                cbtid=hlid(cbtid))
            return True
        else:
            self.log.info('{func} no cookie with cbtid="{cbtid}" exists',
                          func=hltype(self.delAuth),
                          cbtid=hlid(cbtid))
            return False
Ejemplo n.º 9
0
    def getAuth(
        self, cbtid: str
    ) -> Tuple[Optional[str], Optional[str], Optional[str], Optional[str],
               Optional[Dict[str, Any]]]:
        """
        Get the authentication info (if any) for a cookie stored in the database.

        :param cbtid: Cookie value (ID) to get authentication for.
        :return: A tuple ``(authid, authrole, authmethod, authrealm, authextra)`` if the cookie exists,
            or a tuple ``(None, None, None, None, None)`` if no cookie with given ``cbtid`` is
            currently stored.
        """
        with self._db.begin() as txn:
            # find cookie OID by cookie value
            cookie_oid = self._schema.idx_cookies_by_value[txn, cbtid]
            if cookie_oid:
                # if we found a cookie OID, read the actual cookie from database
                cookie = self._schema.cookies[txn, cookie_oid]
                assert cookie
                cbtid_ = cookie.value
                cookie_auth_info = cookie.authid, cookie.authrole, cookie.authmethod, cookie.authrealm, cookie.authextra
            else:
                cbtid_ = None
                cookie_auth_info = None, None, None, None, None

        if cbtid_:
            self.log.info(
                '{func} cookie auth info for "{cbtid}" retrieved: {cookie_auth_info}',
                func=hltype(self.getAuth),
                cbtid=hlid(cbtid_),
                cookie_auth_info=cookie_auth_info)
        else:
            self.log.info(
                '{func} no cookie for "{cbtid}" stored in cookiestore database',
                func=hltype(self.getAuth),
                cbtid=hlid(cbtid))

        return cookie_auth_info
Ejemplo n.º 10
0
    def delAuth(self, cbtid: str) -> bool:
        """
        Delete an existing cookie (if any), including any authentication info and the cookie itself.

        :param cbtid: Cookie value (ID)  of cookie to delete.
        :return: Flag indicating an existing cookie was deleted.
        """
        was_existing = False
        if cbtid in self._cookies:
            del self._cookies[cbtid]
            was_existing = True

        if was_existing:
            self.log.info(
                '{func} cookie with cbtid="{cbtid}" did exist and was deleted',
                func=hltype(self.setAuth),
                cbtid=hlid(cbtid))
        else:
            self.log.info('{func} no cookie with cbtid="{cbtid}" exists',
                          func=hltype(self.setAuth),
                          cbtid=hlid(cbtid))

        return was_existing
Ejemplo n.º 11
0
    def attach(self, session: ISession):
        """
        Implements :func:`autobahn.wamp.interfaces.IRouter.attach`
        """
        self.log.debug('{func}(session={session})',
                       func=hltype(self.attach),
                       session=session)

        if session._session_id not in self._session_id_to_session:
            self._session_id_to_session[session._session_id] = session
        else:
            raise Exception("session with ID {} already attached".format(
                session._session_id))

        self._broker.attach(session)
        self._dealer.attach(session)

        self._attached += 1

        self.log.info(
            '{func} new session attached for realm="{realm}", session={session}, authid="{authid}", '
            'authrole="{authrole}", authmethod="{authmethod}", authprovider="{authprovider}", authextra=\n{authextra}',
            func=hltype(self.attach),
            session=hlid(session._session_id) if session else '',
            authid=hlid(session._authid),
            authrole=hlid(session._authrole),
            authmethod=hlval(session._authmethod),
            authprovider=hlval(session._authprovider),
            authextra=pformat(session._authextra)
            if session._authextra else None,
            realm=hlid(session._realm))

        return {
            'broker': self._broker._role_features,
            'dealer': self._dealer._role_features
        }
Ejemplo n.º 12
0
    def onJoin(self, details):
        self.log.debug('{klass}.onJoin(details={details})',
                       klass=self.__class__.__name__,
                       details=details)

        assert self.config.extra and 'on_ready' in self.config.extra
        assert self.config.extra and 'other' in self.config.extra

        local = self.config.extra['other']
        assert isinstance(local, RLinkLocalSession)
        local._tracker.connected = True

        self._exclude_authid = self.config.extra.get('exclude_authid', None)
        self._exclude_authrole = self.config.extra.get('exclude_authrole',
                                                       None)

        # setup remote->local event forwarding
        forward_events = self.config.extra.get('forward_events', False)
        if forward_events:
            yield self._setup_event_forwarding(local)

        # setup remote->local invocation forwarding
        forward_invocations = self.config.extra.get('forward_invocations',
                                                    False)
        if forward_invocations:
            yield self._setup_invocation_forwarding(local)

        self.log.info(
            '{klass}.onJoin(): rlink remote session ready (forward_events={forward_events}, forward_invocations={forward_invocations}, realm={realm}, authid={authid}, authrole={authrole}, session={session}) {method}',
            klass=self.__class__.__name__,
            method=hltype(RLinkRemoteSession.onJoin),
            forward_events=hluserid(forward_events),
            forward_invocations=hluserid(forward_invocations),
            realm=hluserid(details.realm),
            authid=hluserid(details.authid),
            authrole=hluserid(details.authrole),
            session=hlid(details.session))

        # we are ready!
        on_ready = self.config.extra.get('on_ready', None)
        if on_ready and not on_ready.called:
            self.config.extra['on_ready'].callback(self)
Ejemplo n.º 13
0
    def addProto(self, cbtid: str, proto: ISession) -> int:
        """
        Add given WebSocket connection to the set of connections associated
        with the cookie having the given ID. Return the new count of
        connections associated with the cookie.
        """
        self.log.debug('{func} adding proto {proto} for cookie "{cbtid}"',
                       func=hltype(self.addProto),
                       proto=proto,
                       cbtid=hlid(cbtid))

        if self.exists(cbtid):
            if cbtid not in self._connections:
                self._connections[cbtid] = set()
            self._connections[cbtid].add(proto)
            return len(self._connections[cbtid])
        else:
            if cbtid in self._connections:
                del self._connections[cbtid]
            return 0
Ejemplo n.º 14
0
    def get_member(self, ethadr_raw):
        if self.is_attached():
            is_member = yield self.call('xbr.network.is_member', ethadr_raw)
            if is_member:
                member_data = yield self.call('xbr.network.get_member_by_wallet', ethadr_raw)

                member_data['address'] = web3.Web3.toChecksumAddress(member_data['address'])
                member_data['oid'] = uuid.UUID(bytes=member_data['oid'])
                member_data['balance']['eth'] = web3.Web3.fromWei(unpack_uint256(member_data['balance']['eth']),
                                                                  'ether')
                member_data['balance']['xbr'] = web3.Web3.fromWei(unpack_uint256(member_data['balance']['xbr']),
                                                                  'ether')
                member_data['created'] = np.datetime64(member_data['created'], 'ns')

                member_level = member_data['level']
                member_data['level'] = {
                    # Member is active.
                    1: 'ACTIVE',
                    # Member is active and verified.
                    2: 'VERIFIED',
                    # Member is retired.
                    3: 'RETIRED',
                    # Member is subject to a temporary penalty.
                    4: 'PENALTY',
                    # Member is currently blocked and cannot current actively participate in the market.
                    5: 'BLOCKED',
                }.get(member_level, None)

                self.log.info(
                    'Member {member_oid} found for address 0x{member_adr} - current member level {member_level}',
                    member_level=hlval(member_data['level']),
                    member_oid=hlid(member_data['oid']),
                    member_adr=hlval(member_data['address']))

                return member_data
            else:
                self.log.warn('Address {output_ethadr} is not a member in the XBR network',
                              output_ethadr=ethadr_raw)
        else:
            self.log.warn('not connected: could not retrieve member data for address {output_ethadr}',
                          output_ethadr=ethadr_raw)
Ejemplo n.º 15
0
    def onLeave(self, details):
        # When the rlink is going down, make sure to unsubscribe to
        # all events that are subscribed on the local-leg.
        # This avoids duplicate events that would otherwise arrive
        # See: https://github.com/crossbario/crossbar/issues/1916
        for k, v in self._subs.items():
            if v['sub'].active:
                yield v['sub'].unsubscribe()

        self._subs = {}

        self.config.extra['other']._tracker.connected = False
        self.log.warn(
            '{klass}.onLeave(): rlink remote session left! (realm={realm}, authid={authid}, authrole={authrole}, session={session}, details={details}) {method}',
            klass=self.__class__.__name__,
            method=hltype(RLinkLocalSession.onLeave),
            realm=hluserid(self.config.realm),
            authid=hluserid(self._authid),
            authrole=hluserid(self._authrole),
            session=hlid(self._session_id),
            details=details)

        BridgeSession.onLeave(self, details)
Ejemplo n.º 16
0
    def onConnect(self, request):

        self.log.debug('{func}(request={request})',
                       func=hltype(self.onConnect),
                       request=request)

        if self.factory.debug_traffic:
            from twisted.internet import reactor

            def print_traffic():
                self.log.info(
                    "Traffic {peer}: {wire_in} / {wire_out} in / out bytes - {ws_in} / {ws_out} in / out msgs",
                    peer=self.peer,
                    wire_in=self.trafficStats.incomingOctetsWireLevel,
                    wire_out=self.trafficStats.outgoingOctetsWireLevel,
                    ws_in=self.trafficStats.incomingWebSocketMessages,
                    ws_out=self.trafficStats.outgoingWebSocketMessages,
                )
                reactor.callLater(1, print_traffic)

            print_traffic()

        # if WebSocket client did not set WS subprotocol, assume "wamp.2.json"
        #
        self.STRICT_PROTOCOL_NEGOTIATION = self.factory._requireWebSocketSubprotocol

        # handle WebSocket opening handshake
        #
        protocol, headers = websocket.WampWebSocketServerProtocol.onConnect(
            self, request)

        self.log.debug(
            '{func}: proceed with WebSocket opening handshake for WebSocket subprotocol "{protocol}"',
            func=hltype(self.onConnect),
            protocol=hlval(protocol))

        try:

            self._origin = request.origin

            # transport-level WMAP authentication info
            #
            self._authid = None
            self._authrole = None
            self._authrealm = None
            self._authmethod = None
            self._authextra = None
            self._authprovider = None

            # cookie tracking and cookie-based authentication
            #
            self._cbtid = None

            if self.factory._cookiestore:

                # try to parse an already set cookie from HTTP request headers
                self._cbtid = self.factory._cookiestore.parse(request.headers)

                if self._cbtid:
                    self.log.info(
                        '{func}: parsed tracking/authentication cookie cbtid "{cbtid}" from HTTP request headers',
                        func=hltype(self.onConnect),
                        cbtid=hlval(self._cbtid))
                else:
                    self.log.info(
                        '{func}: no tracking/authentication cookie cbtid found in HTTP request headers!',
                        func=hltype(self.onConnect))

                # if no cookie is set, or it doesn't exist in our database, create a new cookie
                if self._cbtid is None or not self.factory._cookiestore.exists(
                        self._cbtid):

                    self._cbtid, headers[
                        'Set-Cookie'] = self.factory._cookiestore.create()

                    if 'cookie' in self.factory._config:
                        if 'secure' in self.factory._config[
                                'cookie'] and self.factory._config['cookie'][
                                    'secure'] is True:
                            headers['Set-Cookie'] += ';Secure'
                        if 'http_strict' in self.factory._config[
                                'cookie'] and self.factory._config['cookie'][
                                    'http_strict'] is True:
                            headers['Set-Cookie'] += ';HttpOnly'
                        if 'same_site' in self.factory._config['cookie']:
                            headers[
                                'Set-Cookie'] += ';SameSite=' + self.factory._config[
                                    'cookie']['same_site']

                    self.log.info('{func}: setting new cookie {cookie}',
                                  func=hltype(self.onConnect),
                                  cookie=hlval(headers['Set-Cookie'],
                                               color='yellow'))
                else:
                    self.log.info(
                        '{func}: tracking/authentication cookie cbtid "{cbtid}" already set and stored',
                        func=hltype(self.onConnect),
                        cbtid=hlval(self._cbtid))

                # add this WebSocket connection to the set of connections
                # associated with the same cookie
                self.factory._cookiestore.addProto(self._cbtid, self)

                self.log.debug(
                    "Cookie tracking enabled on WebSocket connection {ws}",
                    ws=self)

                # if cookie-based authentication is enabled, set auth info from cookie store
                #
                if 'auth' in self.factory._config and 'cookie' in self.factory._config[
                        'auth']:

                    self._authid, self._authrole, self._authmethod, self._authrealm, self._authextra = self.factory._cookiestore.getAuth(
                        self._cbtid)

                    if self._authid:
                        # there is a cookie set, and the cookie was previously successfully authenticated,
                        # so immediately authenticate the client using that information
                        self._authprovider = 'cookie'
                        self.log.info(
                            '{func} authenticated client via cookie {cookiename}={cbtid} as authid="{authid}", authrole="{authrole}", authmethod="{authmethod}", authprovider="{authprovider}", authrealm="{authrealm}"',
                            func=hltype(self.onConnect),
                            cookiename=self.factory._cookiestore.
                            _cookie_id_field,
                            cbtid=hlval(self._cbtid, color='green'),
                            authid=hlid(self._authid),
                            authrole=hlid(self._authrole),
                            authmethod=hlval(self._authmethod),
                            authprovider=hlval(self._authprovider),
                            authrealm=hlid(self._authrealm))
                    else:
                        # there is a cookie set, but the cookie wasn't authenticated yet using a different auth method
                        self.log.info(
                            '{func} cookie-based authentication enabled, but cookie {cbtid} is not authenticated yet',
                            cbtid=hlval(self._cbtid, color='blue'),
                            func=hltype(self.onConnect))
                else:
                    self.log.info(
                        '{func} cookie-based authentication disabled on connection',
                        func=hltype(self.onConnect))
            else:
                self.log.info(
                    '{func} cookie tracking disabled on WebSocket connection',
                    func=hltype(self.onConnect))

            # negotiated WebSocket subprotocol in use, e.g. "wamp.2.cbor.batched"
            self._transport_details.websocket_protocol = protocol

            # WebSocket extensions in use. will be filled in onOpen(), see below
            self._transport_details.websocket_extensions_in_use = None

            # Crossbar.io tracking ID (for cookie tracking)
            self._transport_details.http_cbtid = self._cbtid

            # all HTTP headers as received by the WebSocket client
            self._transport_details.http_headers_received = request.headers

            # only customer user headers (such as cookie)
            self._transport_details.http_headers_sent = headers

            # accept the WebSocket connection, speaking subprotocol `protocol`
            # and setting HTTP headers `headers`
            return protocol, headers

        except:
            self.log.failure()
Ejemplo n.º 17
0
    def setAuth(self, cbtid: str, authid: Optional[str],
                authrole: Optional[str], authmethod: Optional[str],
                authextra: Optional[Dict[str, Any]],
                authrealm: Optional[str]) -> bool:
        """
        Update the authentication information associated and stored for an existing cookie (if any).

        :param cbtid: Cookie value (ID) to update authentication for.
        :param authid: The WAMP authid a cookie-authenticating session is to be assigned.
        :param authrole: The WAMP authrole a cookie-authenticating session is to join under.
        :param authmethod: The WAMP authentication method to be returned to the client performing
            this cookie-based authentication.
        :param authextra: The WAMP authentication extra data to be returned to the client performing
            this cookie-based authentication.
        :param authrealm: The WAMP realm a cookie-authenticating session is to join.
        :return: Flag indicating an existing cookie was modified.
        """

        was_existing = False
        was_modified = False
        with self._db.begin(write=True) as txn:
            cookie_oid = self._schema.idx_cookies_by_value[txn, cbtid]
            if cookie_oid:
                # read current cookie from database
                cookie = self._schema.cookies[txn, cookie_oid]
                assert cookie
                was_existing = True
                if (authid != cookie.authid or authrole != cookie.authrole
                        or authmethod != cookie.authmethod
                        or authrealm != cookie.authrealm
                        or authextra != cookie.authextra):
                    cookie.authid = authid
                    cookie.authrole = authrole
                    cookie.authmethod = authmethod
                    cookie.authrealm = authrealm
                    cookie.authextra = authextra
                    # write updated cookie to database
                    self._schema.cookies[txn, cookie.oid] = cookie
                    was_modified = True

        if was_existing:
            if was_modified:
                self.log.info(
                    '{func} cookie with cbtid="{cbtid}" exists, but was updated (authid="{authid}", authrole='
                    '"{authrole}", authmethod="{authmethod}", authrealm="{authrealm}", authextra={authextra})',
                    func=hltype(self.setAuth),
                    cbtid=hlid(cbtid),
                    authid=hlid(authid),
                    authrole=hlid(authrole),
                    authmethod=hlval(authmethod),
                    authrealm=hlval(authrealm),
                    authextra=pformat(authextra))
            else:
                self.log.info(
                    '{func} cookie with cbtid="{cbtid}" exists and needs no update',
                    func=hltype(self.setAuth),
                    cbtid=hlid(cbtid))
        else:
            self.log.info(
                '{func} no cookie to modify with cbtid="{cbtid}" exists',
                func=hltype(self.setAuth),
                cbtid=hlid(cbtid))

        return was_modified