diff --git a/ansible_mitogen/helpers.py b/ansible_mitogen/helpers.py index a5ec9abb..39232d45 100644 --- a/ansible_mitogen/helpers.py +++ b/ansible_mitogen/helpers.py @@ -250,7 +250,6 @@ def write_path(path, s): open(path, 'wb').write(s) - CHMOD_CLAUSE_PAT = re.compile(r'([uoga]*)([+\-=])([ugo]|[rwx]*)') CHMOD_MASKS = { 'u': stat.S_IRWXU, diff --git a/mitogen/service.py b/mitogen/service.py index 5663fbb0..b9fad1fe 100644 --- a/mitogen/service.py +++ b/mitogen/service.py @@ -35,6 +35,25 @@ import mitogen.master from mitogen.core import LOG +class Policy(object): + """ + Base security policy. + """ + def is_authorized(self, service, msg): + raise NotImplementedError() + + +class AllowAny(Policy): + def is_authorized(self, service, msg): + return True + + +class AllowParents(Policy): + def is_authorized(self, service, msg): + return (msg.auth_id in mitogen.parent_ids or + msg.auth_id == mitogen.context_id) + + class Service(object): #: Sentinel object to suppress reply generation, since returning ``None`` #: will trigger a response message containing the pickled ``None``. @@ -50,6 +69,12 @@ class Service(object): #: requests. required_args = {} + #: Policies that must authorize each message. By default only parents are + #: authorized. + policies = ( + AllowParents(), + ) + def __init__(self, router): self.router = router self.recv = mitogen.core.Receiver(router, self.handle) @@ -68,6 +93,11 @@ class Service(object): raise NotImplementedError() def dispatch_one(self, msg): + if not all(p.is_authorized(self, msg) for p in self.policies): + LOG.error('%r: unauthorized message %r', self, msg) + msg.reply(mitogen.core.CallError('Unauthorized')) + return + if len(msg.data) > self.max_message_size: LOG.error('%r: larger than permitted size: %r', self, msg) msg.reply(mitogen.core.CallError('Message size exceeded'))