crossbario / crossbar

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

Wamp-CRA for Python3 based crossbar #412

Closed singlecheeze closed 9 years ago

singlecheeze commented 9 years ago

I see this in the repo, is wamp-cra not supported yet?:

Pending WAMP-CRA authentication.
2015-08-27T11:04:53-0400 [Guest        3704] Connected. Joining realm realm1 as user authenUser ...
2015-08-27T11:04:53-0400 [Router       3700] Traceback (most recent call last):
2015-08-27T11:04:53-0400 [Router       3700]   File "/usr/local/lib/python3.4/dist-packages/crossbar/router/session.py", line 586, in onHello
2015-08-27T11:04:53-0400 [Router       3700]     user['secret'].encode('utf8'))
2015-08-27T11:04:53-0400 [Router       3700]   File "/usr/local/lib/python3.4/dist-packages/crossbar/router/auth.py", line 104, in __init__
2015-08-27T11:04:53-0400 [Router       3700]     self.signature = auth.compute_wcs(secret, self.challenge)
oberstet commented 9 years ago

can you post the complete traceback?

oberstet commented 9 years ago

also: what Crossbar.io version? trunk?

singlecheeze commented 9 years ago

WIN NEW LOGO!

     __  __  __  __  __  __      __     __
    /  `|__)/  \/__`/__`|__) /\ |__)  |/  \
    \__,|  \\__/.__/.__/|__)/~~\|  \. |\__/

 Crossbar.io        : 0.11.0
   Autobahn         : 0.10.5-2
     UTF8 Validator : wsaccel-0.6.2
     XOR Masker     : wsaccel-0.6.2
     JSON Codec     : stdlib
     MsgPack Codec  : -
   Twisted          : 15.3.0-EPollReactor
   Python           : 3.4.0/CPython
 OS                 : Linux-3.19.0-26-generic-x86_64-with-Ubuntu-14.04-trusty
 Machine            : x86_64
singlecheeze commented 9 years ago

Installed via: sudo pip3 install -U https://github.com/crossbario/crossbar/zipball/master

singlecheeze commented 9 years ago
2015-08-27T12:14:40-0400 [Controller   3793]      __  __  __  __  __  __      __     __
2015-08-27T12:14:40-0400 [Controller   3793]     /  `|__)/  \/__`/__`|__) /\ |__)  |/  \
2015-08-27T12:14:40-0400 [Controller   3793]     \__,|  \\__/.__/.__/|__)/~~\|  \. |\__/
2015-08-27T12:14:40-0400 [Controller   3793]                                         
2015-08-27T12:14:40-0400 [Controller   3793]     Version: 0.11.0     
2015-08-27T12:14:40-0400 [Controller   3793]     Started: 2015-08-27T16:14:40.988Z
2015-08-27T12:14:40-0400 [Controller   3793] 
2015-08-27T12:14:40-0400 [Controller   3793] Starting from node directory /home/dave/xbar/.crossbar
2015-08-27T12:14:41-0400 [Controller   3793] Loading node configuration file '/home/dave/xbar/.crossbar/config.json'
2015-08-27T12:14:41-0400 [Controller   3793] Entering reactor event loop...
2015-08-27T12:14:41-0400 [Controller   3793] Process utilities not available
2015-08-27T12:14:41-0400 [Controller   3793] Joined realm 'crossbar' on node management router
2015-08-27T12:14:41-0400 [Controller   3793] No WAMPlets detected in enviroment.
2015-08-27T12:14:41-0400 [Controller   3793] Starting Router with ID 'wamprouter'...
2015-08-27T12:14:41-0400 [Router       3797] Running under CPython using EPollReactor reactor
2015-08-27T12:14:41-0400 [Router       3797] Entering event loop...
2015-08-27T12:14:41-0400 [Router       3797] Process utilities not available
2015-08-27T12:14:41-0400 [Controller   3793] Router with ID 'wamprouter' and PID 3797 started
2015-08-27T12:14:41-0400 [Router       3797] Worker ready to roll!
2015-08-27T12:14:41-0400 [Controller   3793] Router 'wamprouter': realm 'realm1' (named 'realm1') started
2015-08-27T12:14:41-0400 [Controller   3793] Router 'wamprouter': role 'role1' (named 'authenticator') started on realm 'realm1'
2015-08-27T12:14:41-0400 [Controller   3793] Router 'wamprouter': role 'role2' (named 'authorizer') started on realm 'realm1'
2015-08-27T12:14:41-0400 [Controller   3793] Router 'wamprouter': role 'role3' (named 'backend') started on realm 'realm1'
2015-08-27T12:14:41-0400 [Controller   3793] Router 'wamprouter': role 'role4' (named 'frontend') started on realm 'realm1'
2015-08-27T12:14:41-0400 [Router       3797] WampWebSocketServerFactory starting on 9090
2015-08-27T12:14:41-0400 [Controller   3793] Router 'wamprouter': transport 'loopback' started
2015-08-27T12:14:41-0400 [Router       3797] Site starting on 8081
2015-08-27T12:14:41-0400 [Controller   3793] Router 'wamprouter': transport 'web' started
2015-08-27T12:14:41-0400 [Controller   3793] Using guest worker executable '/usr/bin/python3' (executable path detected from environment)
2015-08-27T12:14:41-0400 [Controller   3793] Starting Guest with ID 'authenticator'...
2015-08-27T12:14:41-0400 [Controller   3793] Guest with ID 'authenticator' and PID 3801 started
2015-08-27T12:14:41-0400 [Controller   3793] Warning: cannot watch directory for changes - feature DirWatcher unavailable
2015-08-27T12:14:41-0400 [Controller   3793] Guest 'authenticator': started
2015-08-27T12:14:41-0400 [Controller   3793] Using guest worker executable '/usr/bin/python3' (executable path detected from environment)
2015-08-27T12:14:41-0400 [Controller   3793] Starting Guest with ID 'authorizer'...
2015-08-27T12:14:41-0400 [Controller   3793] Guest with ID 'authorizer' and PID 3802 started
2015-08-27T12:14:41-0400 [Controller   3793] Warning: cannot watch directory for changes - feature DirWatcher unavailable
2015-08-27T12:14:41-0400 [Controller   3793] Guest 'authorizer': started
2015-08-27T12:14:41-0400 [Controller   3793] Using guest worker executable '/usr/bin/python3' (executable path detected from environment)
2015-08-27T12:14:41-0400 [Controller   3793] Starting Guest with ID 'backend'...
2015-08-27T12:14:41-0400 [Controller   3793] Guest with ID 'backend' and PID 3803 started
2015-08-27T12:14:41-0400 [Controller   3793] Warning: cannot watch directory for changes - feature DirWatcher unavailable
2015-08-27T12:14:41-0400 [Controller   3793] Guest 'backend': started
2015-08-27T12:14:41-0400 [Router       3797] Cookie tracking disabled on WebSocket connection <crossbar.router.protocol.WampWebSocketServerProtocol object at 0x7ff9067d5f98>
2015-08-27T12:14:41-0400 [Guest        3801] Connected. Joining realm realm1 as user authenUser ...
2015-08-27T12:14:41-0400 [Router       3797] Traceback (most recent call last):
2015-08-27T12:14:41-0400 [Router       3797]   File "/usr/local/lib/python3.4/dist-packages/crossbar/router/session.py", line 586, in onHello
2015-08-27T12:14:41-0400 [Router       3797]     user['secret'].encode('utf8'))
2015-08-27T12:14:41-0400 [Router       3797]   File "/usr/local/lib/python3.4/dist-packages/crossbar/router/auth.py", line 104, in __init__
2015-08-27T12:14:41-0400 [Router       3797]     self.signature = auth.compute_wcs(secret, self.challenge)
2015-08-27T12:14:41-0400 [Router       3797]   File "/usr/local/lib/python3.4/dist-packages/autobahn/wamp/auth.py", line 234, in compute_wcs
2015-08-27T12:14:41-0400 [Router       3797]     assert(type(challenge) == bytes)
2015-08-27T12:14:41-0400 [Router       3797] AssertionError
2015-08-27T12:14:41-0400 [Guest        3802] Traceback (most recent call last):
2015-08-27T12:14:41-0400 [Guest        3802] File "/usr/lib/python3.4/asyncio/base_events.py", line 410, in create_connection
2015-08-27T12:14:41-0400 [Guest        3802] yield from self.sock_connect(sock, address)
2015-08-27T12:14:41-0400 [Guest        3802] File "/usr/lib/python3.4/asyncio/futures.py", line 348, in __iter__
2015-08-27T12:14:41-0400 [Guest        3802] yield self  # This tells Task to wait for completion.
2015-08-27T12:14:41-0400 [Guest        3802] File "/usr/lib/python3.4/asyncio/tasks.py", line 351, in _wakeup
2015-08-27T12:14:41-0400 [Guest        3802] value = future.result()
2015-08-27T12:14:41-0400 [Guest        3802] File "/usr/lib/python3.4/asyncio/futures.py", line 243, in result
2015-08-27T12:14:41-0400 [Guest        3802] raise self._exception
2015-08-27T12:14:41-0400 [Guest        3802] File "/usr/lib/python3.4/asyncio/selector_events.py", line 300, in _sock_connect
2015-08-27T12:14:41-0400 [Guest        3802] raise OSError(err, 'Connect call failed %s' % (address,))
2015-08-27T12:14:41-0400 [Guest        3802] ConnectionRefusedError: [Errno 111] Connect call failed ('127.0.0.1', 8080)
2015-08-27T12:14:41-0400 [Guest        3802] During handling of the above exception, another exception occurred:
2015-08-27T12:14:41-0400 [Guest        3802] Traceback (most recent call last):
2015-08-27T12:14:41-0400 [Guest        3802] File "authorization.py", line 79, in <module>
2015-08-27T12:14:41-0400 [Guest        3802] runner.run(MyBackendComponent)
2015-08-27T12:14:41-0400 [Guest        3802] File "/usr/local/lib/python3.4/dist-packages/autobahn/asyncio/wamp.py", line 162, in run
2015-08-27T12:14:41-0400 [Guest        3802] (transport, protocol) = loop.run_until_complete(coro)
2015-08-27T12:14:41-0400 [Guest        3802] File "/usr/lib/python3.4/asyncio/base_events.py", line 208, in run_until_complete
2015-08-27T12:14:41-0400 [Guest        3802] return future.result()
2015-08-27T12:14:41-0400 [Guest        3802] File "/usr/lib/python3.4/asyncio/futures.py", line 243, in result
2015-08-27T12:14:41-0400 [Guest        3802] raise self._exception
2015-08-27T12:14:41-0400 [Guest        3802] File "/usr/lib/python3.4/asyncio/tasks.py", line 298, in _step
2015-08-27T12:14:41-0400 [Guest        3802] result = coro.throw(exc)
2015-08-27T12:14:41-0400 [Guest        3802] File "/usr/lib/python3.4/asyncio/base_events.py", line 428, in create_connection
2015-08-27T12:14:41-0400 [Guest        3802] ', '.join(str(exc) for exc in exceptions)))
2015-08-27T12:14:41-0400 [Guest        3802] OSError: Multiple exceptions: [Errno 111] Connect call failed ('127.0.0.1', 8080), [Errno 101] Network is unreachable
2015-08-27T12:14:41-0400 [Guest        3803] Traceback (most recent call last):
2015-08-27T12:14:41-0400 [Guest        3803] File "/usr/lib/python3.4/asyncio/base_events.py", line 410, in create_connection
2015-08-27T12:14:41-0400 [Guest        3803] yield from self.sock_connect(sock, address)
2015-08-27T12:14:41-0400 [Guest        3803] File "/usr/lib/python3.4/asyncio/futures.py", line 348, in __iter__
2015-08-27T12:14:41-0400 [Guest        3803] yield self  # This tells Task to wait for completion.
2015-08-27T12:14:41-0400 [Guest        3803] File "/usr/lib/python3.4/asyncio/tasks.py", line 351, in _wakeup
2015-08-27T12:14:41-0400 [Guest        3803] value = future.result()
2015-08-27T12:14:41-0400 [Guest        3803] File "/usr/lib/python3.4/asyncio/futures.py", line 243, in result
2015-08-27T12:14:41-0400 [Guest        3803] raise self._exception
2015-08-27T12:14:41-0400 [Guest        3803] File "/usr/lib/python3.4/asyncio/selector_events.py", line 300, in _sock_connect
2015-08-27T12:14:41-0400 [Guest        3803] raise OSError(err, 'Connect call failed %s' % (address,))
2015-08-27T12:14:41-0400 [Guest        3803] ConnectionRefusedError: [Errno 111] Connect call failed ('127.0.0.1', 8080)
2015-08-27T12:14:41-0400 [Guest        3803] During handling of the above exception, another exception occurred:
2015-08-27T12:14:41-0400 [Guest        3803] Traceback (most recent call last):
2015-08-27T12:14:41-0400 [Guest        3803] File "backend.py", line 229, in <module>
2015-08-27T12:14:41-0400 [Guest        3803] runner.run(MyBackendComponent)
2015-08-27T12:14:41-0400 [Guest        3803] File "/usr/local/lib/python3.4/dist-packages/autobahn/asyncio/wamp.py", line 162, in run
2015-08-27T12:14:41-0400 [Guest        3803] (transport, protocol) = loop.run_until_complete(coro)
2015-08-27T12:14:41-0400 [Guest        3803] File "/usr/lib/python3.4/asyncio/base_events.py", line 208, in run_until_complete
2015-08-27T12:14:41-0400 [Guest        3803] return future.result()
2015-08-27T12:14:41-0400 [Guest        3803] File "/usr/lib/python3.4/asyncio/futures.py", line 243, in result
2015-08-27T12:14:41-0400 [Guest        3803] raise self._exception
2015-08-27T12:14:41-0400 [Guest        3803] File "/usr/lib/python3.4/asyncio/tasks.py", line 298, in _step
2015-08-27T12:14:41-0400 [Guest        3803] result = coro.throw(exc)
2015-08-27T12:14:41-0400 [Guest        3803] File "/usr/lib/python3.4/asyncio/base_events.py", line 428, in create_connection
2015-08-27T12:14:41-0400 [Guest        3803] ', '.join(str(exc) for exc in exceptions)))
2015-08-27T12:14:41-0400 [Guest        3803] OSError: Multiple exceptions: [Errno 111] Connect call failed ('127.0.0.1', 8080), [Errno 101] Network is unreachable
2015-08-27T12:14:41-0400 [Controller   3793] Guest authorizer exited with error A process has ended with a probable error condition: process ended with exit code 1.
2015-08-27T12:14:41-0400 [Controller   3793] Guest backend exited with error A process has ended with a probable error condition: process ended with exit code 1.
oberstet commented 9 years ago

you seem to be running a guest worker which is a Python 3 / asyncio component, but the guest worker fails to connect back to the router worker: "Network is unreachable"

the root cause is this assert that breaks:

2015-08-27T12:14:41-0400 [Router 3797] File "/usr/local/lib/python3.4/dist-packages/autobahn/wamp/auth.py", line 234, in compute_wcs
2015-08-27T12:14:41-0400 [Router 3797] assert(type(challenge) == bytes)
2015-08-27T12:14:41-0400 [Router 3797] AssertionError

So yes, there might lurk a bug with WAMP-CRA + Python 3 + asyncio at least.

singlecheeze commented 9 years ago

Yes, I am running 3 guest workers. Please see my jason.config below:

{
   "controller": {
   },
   "workers": [
      {
         "id": "wamprouter",
         "type": "router",
         "options": {
            "title": "WAMP Router"
         },
         "realms": [
            {
               "name": "realm1",
               "roles": [
                  {
                     "name": "authenticator",
                     "permissions": [
                        {
                           "uri": "com.aurora.authenticate",
                           "register": true
                        }
                     ]
                  },
                  {
                     "name": "authorizer",
                     "permissions": [
                        {
                           "uri": "com.aurora.authorize",
                           "register": true
                        }
                     ]
                  },
                  {
                     "name": "backend",
                     "authorizer": "com.aurora.authorize"
                  },
                  {
                     "name": "frontend",
                     "authorizer": "com.aurora.authorize"
                  }
               ]
            }
         ],
         "transports": [
            {
               "id": "loopback",
               "type": "websocket",
               "endpoint": {
                  "type": "tcp",
                  "port": 9090,
                  "interface": "127.0.0.1"
               },
               "auth": {
                  "wampcra": {
                     "type": "static",
                     "users": {
                        "authenUser": {
                           "secret": "prq7+YkJ1/KlW1X0YczMHw==",
                           "role": "authenticator",
                           "salt": "salt123",
                           "iterations": 100,
                           "keylen": 16
                        }
                     }
                  }
               },
               "debug": false,
               "options": {
                  "compression": {
                     "deflate": {
                        "request_no_context_takeover": false,
                        "request_max_window_bits": 11,
                        "no_context_takeover": false,
                        "max_window_bits": 11,
                        "memory_level": 4
                     }
                  },
                  "auto_ping_interval": 10000,
                  "auto_ping_timeout": 5000,
                  "auto_ping_size": 4
               }
            },
            {
               "id": "web",
               "type": "web",
               "endpoint": {
                  "type": "tcp",
                  "port": 8081
               },
               "paths": {
                  "/": {
                     "type": "static",
                     "directory": "../frontend"
                  },
                  "ws": {
                     "type": "websocket",
                     "url": "ws://localhost:8080/ws",
                     "auth": {
                        "wampcra": {
                           "type": "dynamic",
                           "authenticator": "com.aurora.authenticate"
                        }
                     },
                     "debug": false,
                     "options": {
                        "compression": {
                           "deflate": {
                              "request_no_context_takeover": false,
                              "request_max_window_bits": 11,
                              "no_context_takeover": false,
                              "max_window_bits": 11,
                              "memory_level": 4
                           }
                        },
                        "auto_ping_interval": 10000,
                        "auto_ping_timeout": 5000,
                        "auto_ping_size": 4
                     }
                  }
               }
            }
         ]
      },
      {
         "id": "authenticator",
         "type": "guest",
         "executable": "python3",
         "arguments": ["authentication.py"],
         "options": {
           "env": {
               "vars": {
                  "PYTHONUNBUFFERED": "1"
               }
            },
            "workdir": "../backend",
            "stdout": "log",
            "stderr": "log",
            "watch": {
               "directories": ["../backend"],
               "action": "restart"
            }
         }
      },
      {
         "id": "authorizer",
         "type": "guest",
         "executable": "python3",
         "arguments": ["authorization.py"],
         "options": {
            "env": {
               "vars": {
                  "PYTHONUNBUFFERED": "1"
               }
            },
            "workdir": "../backend",
            "stdout": "log",
            "stderr": "log",
            "watch": {
               "directories": ["../backend"],
               "action": "restart"
            }
         }
      },
      {
         "id": "backend",
         "type": "guest",
         "executable": "python3",
         "arguments": ["backend.py"],
         "options": {
            "env": {
               "vars": {
                  "PYTHONUNBUFFERED": "1"
               }
            },
            "workdir": "../backend",
            "stdout": "log",
            "stderr": "log",
            "watch": {
               "directories": ["../backend"],
               "action": "restart"
            }
         }
      }
   ]
}
meejah commented 9 years ago

I reduced the above to just the "authorizor" part, it works for me on Crossbar master + Autobahn master or 0.10.5-2 (with crossbar running on python2, and the guest on python 3.4.2). My onChallenge looks like this:

    def onChallenge(self, challenge):
        signature = auth.compute_wcs(
            "prq7+YkJ1/KlW1X0YczMHw==".encode('utf8'),
            challenge.extra['challenge'].encode('utf8')
        )
        return signature.decode('ascii')                                                                                                
singlecheeze commented 9 years ago

And mine.... they look equivalent to me, only difference is I'm running crossbar in python 3.4.0. Could this be a bytes problem? Going to try on 3.4.2.....

One thing to note, latest Autobahn|JS for my frontend is at 0.9.6 from (I know I'm not even getting that far, just not sure if it needs and update too): https://autobahn.s3.amazonaws.com/autobahnjs/latest/autobahn.min.jgz

def onChallenge(self, challenge):
        # print("Authentication challenge received: {}".format(challenge))
        if challenge.method == "wampcra":
            if'salt' in challenge.extra:
                key = auth.derive_key(PASSWORD.encode('utf8'),
                                      challenge.extra['salt'].encode('utf8'),
                                      challenge.extra.get('iterations', None),
                                      challenge.extra.get('keylen', None))
            else:
                key = PASSWORD.encode('utf8')

            signature = auth.compute_wcs(key, challenge.extra['challenge'].encode('utf8'))
            return signature.decode('ascii')
        else:
            raise Exception("Don't know how to compute challenge for authmethod {}".format(challenge.method))
oberstet commented 9 years ago

One thing to note ..

So what is the point? WAMP-CRA (salted and unsalted) works with AutobahnJS.

singlecheeze commented 9 years ago

Just commenting that there is a version difference between Autobahn|JS and Autobahn|Python... not sure if things need to be updated that's all :-)

singlecheeze commented 9 years ago

@meejah would you be willing to test crossbar in python 3.4.0 and 3.4.2...

I think I just boned my Ubuntu server after mistyping installing 3.4.2...

meejah commented 9 years ago

@singlecheeze ah, you're running crossbar itself in Python3? (I did run my guest worker in 3.4.2, and that works to a crossbar on 2.7.x).

Yes, running crossbar itself in Python 3.4.2 I see the assert(type(challenge)) == bytes error (on the router side)

meejah commented 9 years ago

For now, you can work around it by NOT doing the .decode('ascii') and simply return signature in your onAuthenticate call...

meejah commented 9 years ago

Ah, sorry that's not sufficient to work around it. Essentially a bytes vs str encoding issue on Python3 with the "challenge" etc. @oberstet I'm not sure why we insist that the challenge is bytes? (It makes some sense, but auth.py isn't ensuring that properly, hence the asserts...).

Meta-thing: maybe we should add a "python3" label for bugs? (That is, if it's purely a "crossbar on Python3" issue).

oberstet commented 9 years ago

@meejah we can certainly restructure that code I guess. I think the trick was to get the HMAC-SHA256 compute the correct signature making sure the input types are right. what matters is bytes on the wire and the spec https://github.com/tavendo/WAMP/blob/master/spec/advanced.md#challenge-response-authentication

meejah commented 9 years ago

Yeah, I think insisting that it's bytes is a good idea.

Might need some thinking to make sure this all works fine. crossbar.router.auth is just doing self.challenge = json.dumps(...) which will always be not-bytes on Python3 (but just adding .encode('utf8') means all signature-producing code has to NOT do .decode('ascii') as the docs currently say to do...

At this point I guess the only real "workaround" is "use Python2 to run crossbar"

meejah commented 9 years ago

I was thinking it might make some sense to re-factor the auth code a little so it's easier to use and at the same time harder to pass the "wrong thing" to compute_wcs (e.g. it's really easy to accidentally pass the actual secret instead of derived key)

Also, I'm not sure of wider implications, but WCS_SECRET_CHARSET is awfully close to url-safe base64 encoding and it might be worth simply using that instead...?

It's also not safe to use random for cryptographic secrets so generate_wcs should probably actually be something like return b64encode(os.urandom(32)) (this method isn't actually used by crossbar, but still).

meejah commented 9 years ago

@oberstet Hmm, looking at the spec, maybe it's actually better to specify the encoding and insist that the challenge is always a string in that particular encoding (e.g. utf8? ascii?) instead of bytes since the spec says it "MUST BE a JSON serialized object". According to Python docs, json.dumps will always be returning an ASCII str object, with any non-ASCII characters escaped (so this could be put into the WAMP spec too). I'm unsure how this might affect non-Python implementations...

singlecheeze commented 9 years ago

Thank you @meejah for taking a close look at this!!!

I'll hit you guys up on IRC if that's still something you guys use daily too? On Aug 27, 2015 8:31 PM, "meejah" notifications@github.com wrote:

@oberstet https://github.com/oberstet Hmm, looking at the spec, maybe it's actually better to specify the encoding and insist that the challenge is always a string in that particular encoding (e.g. utf8? ascii?) instead of bytes since the spec says it "MUST BE a JSON serialized object". According to Python docs, json.dumps will always be returning an ASCII str object, with any non-ASCII characters escaped (so this could be put into the WAMP spec too). I'm unsure how this might affect non-Python implementations...

— Reply to this email directly or view it on GitHub https://github.com/crossbario/crossbar/issues/412#issuecomment-135591800 .

meejah commented 9 years ago

Yes, I'm usually idling in #autobahn -- if you put "meejah: " in front I'm way more likely to notice faster :) (I do check IRC, but do leave your client connected if I don't respond right away).

singlecheeze commented 9 years ago

https://docs.python.org/3/howto/pyporting.html#text-versus-binary-data

I think we have a conflict here

oberstet commented 9 years ago

Yes, running crossbar itself in Python 3.4.2 I see the assert(type(challenge)) == bytes error (on the router side)

The signature for WAMP-CRA is computed within the router here: https://github.com/crossbario/crossbar/blob/master/crossbar/router/auth.py#L104:

self.signature = auth.compute_wcs(secret, self.challenge)

That is, secret actually is already bytes (sidenote: the doc string on PendingAuthWampCra is wrong): https://github.com/crossbario/crossbar/blob/master/crossbar/router/session.py#L601

but self.challenge is computed as

self.challenge = json.dumps(challenge_obj)

and this isn't bytes on Python 3.

Personally, I find it "unexpected" (and I always forget it) that json.dumps produces a string (=unicode) under Python 3, not bytes. But that's how it is.

@meejah could you try changing above line to

self.challenge = json.dumps(challenge_obj, ensure_ascii=False).encode('utf8')

and see if that does away with the traceback in the router?

oberstet commented 9 years ago

Actually, there are more instances of this we should check:

(python279_1)oberstet@thinkpad-t430s:~/scm/crossbar/crossbar$ find . -name "*.py" -exec grep -Hi "json\.dumps" {} \;
./crossbar/controller/guest.py:                    self.transport.write(json.dumps(options['stdin']['value']))
./crossbar/controller/cli.py:            fd.write("{}\n".format(json.dumps(pid_data, sort_keys=False, indent=3, separators=(',', ': '))))
./crossbar/adapter/rest/publisher.py:            body = json.dumps(res, separators=(',', ':'))
./crossbar/adapter/rest/webhook.py:                                  json.loads(json.dumps(message)),
./crossbar/adapter/rest/caller.py:            body = json.dumps(res, separators=(',', ':'))
./crossbar/adapter/rest/subscriber.py:            body = json.dumps({"args": args, "kwargs": kwargs},
./crossbar/router/cookiestore.py:        self._cookie_file.write(json.dumps({
./crossbar/router/auth.py:        self.challenge = json.dumps(challenge_obj)
./crossbar/router/service.py:            if json.dumps(schema) != json.dumps(self._schemas[uri]):
./crossbar/twisted/resource.py:            self._data = json.dumps(value, sort_keys=True, indent=3, ensure_ascii=False)
./crossbar/twisted/resource.py:            self._data = json.dumps(value, separators=(',', ':'), ensure_ascii=False)

and

(python279_1)oberstet@thinkpad-t430s:~/scm/autobahn/AutobahnPython$ find autobahn/ -name "*.py" -exec grep -Hi "json\.dumps" {} \;
autobahn/wamp/role.py:        return json.dumps(self.__dict__)
autobahn/wamp/test/test_auth.py:        challenge = json.dumps([1, 2, 3], ensure_ascii=False).encode('utf8')
autobahn/wamp/serializer.py:        return ujson.dumps(obj, double_precision=15, ensure_ascii=False)
autobahn/wamp/serializer.py:        return json.dumps(obj, separators=(',', ':'), ensure_ascii=False)
autobahn/twisted/longpoll.py:        payload = json.dumps(result)
autobahn/websocket/protocol.py:        return json.dumps(self.__json__())
autobahn/websocket/protocol.py:        return json.dumps(self.__json__())
autobahn/websocket/protocol.py:        return json.dumps(self.__json__())
singlecheeze commented 9 years ago

Thank you Tobias! On Aug 31, 2015 6:59 PM, "Tobias Oberstein" notifications@github.com wrote:

Actually, there are more instances of this we should check:

(python279_1)oberstet@thinkpad-t430s:~/scm/crossbar/crossbar$ find . -name "*.py" -exec grep -Hi "json.dumps" {} \;./crossbar/controller/guest.py: self.transport.write(json.dumps(options['stdin']['value']))./crossbar/controller/cli.py: fd.write("{}\n".format(json.dumps(pid_data, sort_keys=False, indent=3, separators=(',', ': '))))./crossbar/adapter/rest/publisher.py: body = json.dumps(res, separators=(',', ':'))./crossbar/adapter/rest/webhook.py: json.loads(json.dumps(message)),./crossbar/adapter/rest/caller.py: body = json.dumps(res, separators=(',', ':'))./crossbar/adapter/rest/subscriber.py: body = json.dumps({"args": args, "kwargs": kwargs},./crossbar/router/cookiestore.py: self._cookie_file.write(json.dumps({./crossbar/router/auth.py: self.challenge = json.dumps(challenge_obj)./crossbar/router/service.py: if json.dumps(schema) != json.dumps(self._schemas[uri]):./crossbar/twisted/resource.py: self._data = json.dumps(value, sort_keys=True, indent=3, ensure_ascii=False)./crossbar/twisted/resource.py: self._data = json.dumps(value, separators=(',', ':'), ensure_ascii=False)

and

(python279_1)oberstet@thinkpad-t430s:~/scm/autobahn/AutobahnPython$ find autobahn/ -name "*.py" -exec grep -Hi "json.dumps" {} \;autobahn/wamp/role.py: return json.dumps(self.dict)autobahn/wamp/test/test_auth.py: challenge = json.dumps([1, 2, 3], ensure_ascii=False).encode('utf8')autobahn/wamp/serializer.py: return ujson.dumps(obj, double_precision=15, ensure_ascii=False)autobahn/wamp/serializer.py: return json.dumps(obj, separators=(',', ':'), ensure_ascii=False)autobahn/twisted/longpoll.py: payload = json.dumps(result)autobahn/websocket/protocol.py: return json.dumps(self.json())autobahn/websocket/protocol.py: return json.dumps(self.json())autobahn/websocket/protocol.py: return json.dumps(self.json())

— Reply to this email directly or view it on GitHub https://github.com/crossbario/crossbar/issues/412#issuecomment-136522924 .

singlecheeze commented 9 years ago

Also of side note... in python 3 isn't the correct arg 'utf-8' instead of 'utf8' ? Or does the method accept both? On Aug 31, 2015 6:59 PM, "Tobias Oberstein" notifications@github.com wrote:

Actually, there are more instances of this we should check:

(python279_1)oberstet@thinkpad-t430s:~/scm/crossbar/crossbar$ find . -name "*.py" -exec grep -Hi "json.dumps" {} \;./crossbar/controller/guest.py: self.transport.write(json.dumps(options['stdin']['value']))./crossbar/controller/cli.py: fd.write("{}\n".format(json.dumps(pid_data, sort_keys=False, indent=3, separators=(',', ': '))))./crossbar/adapter/rest/publisher.py: body = json.dumps(res, separators=(',', ':'))./crossbar/adapter/rest/webhook.py: json.loads(json.dumps(message)),./crossbar/adapter/rest/caller.py: body = json.dumps(res, separators=(',', ':'))./crossbar/adapter/rest/subscriber.py: body = json.dumps({"args": args, "kwargs": kwargs},./crossbar/router/cookiestore.py: self._cookie_file.write(json.dumps({./crossbar/router/auth.py: self.challenge = json.dumps(challenge_obj)./crossbar/router/service.py: if json.dumps(schema) != json.dumps(self._schemas[uri]):./crossbar/twisted/resource.py: self._data = json.dumps(value, sort_keys=True, indent=3, ensure_ascii=False)./crossbar/twisted/resource.py: self._data = json.dumps(value, separators=(',', ':'), ensure_ascii=False)

and

(python279_1)oberstet@thinkpad-t430s:~/scm/autobahn/AutobahnPython$ find autobahn/ -name "*.py" -exec grep -Hi "json.dumps" {} \;autobahn/wamp/role.py: return json.dumps(self.dict)autobahn/wamp/test/test_auth.py: challenge = json.dumps([1, 2, 3], ensure_ascii=False).encode('utf8')autobahn/wamp/serializer.py: return ujson.dumps(obj, double_precision=15, ensure_ascii=False)autobahn/wamp/serializer.py: return json.dumps(obj, separators=(',', ':'), ensure_ascii=False)autobahn/twisted/longpoll.py: payload = json.dumps(result)autobahn/websocket/protocol.py: return json.dumps(self.json())autobahn/websocket/protocol.py: return json.dumps(self.json())autobahn/websocket/protocol.py: return json.dumps(self.json())

— Reply to this email directly or view it on GitHub https://github.com/crossbario/crossbar/issues/412#issuecomment-136522924 .

hawkowl commented 9 years ago

@singlecheeze it accepts both, utf8 is an alias to utf-8.

singlecheeze commented 9 years ago

Bumping this... I saw the announcement for Crossbar 11 and have noticed that 10.4 has been replaced on python 2 pip. Any idea when this will be fixed? I know auth is tough and there is probably other low hanging fruit on the list but without the ability to run 10.4 on py 2 I'm at a standstill :-(

meejah commented 9 years ago

I'm about to push a PR for just this issue -- @oberstet should we move the "double-check these other things" to a separate ticket?

It might be worth putting this one fix into a 0.11.1 release since it means you can't really run crossbar on Python3 if you also want to do WAMP-CRA :/

singlecheeze commented 9 years ago

I'm VERY satisfied with the support Tavendo is providing for this product ;)

On Tue, Sep 8, 2015 at 3:37 PM, meejah notifications@github.com wrote:

I'm about to push a PR for just this issue -- @oberstet https://github.com/oberstet should we move the "double-check these other things" to a separate ticket?

It might be worth putting this one fix into a 0.11.1 release since it means you can't really run crossbar on Python3 if you also want to do WAMP-CRA :/

— Reply to this email directly or view it on GitHub https://github.com/crossbario/crossbar/issues/412#issuecomment-138678589 .

oberstet commented 9 years ago

@singlecheeze thanks for recognizing;) please spread the word ..

oberstet commented 9 years ago

@meejah yeah, CB follow up release .. good idea. lets wait another 1-2 days and see if another hot-fix worthy issue pops up and we can coalesce. it's a big release with tons of change ..

johnnywell commented 9 years ago

I can't run authenticate wamprca examples on Python 3. There's something still broken?