standardizing naming convention for new plugins

pull/288/head
Andrew Mirsky 2025-08-06 14:08:45 -04:00
rodzic 04591aaaab
commit ae6d772927
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: A98E67635CDF2C39
5 zmienionych plików z 38 dodań i 25 usunięć

Wyświetl plik

@ -20,7 +20,7 @@ def default_hash_scheme() -> list[str]:
return ["argon2", "bcrypt", "pbkdf2_sha256", "scrypt"] return ["argon2", "bcrypt", "pbkdf2_sha256", "scrypt"]
class UserAuthDBPlugin(BaseAuthPlugin, BaseTopicPlugin): class UserAuthDBPlugin(BaseAuthPlugin):
def __init__(self, context: BrokerContext) -> None: def __init__(self, context: BrokerContext) -> None:
super().__init__(context) super().__init__(context)

Wyświetl plik

@ -15,7 +15,7 @@ from aiohttp import ClientResponse, ClientSession, FormData
from amqtt.broker import BrokerContext from amqtt.broker import BrokerContext
from amqtt.contexts import Action from amqtt.contexts import Action
from amqtt.plugins.base import BaseAuthPlugin, BaseTopicPlugin, BasePlugin from amqtt.plugins.base import BaseAuthPlugin, BasePlugin, BaseTopicPlugin
from amqtt.session import Session from amqtt.session import Session
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -72,7 +72,7 @@ class HttpConfig:
"""duration, in seconds, to wait for the HTTP server to respond""" """duration, in seconds, to wait for the HTTP server to respond"""
class HttpPlugin(BasePlugin): class AuthHttpPlugin(BasePlugin[BrokerContext]):
def __init__(self, context: BrokerContext) -> None: def __init__(self, context: BrokerContext) -> None:
super().__init__(context) super().__init__(context)
@ -138,7 +138,7 @@ class HttpPlugin(BasePlugin):
return f"{'https' if self.config.with_tls else 'http'}://{self.config.host}:{self.config.port}{uri}" return f"{'https' if self.config.with_tls else 'http'}://{self.config.host}:{self.config.port}{uri}"
class HttpAuthPlugin(HttpPlugin, BaseAuthPlugin): class UserAuthHttpPlugin(AuthHttpPlugin, BaseAuthPlugin):
async def authenticate(self, *, session: Session) -> bool | None: async def authenticate(self, *, session: Session) -> bool | None:
d = {"username": session.username, "password": session.password, "client_id": session.client_id} d = {"username": session.username, "password": session.password, "client_id": session.client_id}
@ -152,7 +152,7 @@ class HttpAuthPlugin(HttpPlugin, BaseAuthPlugin):
"""URI of the auth check.""" """URI of the auth check."""
class HttpTopicPlugin(HttpPlugin, BaseTopicPlugin): class TopicAuthHttpPlugin(AuthHttpPlugin, BaseTopicPlugin):
async def topic_filtering(self, *, async def topic_filtering(self, *,
session: Session | None = None, session: Session | None = None,
@ -175,5 +175,6 @@ class HttpTopicPlugin(HttpPlugin, BaseTopicPlugin):
@dataclass @dataclass
class Config(HttpConfig): class Config(HttpConfig):
"""Configuration for the HTTP Topic Plugin.""" """Configuration for the HTTP Topic Plugin."""
topic_uri: str = "/acl" topic_uri: str = "/acl"
"""URI of the topic check.""" """URI of the topic check."""

Wyświetl plik

@ -1,7 +1,7 @@
# Relational Database for Authentication and Authorization # Relational Database for Authentication and Authorization
- `amqtt.contrib.auth_db.AuthUserDBPlugin` (authentication) verify a client's ability to connect to broker - `amqtt.contrib.auth_db.UserAuthDBPlugin` (authentication) verify a client's ability to connect to broker
- `amqtt.contrib.auth_db.AuthTopicDBPlugin` (authorization) determine a client's access to topics - `amqtt.contrib.auth_db.TopicAuthDBPlugin` (authorization) determine a client's access to topics
Relational database access is supported using SQLAlchemy so MySQL, MariaDB, Postgres and SQLite support is available. Relational database access is supported using SQLAlchemy so MySQL, MariaDB, Postgres and SQLite support is available.

Wyświetl plik

@ -1,9 +1,16 @@
# Authentication & Authorization via external HTTP server # Authentication & Authorization via external HTTP server
`amqtt.contrib.http.HttpAuthPlugin`
If clients accessing the broker are managed by another application, it can implement API endpoints If clients accessing the broker are managed by another application, it can implement API endpoints
that respond with information about client authenticated and topic-level authorization. that respond with information about client authentication and/or topic-level authorization.
- `amqtt.contrib.http.UserAuthHttpPlugin` (client authentication)
- `amqtt.contrib.http.TopicAuthHttpPlugin` (topic authorization)
Configuration of these plugins is identical (except for the uri name) so that they can be used independently, if desired.
## User Auth
See the [Request and Response Modes](#request-response-modes) section below for details on `params_mode` and `response_mode`.
!!! info "browser-based mqtt over websockets" !!! info "browser-based mqtt over websockets"
@ -35,9 +42,18 @@ that respond with information about client authenticated and topic-level authori
try { try {
const clientMqtt = await mqtt.connect(url, options); const clientMqtt = await mqtt.connect(url, options);
See the [Request and Response Modes](#request-response-modes) section below for details on `params_mode` and `response_mode`. ::: amqtt.contrib.http.UserAuthHttpPlugin.Config
options:
show_source: false
heading_level: 4
extra:
class_style: "simple"
::: amqtt.contrib.http.HttpAuthPlugin.Config ## Topic ACL
See the [Request and Response Modes](#request-response-modes) section below for details on `params_mode` and `response_mode`.
::: amqtt.contrib.http.TopicAuthHttpPlugin.Config
options: options:
show_source: false show_source: false
heading_level: 4 heading_level: 4
@ -57,10 +73,6 @@ format will depend on `params_mode` configuration attribute (`json` or `form`).:
- password *(str)* - password *(str)*
- client_id *(str)* - client_id *(str)*
*For superuser validation, the request will contain:*
- username *(str)*
*For acl check, the request will contain:* *For acl check, the request will contain:*
- username *(str)* - username *(str)*
@ -75,8 +87,8 @@ All endpoints should respond with the following, dependent on `response_mode` co
- status code: 2xx (granted) or 4xx(denied) or 5xx (noop) - status code: 2xx (granted) or 4xx(denied) or 5xx (noop)
!!! note "5xx response" !!! note "5xx response"
**noop** (no operation): plugin will not participate in the filtering operation and will defer to another **noop** (no operation): plugin will not participate in the operation and will defer to another
topic filtering plugin to determine access. if there is no other topic filtering plugin, access will be denied. plugin to determine access. if there is no other auth/filtering plugin, access will be denied.
*In `json` mode:* *In `json` mode:*
@ -87,8 +99,8 @@ All endpoints should respond with the following, dependent on `response_mode` co
or { 'error': 'optional error message' } (noop) or { 'error': 'optional error message' } (noop)
!!! note "excluded 'ok' key" !!! note "excluded 'ok' key"
**noop** (no operation): plugin will not participate in the filtering operation and will defer to another **noop** (no operation): plugin will not participate in the operation and will defer to another
topic filtering plugin to determine access. if there is no other topic filtering plugin, access will be denied. plugin to determine access. if there is no other auth/filtering plugin, access will be denied.
*In `text` mode:* *In `text` mode:*

Wyświetl plik

@ -8,7 +8,7 @@ from aiohttp.web import Response
from amqtt.broker import BrokerContext, Broker from amqtt.broker import BrokerContext, Broker
from amqtt.contexts import Action from amqtt.contexts import Action
from amqtt.contrib.http import HttpAuthPlugin, ParamsMode, ResponseMode, RequestMethod, HttpTopicPlugin from amqtt.contrib.http import UserAuthHttpPlugin, TopicAuthHttpPlugin, ParamsMode, ResponseMode, RequestMethod
from amqtt.session import Session from amqtt.session import Session
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -135,7 +135,7 @@ async def test_request_auth_response(empty_broker, http_server, kind, url,
username, matcher, is_allowed): username, matcher, is_allowed):
context = BrokerContext(broker=empty_broker) context = BrokerContext(broker=empty_broker)
context.config = HttpAuthPlugin.Config( context.config = UserAuthHttpPlugin.Config(
host="127.0.0.1", host="127.0.0.1",
port=8080, port=8080,
user_uri=url, user_uri=url,
@ -143,7 +143,7 @@ async def test_request_auth_response(empty_broker, http_server, kind, url,
params_mode=params_mode, params_mode=params_mode,
response_mode=response_mode, response_mode=response_mode,
) )
http_acl = HttpAuthPlugin(context) http_acl = UserAuthHttpPlugin(context)
logger.warning(f'kind is {kind}') logger.warning(f'kind is {kind}')
session = Session() session = Session()
@ -162,7 +162,7 @@ async def test_request_topic_response(empty_broker, http_server, kind, url,
request_method, params_mode, response_mode, request_method, params_mode, response_mode,
username, matcher, is_allowed): username, matcher, is_allowed):
context = BrokerContext(broker=empty_broker) context = BrokerContext(broker=empty_broker)
context.config = HttpTopicPlugin.Config( context.config = TopicAuthHttpPlugin.Config(
host="127.0.0.1", host="127.0.0.1",
port=8080, port=8080,
topic_uri=url, topic_uri=url,
@ -170,7 +170,7 @@ async def test_request_topic_response(empty_broker, http_server, kind, url,
params_mode=params_mode, params_mode=params_mode,
response_mode=response_mode, response_mode=response_mode,
) )
http_acl = HttpTopicPlugin(context) http_acl = TopicAuthHttpPlugin(context)
s = Session() s = Session()
s.username = username s.username = username