Skip to content

Instantly share code, notes, and snippets.

@helambuapps
Created January 25, 2015 03:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save helambuapps/28fbccaff23a93c37b82 to your computer and use it in GitHub Desktop.
Save helambuapps/28fbccaff23a93c37b82 to your computer and use it in GitHub Desktop.
WAMP (Web Apps Messaging Protocol) Dynamic Authentication and Authorization example
from autobahn.asyncio.wamp import ApplicationSession
from autobahn.wamp import auth
from autobahn import wamp
import asyncio
# In a real life get this from your application database
USER = 'eddie'
PASSWORD = 'secret1'
class MyBackendComponent(ApplicationSession):
# In a real life get this from your application database
USERDB = {
'joe': {
'secret': 'secret2',
'role': 'backend'
},
'peter': {
'secret': 'prq7+YkJ1/KlW1X0YczMHw==',
'role': 'frontend',
'salt': 'salt123',
'iterations': 100,
'keylen': 16
},
'jackie': {
'secret': 'forest123',
'role': 'authorizer'
}
}
@wamp.register('com.example.authenticate')
def authenticate(self, realm, authid, details):
print("authenticate called: realm = '{}', authid = '{}', details = '{}'".format(realm, authid, details))
if authid in self.USERDB:
return self.USERDB[authid]
def onConnect(self):
print("connected. joining realm {} asser {} ...".format(self.config.realm, USER))
self.join(self.config.realm, ["wampcra"], USER)
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))
@asyncio.coroutine
def onJoin(self, details):
res = yield from self.register(self)
print("{} procedures registered.".format(len(res)))
def onLeave(self, details):
print("onLeave: {}".format(details))
self.disconnect()
if __name__ == '__main__':
from autobahn.asyncio.wamp import ApplicationRunner
runner = ApplicationRunner(url="ws://localhost:9000/ws", realm="realm1")
runner.run(MyBackendComponent)
from autobahn.asyncio.wamp import ApplicationSession
from autobahn.wamp import auth
from autobahn import wamp
import asyncio
USER = 'jackie'
PASSWORD = 'forest123'
class MyBackendComponent(ApplicationSession):
@wamp.register('com.example.authorize')
def authorize(self, session, uri, action):
print("My Authorizer.authorize({}, {}, {})".format(session, uri, action))
if session['authrole'] == 'authenticator' and uri == 'com.example.authenticate' and action == 'register':
return True
elif session['authrole'] == 'frontend' and uri == 'com.example.add2' and action == 'call':
return True
elif session['authrole'] == 'backend' and uri == 'com.example.add2' and action == 'register':
return True
else:
return False
def onConnect(self):
print("connected. joining realm {} asser {} ...".format(self.config.realm, USER))
self.join(self.config.realm, ["wampcra"], USER)
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))
@asyncio.coroutine
def onJoin(self, details):
res = yield from self.register(self)
print("{} procedures registered.".format(len(res)))
def onLeave(self, details):
print("onLeave: {}".format(details))
self.disconnect()
if __name__ == '__main__':
from autobahn.asyncio.wamp import ApplicationRunner
runner = ApplicationRunner(url="ws://localhost:8080/ws", realm="realm1")
runner.run(MyBackendComponent)
from autobahn.asyncio.wamp import ApplicationSession
from autobahn.wamp import auth
from autobahn import wamp
import asyncio
USER = 'joe'
PASSWORD = 'secret2'
class MyBackendComponent(ApplicationSession):
@wamp.register('com.example.add2')
def add2(self, x, y):
return x + y
def onConnect(self):
print("connected. joining realm {} asser {} ...".format(self.config.realm, USER))
self.join(self.config.realm, ["wampcra"], USER)
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))
@asyncio.coroutine
def onJoin(self, details):
res = yield from self.register(self)
print("{} procedures registered.".format(len(res)))
def onLeave(self, details):
print("onLeave: {}".format(details))
self.disconnect()
if __name__ == '__main__':
from autobahn.asyncio.wamp import ApplicationRunner
runner = ApplicationRunner(url="ws://localhost:8080/ws", realm="realm1")
runner.run(MyBackendComponent)
{
"controller": {
},
"workers": [
{
"type": "router",
"options": {
"pythonpath": [".."]
},
"realms": [
{
"name": "realm1",
"roles": [
{
"name": "authenticator",
"permissions": [
{
"uri": "com.example.authenticate",
"register": true
}
]
},
{
"name": "authorizer",
"permissions": [
{
"uri": "com.example.authorize",
"register": true
}
]
},
{
"name": "backend",
"authorizer": "com.example.authorize"
},
{
"name": "frontend",
"authorizer": "com.example.authorize"
}
]
}
],
"transports": [
{
"type": "websocket",
"endpoint": {
"type": "tcp",
"port": 9000,
"interface": "127.0.0.1"
},
"auth": {
"wampcra": {
"type": "static",
"users": {
"eddie": {
"secret": "prq7+YkJ1/KlW1X0YczMHw==",
"role": "authenticator",
"salt": "salt123",
"iterations": 100,
"keylen": 16
}
}
}
}
},
{
"type": "web",
"endpoint": {
"type": "tcp",
"port": 8080
},
"paths": {
"/": {
"type": "static",
"directory": "../web"
},
"ws": {
"type": "websocket",
"auth": {
"wampcra": {
"type": "dynamic",
"authenticator": "com.example.authenticate"
}
}
}
}
}
]
},
{
"type": "guest",
"executable": "/path/to/python/executable",
"arguments": ["authentication.py"],
"options": {
"workdir": "..",
"watch": {
"directories": [".."],
"action": "restart"
}
}
},
{
"type": "guest",
"executable": "/path/to/python/executable",
"arguments": ["authorization.py"],
"options": {
"workdir": "..",
"watch": {
"directories": [".."],
"action": "restart"
}
}
},
{
"type": "guest",
"executable": "/path/to/python/executable",
"arguments": ["backend.py"],
"options": {
"workdir": "..",
"watch": {
"directories": [".."],
"action": "restart"
}
}
}
]
}
from autobahn.asyncio import wamp
from autobahn.wamp import auth
import asyncio
USER = 'peter'
PASSWORD = 'secret1'
class MyFrontendComponent(wamp.ApplicationSession):
def onConnect(self):
print("connected. joining realm {} asser {} ...".format(self.config.realm, USER))
self.join(self.config.realm, [u"wampcra"], USER)
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))
@asyncio.coroutine
def onJoin(self, details):
res = yield from self.call('com.example.add2', 2, 3)
print("called procedure add2 {}".format(res))
def onLeave(self, details):
print("onLeave: {}".format(details))
self.disconnect()
if __name__ == '__main__':
from autobahn.asyncio.wamp import ApplicationRunner
runner = ApplicationRunner(url="ws://localhost:8080/ws", realm="realm1")
runner.run(MyFrontendComponent)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment