crossbario / crossbar

Crossbar.io - WAMP application router
https://crossbar.io/
Other
2.05k stars 274 forks source link

proxy: allow to start route without role #2014

Closed om26er closed 2 years ago

om26er commented 2 years ago

The proxy worker should optionally allow to start realm routes without any roles defined. Essentially forwarding all authenticated clients to the backend router.

This essentially means the proxy can be used to forward clients without knowing if the router has a specific role running or not.

Currently you can start a route without a role BUT when a client tries to connect, the proxy does't forward the connection and rather tells the user code that the role does not exist

oberstet commented 2 years ago

allow to start realm routes without any roles defined

no, rlinks are always to a specific realm-role

oberstet commented 2 years ago

ah, didn't read .. you meant proxy->router, not router->router?

eg https://github.com/crossbario/crossbar-examples/blob/852680eee646cf5479bff18ec727a8026d9bdcda/authentication/wampcra/static/.crossbar/config-rtrpxy-realmstore.json#L206

om26er commented 2 years ago

no, rlinks are always to a specific realm-role

This issue is about proxy only. We want to forward an authenticated client to the backend router without starting the realm route

oberstet commented 2 years ago

without starting the realm route

well, that's not how proxy workers work: the proxy worker, once it has authenticated a client under some role needs to know to which router that realm-role should be proxied to. hence proxy-routes are needed, and configured automatically be the master node

om26er commented 2 years ago

So something like below would forward all authenticated clients to the backend router

         "routes": {
            "realm1": {
               "*": "router1"
            }
         }

Or even

         "routes": {
            "realm1": "router1"
         }
oberstet commented 2 years ago

nope, as said, this doesn't fit into the design

to the backend router

"the": which one?

om26er commented 2 years ago

I have updated the config. Basically that would be "router1" where the authenticated client is forwarded to

oberstet commented 2 years ago

yeah, it could be made consistent just from looking at config file format. eg

"connections": {
    "conn1": {
        "transport": "..."
    },
    "conn2": {
        "transport": "..."
    }
},
"routes": {
    "realm1": {
        "anonymous": "conn2",
        "frontend": "conn1"
    },
    "realm2": "conn2"
},

this would make all roles to realm2 go to conn2, but also have role anonymous on realm1 go to conn2

but it leads to more complications, since in above case, the router listening on conn2 needs to have both realm1 and realm2 running, when realm2 is actually running on conn2

anyways: I don't need that;)

om26er commented 2 years ago

One approach that I tested and something that seems to work as well is

If the route is of the form

"routes": {
    "realm2": "conn2"
}

The below patch is able to achieve the required behavior with minimal change

diff --git a/crossbar/worker/proxy.py b/crossbar/worker/proxy.py
index b1eb0f3a..7d106d35 100644
--- a/crossbar/worker/proxy.py
+++ b/crossbar/worker/proxy.py
@@ -1096,7 +1096,9 @@ class ProxyRoute(object):
         :param role_name: Role to lookup.
         :return: ``True`` if the role is configured in this proxy route.
         """
-        return role_name in self._config
+        # The '*' below means that we want to forward all roles
+        # to the backend.
+        return role_name in self._config or "*" in self._config

     def map_connection_id(self, role_name) -> Optional[str]:
         """
@@ -1450,7 +1452,8 @@ class ProxyController(TransportController):
             realm_routes = self._routes[realm]

             # the route config is a map with role name as key
-            result = any(authrole in route.config for route in realm_routes.values())
+            # NOTE: The '*' below means that we want to forward all roles to the backend.
+            result = any(authrole in route.config or "*" in route.config for route in realm_routes.values())
         else:
             realm_routes = None
             result = False
@@ -1661,6 +1664,10 @@ class ProxyController(TransportController):
         assert self.has_role(realm_name, role_name)

         key = realm_name, role_name
+        # FIXME: hack
+        if key not in self._connections_by_auth:
+            key = realm_name, "*"
+
         if key not in self._roundrobin_idx:
             self._roundrobin_idx[key] = 0
         else:
@@ -1897,6 +1904,10 @@ class ProxyController(TransportController):
             config=config,
         )

+        # Forward all roles to the connection
+        if isinstance(config, str):
+            config = {"*": config}
+
         # check that we already know about all connections specified in the route
         connection_ids = set()
         for role_name in config.keys():