Basic support for token authentication on request level

This commit is contained in:
Fabio Manganiello 2018-07-05 09:15:53 +02:00
parent 7ad0724f0e
commit 81a81312e3
6 changed files with 39 additions and 20 deletions

View file

@ -78,7 +78,11 @@ class Daemon(object):
msg -- platypush.message.Message instance """ msg -- platypush.message.Message instance """
if isinstance(msg, Request): if isinstance(msg, Request):
msg.execute(n_tries=self.n_tries) try:
msg.execute(n_tries=self.n_tries)
except PermissionError:
logger.info('Dropped unauthorized request: {}'.format(msg))
self.processed_requests += 1 self.processed_requests += 1
if self.requests_to_process \ if self.requests_to_process \
and self.processed_requests >= self.requests_to_process: and self.processed_requests >= self.requests_to_process:

View file

@ -180,7 +180,11 @@ class HttpBackend(Backend):
self.logger.info('Received message on the HTTP backend: {}'.format(msg)) self.logger.info('Received message on the HTTP backend: {}'.format(msg))
if isinstance(msg, Request): if isinstance(msg, Request):
response = msg.execute(async=False) try:
response = msg.execute(async=False)
except PermissionError:
abort(401)
self.logger.info('Processing response on the HTTP backend: {}'.format(msg)) self.logger.info('Processing response on the HTTP backend: {}'.format(msg))
return str(response) return str(response)
elif isinstance(msg, Event): elif isinstance(msg, Event):

View file

@ -6,6 +6,7 @@ import sys
import time import time
import yaml import yaml
from platypush.utils import get_hash
""" Config singleton instance """ """ Config singleton instance """
_default_config_instance = None _default_config_instance = None
@ -18,8 +19,6 @@ class Config(object):
Config.init() Config.init()
- Initialize config from a custom path - Initialize config from a custom path
Config.init(config_file_path) Config.init(config_file_path)
- Set a value
Config.set('foo', 'bar')
- Get a value - Get a value
Config.get('foo') Config.get('foo')
""" """
@ -60,6 +59,9 @@ class Config(object):
self._cfgfile = cfgfile self._cfgfile = cfgfile
self._config = self._read_config_file(self._cfgfile) self._config = self._read_config_file(self._cfgfile)
if 'token' in self._config:
self._config['token_hash'] = get_hash(self._config['token'])
if 'workdir' not in self._config: if 'workdir' not in self._config:
self._config['workdir'] = self._workdir_location self._config['workdir'] = self._workdir_location
os.makedirs(self._config['workdir'], exist_ok=True) os.makedirs(self._config['workdir'], exist_ok=True)
@ -242,20 +244,7 @@ class Config(object):
""" """
global _default_config_instance global _default_config_instance
if _default_config_instance is None: _default_config_instance = Config() if _default_config_instance is None: _default_config_instance = Config()
return _default_config_instance._config[key] return _default_config_instance._config.get(key)
@staticmethod
def set(key, value):
"""
Sets a config value
Params:
key -- Config key to set
value -- Value for key
"""
global _default_config_instance
if _default_config_instance is None: _default_config_instance = Config()
_default_config_instance._config[key] = key
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View file

@ -8,10 +8,11 @@ import traceback
from threading import Thread from threading import Thread
from platypush.config import Config
from platypush.context import get_plugin from platypush.context import get_plugin
from platypush.message import Message from platypush.message import Message
from platypush.message.response import Response from platypush.message.response import Response
from platypush.utils import get_module_and_method_from_action from platypush.utils import get_hash, get_module_and_method_from_action
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -19,7 +20,8 @@ logger = logging.getLogger(__name__)
class Request(Message): class Request(Message):
""" Request message class """ """ Request message class """
def __init__(self, target, action, origin=None, id=None, backend=None, args=None): def __init__(self, target, action, origin=None, id=None, backend=None,
args=None, token=None):
""" """
Params: Params:
target -- Target node [String] target -- Target node [String]
@ -28,6 +30,7 @@ class Request(Message):
id -- Message ID, or None to get it auto-generated id -- Message ID, or None to get it auto-generated
backend -- Backend connected to the request, where the response will be delivered backend -- Backend connected to the request, where the response will be delivered
args -- Additional arguments for the action [Dict] args -- Additional arguments for the action [Dict]
token -- Authorization token, if required on the server [Str]
""" """
self.id = id if id else self._generate_id() self.id = id if id else self._generate_id()
@ -36,6 +39,7 @@ class Request(Message):
self.origin = origin self.origin = origin
self.args = args if args else {} self.args = args if args else {}
self.backend = backend self.backend = backend
self.token = token
@classmethod @classmethod
def build(cls, msg): def build(cls, msg):
@ -48,6 +52,7 @@ class Request(Message):
args['id'] = msg['id'] if 'id' in msg else cls._generate_id() args['id'] = msg['id'] if 'id' in msg else cls._generate_id()
if 'origin' in msg: args['origin'] = msg['origin'] if 'origin' in msg: args['origin'] = msg['origin']
if 'token' in msg: args['token'] = msg['token']
return cls(**args) return cls(**args)
@staticmethod @staticmethod
@ -201,6 +206,12 @@ class Request(Message):
self._send_response(response) self._send_response(response)
return response return response
token_hash = Config.get('token_hash')
if token_hash:
if self.token is None or get_hash(self.token) != token_hash:
raise PermissionError()
if async: if async:
Thread(target=_thread_func, args=(n_tries,)).start() Thread(target=_thread_func, args=(n_tries,)).start()
else: else:

View file

@ -5,6 +5,12 @@ from platypush.config import Config
from platypush.message.response import Response from platypush.message.response import Response
def action(f):
def _execute_action(*args, **kwargs):
return f(*args, **kwargs)
return _execute_action
class Plugin(object): class Plugin(object):
""" Base plugin class """ """ Base plugin class """

View file

@ -1,4 +1,5 @@
import errno import errno
import hashlib
import importlib import importlib
import logging import logging
import os import os
@ -65,5 +66,9 @@ def clear_timeout():
signal.alarm(0) signal.alarm(0)
def get_hash(s):
return hashlib.sha256(s.encode('utf-8')).hexdigest()
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et: