Implement anonymous and file auth plugin

HBMQTT-14
pull/8/head
Nicolas Jouanin 2015-08-29 21:25:59 +02:00
rodzic 15cea7e9fa
commit 61cdc1a0d2
7 zmienionych plików z 55 dodań i 26 usunięć

Wyświetl plik

@ -636,25 +636,26 @@ class Broker:
def authenticate(self, session: Session, listener):
"""
This method call the authenticate method on registered plugins to test user authentication.
User is considered authenticated if at least one plugin returns True.
User is considered authenticated if all plugins called returns True.
Plugins authenticate() method are supposed to return :
- True if user is authentication succeed
- False if user authentication fails
- None if authentication can't be achieved (then plugin result is then ignored)
:param session:
:param listener:
:return:
"""
returns = yield from self.plugins_manager.map_plugin_coro("authenticate", session=session)
if not returns:
self.logger.debug("Authentication plugin results: %r" % returns)
return True
else:
for res in returns:
if res:
# Consider authentication succeed if at least one plugin returns True
return True
# If all plugins returned False, authentications is failed
return True
# TODO : Handle client authentication here
return True
auth_result = True
for plugin in returns:
res = returns[plugin]
if res is False:
auth_result = False
self.logger.debug("Authentication failed due to '%s' plugin result: %s" % (plugin.name, res))
else:
self.logger.debug("'%s' plugin result: %s" % (plugin.name, res))
# If all plugins returned True, authentication is success
return auth_result
def retain_message(self, source_session, topic_name, data, qos=None):
if data is not None and data != b'':

Wyświetl plik

@ -2,6 +2,7 @@
#
# See the file license.txt for copying permission.
import logging
import asyncio
from passlib.apps import custom_app_context as pwd_context
@ -25,6 +26,7 @@ class AnonymousAuthPlugin(BaseAuthPlugin):
def __init__(self, context):
super().__init__(context)
@asyncio.coroutine
def authenticate(self, *args, **kwargs):
authenticated = super().authenticate(*args, **kwargs)
if authenticated:
@ -72,14 +74,18 @@ class FileAuthPlugin(BaseAuthPlugin):
else:
self.context.logger.debug("Configuration parameter 'password_file' not found")
@asyncio.coroutine
def authenticate(self, *args, **kwargs):
authenticated = super().authenticate(*args, **kwargs)
if authenticated:
session = kwargs.get('session', None)
hash = self._users.get(session.username, None)
if not hash:
authenticated = False
self.context.logger.debug("User '%s' unknown" % session.username)
if session.username:
hash = self._users.get(session.username, None)
if not hash:
authenticated = False
self.context.logger.debug("No hash found for user '%s'" % session.username)
else:
authenticated = pwd_context.verify(session.password, hash)
else:
authenticated = pwd_context.verify(session.password, hash)
return None
return authenticated

Wyświetl plik

@ -1,5 +1,6 @@
import logging
import asyncio
import os
from hbmqtt.broker import Broker
logger = logging.getLogger(__name__)
@ -19,6 +20,11 @@ config = {
},
},
'sys_interval': 0,
'auth': {
'allow-anonymous': False,
'password-file': os.path.join(os.path.dirname(os.path.realpath(__file__)), "passwd")
}
}
broker = Broker(config)

Wyświetl plik

@ -45,7 +45,7 @@ def test_coro():
@asyncio.coroutine
def test_coro2():
try:
future = yield from C.connect('mqtt://localhost:1883/')
future = yield from C.connect('mqtt://test:test@localhost:1883/')
future.add_done_callback(disconnected)
yield from asyncio.wait([asyncio.async(C.publish('a/b', b'TEST MESSAGE WITH QOS_1', qos=0x01))])
logger.info("messages published")

Wyświetl plik

@ -0,0 +1,2 @@
# Test user with 'test' password encrypted with sha-512
test:$6$l4zQEHEcowc1Pnv4$HHrh8xnsZoLItQ8BmpFHM4r6q5UqK3DnXp2GaTm5zp5buQ7NheY3Xt9f6godVKbEtA.hOC7IEDwnok3pbAOip.

Wyświetl plik

@ -41,6 +41,7 @@ setup(
# 'event_logger_plugin = hbmqtt.plugins.logging:EventLoggerPlugin',
'packet_logger_plugin = hbmqtt.plugins.logging:PacketLoggerPlugin',
'auth_anonymous = hbmqtt.plugins.authentication:AnonymousAuthPlugin',
'auth_file = hbmqtt.plugins.authentication:FileAuthPlugin',
],
'hbmqtt.client.plugins': [
'packet_logger_plugin = hbmqtt.plugins.logging:PacketLoggerPlugin',

Wyświetl plik

@ -5,6 +5,7 @@
import unittest
import logging
import os
import asyncio
from hbmqtt.plugins.manager import BaseContext
from hbmqtt.plugins.authentication import AnonymousAuthPlugin, FileAuthPlugin
from hbmqtt.session import Session
@ -14,6 +15,9 @@ logging.basicConfig(level=logging.DEBUG, format=formatter)
class TestAnonymousAuthPlugin(unittest.TestCase):
def setUp(self):
self.loop = asyncio.new_event_loop()
def test_allow_anonymous(self):
context = BaseContext()
context.logger = logging.getLogger(__name__)
@ -25,7 +29,8 @@ class TestAnonymousAuthPlugin(unittest.TestCase):
s = Session()
s.username = ""
auth_plugin = AnonymousAuthPlugin(context)
self.assertTrue(auth_plugin.authenticate())
ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
self.assertTrue(ret)
def test_disallow_anonymous(self):
context = BaseContext()
@ -38,7 +43,8 @@ class TestAnonymousAuthPlugin(unittest.TestCase):
s = Session()
s.username = ""
auth_plugin = AnonymousAuthPlugin(context)
self.assertFalse(auth_plugin.authenticate(session=s))
ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
self.assertFalse(ret)
def test_allow_nonanonymous(self):
context = BaseContext()
@ -51,10 +57,14 @@ class TestAnonymousAuthPlugin(unittest.TestCase):
s = Session()
s.username = "test"
auth_plugin = AnonymousAuthPlugin(context)
self.assertTrue(auth_plugin.authenticate(session=s))
ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
self.assertTrue(ret)
class TestFileAuthPlugin(unittest.TestCase):
def setUp(self):
self.loop = asyncio.new_event_loop()
def test_allow(self):
context = BaseContext()
context.logger = logging.getLogger(__name__)
@ -67,7 +77,8 @@ class TestFileAuthPlugin(unittest.TestCase):
s.username = "user"
s.password = "test"
auth_plugin = FileAuthPlugin(context)
self.assertTrue(auth_plugin.authenticate(session=s))
ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
self.assertTrue(ret)
def test_wrong_password(self):
context = BaseContext()
@ -81,7 +92,8 @@ class TestFileAuthPlugin(unittest.TestCase):
s.username = "user"
s.password = "wrong password"
auth_plugin = FileAuthPlugin(context)
self.assertFalse(auth_plugin.authenticate(session=s))
ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
self.assertFalse(ret)
def test_unknown_password(self):
context = BaseContext()
@ -95,4 +107,5 @@ class TestFileAuthPlugin(unittest.TestCase):
s.username = "some user"
s.password = "some password"
auth_plugin = FileAuthPlugin(context)
self.assertFalse(auth_plugin.authenticate(session=s))
ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
self.assertFalse(ret)