From f1fb7040bc3dd5ae626fa24a5160a3ee02cecd62 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone <exarkun@twistedmatrix.com> Date: Sat, 15 Jun 2019 20:14:34 -0400 Subject: [PATCH] start of a plugin implementation --- src/_secureaccesstokenauthorizer/__init__.py | 8 ++ src/_secureaccesstokenauthorizer/_plugin.py | 47 ++++++++++ .../_storage_server.py | 86 +++++++++++++++++++ .../plugins/secureaccesstokenauthorizer.py | 6 ++ 4 files changed, 147 insertions(+) create mode 100644 src/_secureaccesstokenauthorizer/_plugin.py create mode 100644 src/_secureaccesstokenauthorizer/_storage_server.py diff --git a/src/_secureaccesstokenauthorizer/__init__.py b/src/_secureaccesstokenauthorizer/__init__.py index 4990b68..51b6aad 100644 --- a/src/_secureaccesstokenauthorizer/__init__.py +++ b/src/_secureaccesstokenauthorizer/__init__.py @@ -13,3 +13,11 @@ # limitations under the License. __version__ = "0.0" + +from ._storage_server import ( + SecureAccessTokenAuthorizerStorageServer, +) + +from ._plugin import ( + SecureAccessTokenAuthorizer, +) diff --git a/src/_secureaccesstokenauthorizer/_plugin.py b/src/_secureaccesstokenauthorizer/_plugin.py new file mode 100644 index 0000000..57a8286 --- /dev/null +++ b/src/_secureaccesstokenauthorizer/_plugin.py @@ -0,0 +1,47 @@ +# Copyright 2019 PrivateStorage.io, LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +The Twisted plugin that glues the Secure Access Token system into +Tahoe-LAFS. +""" + +from zope.interface import ( + implementer, +) + +from allmydata.interfaces import ( + IFoolscapStoragePlugin, +) + +from . import ( + SecureAccessTokenAuthorizerStorageServer, +) + +@implementer(IFoolscapStoragePlugin) +class SecureAccessTokenAuthorizer(object): + """ + A storage plugin which provides a token-based access control mechanism on + top of the Tahoe-LAFS built-in storage server interface. + """ + name = u"privatestorageio-satauthz-v1" + + def get_storage_server(self, configuration, get_anonymous_storage_server): + return SecureAccessTokenAuthorizerStorageServer( + get_anonymous_storage_server(), + **configuration, + ) + + def get_storage_client(self, configuration, announcement): + raise NotImplementedError() diff --git a/src/_secureaccesstokenauthorizer/_storage_server.py b/src/_secureaccesstokenauthorizer/_storage_server.py new file mode 100644 index 0000000..aa5032f --- /dev/null +++ b/src/_secureaccesstokenauthorizer/_storage_server.py @@ -0,0 +1,86 @@ +# Copyright 2019 PrivateStorage.io, LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +A Tahoe-LAFS RIStorageServer-alike which authorizes writes and lease +updates using a per-call token. +""" + +from allmydata.interfaces import ( + RIStorageServer, +) + +MAXIMUM_TOKENS_PER_CALL = 10 +TOKEN_LENGTH = 97 + +Token = ByteStringConstraint(maxLength=TOKEN_LENGTH, minLength=TOKEN_LENGTH) +TokenList = ListOf(Token, maxLength=MAXIMUM_TOKENS_PER_CALL) + + +def add_tokens(schema): + """ + Add a ``tokens`` parameter to the given method schema. + + :param foolscap.remoteinterface.RemoteMethodSchema schema: An existing + method schema to modify. + + :return foolscap.remoteinterface.RemoteMethodSchema: A schema like + ``schema`` but with one additional required argument. + """ + return add_arguments(schema, tokens=TokenList) + + + +def add_arguments(schema, **kwargs): + new_kwargs = dict(**zip(schema.argumentNames, schema.argConstraints)) + new_kwargs.update(kwargs) + modified_schema = RemoteMethodSchema(**new_kwargs) + return modified_schema + + + +class RITokenAuthorizedStorageServer(RemoteInterface): + __remote_name__ = ( + "RITokenAuthorizedStorageServer.tahoe.privatestorage.io" + ) + + get_version = RIStorageServer["get_version"] + + allocate_buckets = add_tokens(RIStorageServer["allocate_buckets"]) + + add_lease = add_tokens(RIStorageServer["add_lease"]) + + renew_lease = add_tokens(RIStorageServer["renew_lease"]) + + get_buckets = RIStorageServer["get_buckets"] + + slot_readv = RIStorageServer["slot_readv"] + + slot_testv_and_readv_and_writev = add_tokens( + RIStorageServer["slot_testv_and_readv_and_writev"], + ) + + advise_corrupt_share = RIStorageServer["advise_corrupt_share"] + + + +@implementer(RITokenAuthorizedStorageServer) +class SecureAccessTokenAuthorizerStorageServer(proxyForInterface(RIStorageServer)): + def allocate_buckets(self, tokens, *a, **kw): + self._validate_tokens(tokens) + return super(SecureAccessTokenAuthorizerStorageServer, self).allocate_buckets(*a, **kw) + + def add_lease(self, tokens, *a, **kw): + self._validate_tokens(tokens) + return super(SecureAccessTokenAuthorizerStorageServer, self).add_lease(*a, **kw) diff --git a/src/twisted/plugins/secureaccesstokenauthorizer.py b/src/twisted/plugins/secureaccesstokenauthorizer.py index 4fa53c2..de01bbe 100644 --- a/src/twisted/plugins/secureaccesstokenauthorizer.py +++ b/src/twisted/plugins/secureaccesstokenauthorizer.py @@ -15,3 +15,9 @@ """ A drop-in to supply plugins to the Twisted plugin system. """ + +from _secureaccesstokenauthorizer import ( + SecureAccessTokenAuthorizer, +) + +storage_server = SecureAccessTokenAuthorizer() -- GitLab