From 09a312e9b269f45ef46680a64b32560279798590 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Thu, 19 Nov 2015 00:01:08 -0400 Subject: [feat] use twisted IService interface to run bonafide service --- .gitignore | 1 + Makefile | 2 + README.rst | 4 ++ src/leap/bonafide/_protocol.py | 130 +++++++++++++++++++++++++++++++++++++++ src/leap/bonafide/service.py | 129 -------------------------------------- src/leap/bonafide/zmq.tac | 10 +++ src/leap/bonafide/zmq_service.py | 51 +++++++-------- 7 files changed, 173 insertions(+), 154 deletions(-) create mode 100644 Makefile create mode 100644 src/leap/bonafide/_protocol.py delete mode 100644 src/leap/bonafide/service.py create mode 100644 src/leap/bonafide/zmq.tac diff --git a/.gitignore b/.gitignore index 9ac4b93..6fbbf52 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.swp *.swo .project +*.pid dist/ build/ MANIFEST diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c311005 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +bonafide_server: + twistd -n -y src/leap/bonafide/zmq.tac diff --git a/README.rst b/README.rst index 044ac71..1a4e44e 100644 --- a/README.rst +++ b/README.rst @@ -17,4 +17,8 @@ the package in development mode by running:: from the parent folder. +To run the bonafide daemon:: + + make bonafide_server + Then you can use `bonafide_cli2 -h` to see the available commands. diff --git a/src/leap/bonafide/_protocol.py b/src/leap/bonafide/_protocol.py new file mode 100644 index 0000000..b093b9c --- /dev/null +++ b/src/leap/bonafide/_protocol.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- +# _protocol.py +# Copyright (C) 2014-2015 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +""" +Bonafide protocol. +""" +import os +import resource +from collections import defaultdict + +from leap.bonafide import config +from leap.bonafide import provider +from leap.bonafide.session import Session, OK + +from twisted.cred.credentials import UsernamePassword +from twisted.internet.defer import fail +from twisted.python import log + + +# TODO [ ] enable-disable services +# TODO [ ] read provider info + +COMMANDS = 'signup', 'authenticate', 'logout', 'stats' + + +class BonafideProtocol(object): + """ + Expose the protocol that interacts with the Bonafide Service API. + """ + + _apis = defaultdict(None) + _sessions = defaultdict(None) + + def _get_api(self, provider_id): + if provider_id in self._apis: + return self._apis[provider_id] + + # XXX lookup the provider config instead + # TODO defer the autoconfig for the provider if needed... + api = provider.Api('https://api.%s:4430' % provider_id) + self._apis[provider_id] = api + return api + + def _get_session(self, full_id, password=""): + if full_id in self._sessions: + return self._sessions[full_id] + + # TODO if password/username null, then pass AnonymousCreds + # TODO use twisted.cred instead + username, provider_id = config.get_username_and_provider(full_id) + credentials = UsernamePassword(username, password) + api = self._get_api(provider_id) + cdev_pem = os.path.expanduser( + '~/.config/leap/providers/%s/keys/ca/cacert.pem' % + provider_id) + session = Session(credentials, api, cdev_pem) + self._sessions[full_id] = session + return session + + # Service public methods + + def do_signup(self, full_id, password): + # XXX check it's unauthenticated + def return_user(result, _session): + return_code, user = result + if return_code == OK: + return user + + log.msg('SIGNUP for %s' % full_id) + session = self._get_session(full_id, password) + username, provider_id = config.get_username_and_provider(full_id) + + d = session.signup(username, password) + d.addCallback(return_user, session) + return d + + def do_authenticate(self, full_id, password): + def return_token(result, _session): + if result == OK: + return str(_session.token) + + log.msg('AUTH for %s' % full_id) + session = self._get_session(full_id, password) + d = session.authenticate() + d.addCallback(return_token, session) + return d + + def do_logout(self, full_id, password): + # XXX use the AVATAR here + log.msg('LOGOUT for %s' % full_id) + session = self._get_session(full_id) + if not session.is_authenticated: + return fail(RuntimeError("There is no session for such user")) + try: + d = session.logout() + except Exception as exc: + log.err(exc) + return fail(exc) + + d.addCallback(lambda _: self._sessions.pop(full_id)) + d.addCallback(lambda _: '%s logged out' % full_id) + return d + + def do_stats(self): + log.msg('Calculating Bonafide STATS') + mem = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + return '[+] Bonafide service: [%s sessions] [Mem usage: %s KB]' % ( + len(self._sessions), mem / 1024) + + def do_get_vpn_cert(self): + pass + + def do_get_smtp_cert(self): + pass + + def do_update_user(self): + pass diff --git a/src/leap/bonafide/service.py b/src/leap/bonafide/service.py deleted file mode 100644 index 24004fa..0000000 --- a/src/leap/bonafide/service.py +++ /dev/null @@ -1,129 +0,0 @@ -# -*- coding: utf-8 -*- -# service.py -# Copyright (C) 2014 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -""" -Bonafide service. -""" -import os -import resource -from collections import defaultdict - -from leap.bonafide import config -from leap.bonafide import provider -from leap.bonafide.session import Session, OK - -from twisted.cred.credentials import UsernamePassword -from twisted.internet.defer import fail -from twisted.python import log - - -# TODO [ ] enable-disable services -# TODO [ ] read provider info - -COMMANDS = 'signup', 'authenticate', 'logout', 'stats' - - -class BonafideService(object): - """ - Expose the Bonafide Service API. - """ - - _apis = defaultdict(None) - _sessions = defaultdict(None) - - def _get_api(self, provider_id): - if provider_id in self._apis: - return self._apis[provider_id] - - # XXX lookup the provider config instead - # TODO defer the autoconfig for the provider if needed... - api = provider.Api('https://api.%s:4430' % provider_id) - self._apis[provider_id] = api - return api - - def _get_session(self, full_id, password=""): - if full_id in self._sessions: - return self._sessions[full_id] - - # TODO if password/username null, then pass AnonymousCreds - # TODO use twisted.cred instead - username, provider_id = config.get_username_and_provider(full_id) - credentials = UsernamePassword(username, password) - api = self._get_api(provider_id) - cdev_pem = os.path.expanduser( - '~/.config/leap/providers/%s/keys/ca/cacert.pem' % - provider_id) - session = Session(credentials, api, cdev_pem) - self._sessions[full_id] = session - return session - - # Service public methods - - def do_signup(self, full_id, password): - # XXX check it's unauthenticated - def return_user(result, _session): - return_code, user = result - if return_code == OK: - return user - - log.msg('SIGNUP for %s' % full_id) - session = self._get_session(full_id, password) - username, provider_id = config.get_username_and_provider(full_id) - - d = session.signup(username, password) - d.addCallback(return_user, session) - return d - - def do_authenticate(self, full_id, password): - def return_token(result, _session): - if result == OK: - return str(_session.token) - - log.msg('AUTH for %s' % full_id) - session = self._get_session(full_id, password) - d = session.authenticate() - d.addCallback(return_token, session) - return d - - def do_logout(self, full_id, password): - # XXX use the AVATAR here - log.msg('LOGOUT for %s' % full_id) - session = self._get_session(full_id) - if not session.is_authenticated: - return fail(RuntimeError("There is no session for such user")) - try: - d = session.logout() - except Exception as exc: - log.err(exc) - return fail(exc) - - d.addCallback(lambda _: self._sessions.pop(full_id)) - d.addCallback(lambda _: '%s logged out' % full_id) - return d - - def do_stats(self): - mem = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss - return '[+] Bonafide service: [%s sessions] [Mem usage: %s KB]' % ( - len(self._sessions), mem / 1024) - - def do_get_vpn_cert(self): - pass - - def do_get_smtp_cert(self): - pass - - def do_update_user(self): - pass diff --git a/src/leap/bonafide/zmq.tac b/src/leap/bonafide/zmq.tac new file mode 100644 index 0000000..d3a9625 --- /dev/null +++ b/src/leap/bonafide/zmq.tac @@ -0,0 +1,10 @@ +# Run as: twistd -n -y zmq.tac +from twisted.application import service +from leap.bonafide.zmq_service import BonafideZMQService + +top_service = service.MultiService() +bonafide_zmq_service = BonafideZMQService() +bonafide_zmq_service.setServiceParent(top_service) + +application = service.Application("bonafide") +top_service.setServiceParent(application) diff --git a/src/leap/bonafide/zmq_service.py b/src/leap/bonafide/zmq_service.py index e33df3d..df8e234 100644 --- a/src/leap/bonafide/zmq_service.py +++ b/src/leap/bonafide/zmq_service.py @@ -15,23 +15,39 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ -Bonafide ZMQ Service +Bonafide ZMQ Service. """ from leap.bonafide import config -from leap.bonafide.service import BonafideService, COMMANDS +from leap.bonafide.protocol import BonafideProtocol, COMMANDS from txzmq import ZmqEndpoint, ZmqFactory, ZmqREPConnection +from twisted.application import service +from twisted.internet import reactor from twisted.python import log -class BonafideZmqREPConnection(ZmqREPConnection): +class BonafideZMQService(service.Service): - def initialize(self): - self._service = BonafideService() + def __init__(self): + self._bonafide = BonafideProtocol() + self._conn = None + + def startService(self): + zf = ZmqFactory() + e = ZmqEndpoint("bind", config.ENDPOINT) + self._conn = _BonafideZmqREPConnection(zf, e, self._bonafide) + reactor.callWhenRunning(self._conn.do_greet) + + +class _BonafideZmqREPConnection(ZmqREPConnection): + + def __init__(self, zf, e, bonafide): + ZmqREPConnection.__init__(self, zf, e) + self._bonafide = bonafide def do_greet(self): - print "[+] Bonafide service running..." + print "Bonafide service running..." def do_bye(self): print "[+] Bonafide service stopped. Have a nice day." @@ -58,40 +74,25 @@ class BonafideZmqREPConnection(ZmqREPConnection): elif cmd == 'signup': username, password = parts[1], parts[2] - d = self._service.do_signup(username, password) + d = self._bonafide.do_signup(username, password) d.addCallback(lambda response: defer_reply( 'REGISTERED -> %s' % response)) d.addErrback(log_err) elif cmd == 'authenticate': username, password = parts[1], parts[2] - d = self._service.do_authenticate(username, password) + d = self._bonafide.do_authenticate(username, password) d.addCallback(lambda response: defer_reply( 'TOKEN -> %s' % response)) d.addErrback(log_err) elif cmd == 'logout': username, password = parts[1], parts[2] - d = self._service.do_logout(username, password) + d = self._bonafide.do_logout(username, password) d.addCallback(lambda response: defer_reply( 'LOGOUT -> ok')) d.addErrback(log_err) elif cmd == 'stats': - response = self._service.do_stats() + response = self._bonafide.do_stats() defer_reply(response) - - -def get_zmq_connection(): - zf = ZmqFactory() - e = ZmqEndpoint("bind", config.ENDPOINT) - return BonafideZmqREPConnection(zf, e) - - -if __name__ == "__main__": - from twisted.internet import reactor - - s = get_zmq_connection() - reactor.callWhenRunning(s.initialize) - reactor.callWhenRunning(s.do_greet) - reactor.run() -- cgit v1.2.3