diff --git a/src/_secureaccesstokenauthorizer/__init__.py b/src/_secureaccesstokenauthorizer/__init__.py index 4990b680dc807e489646b6ae427a5e4973214bd0..51b6aadfbd94abea8e8d96e67e989f05d6202888 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 0000000000000000000000000000000000000000..57a8286a33c7fd27032fa804966a44ef7db71809 --- /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 0000000000000000000000000000000000000000..aa5032f5e2a3e541248fe98f8a14a92ca55dc17f --- /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 4fa53c24ef8fc0a8de39a99887d180b84bb541f0..de01bbecc90c88492a69152d72c14030115eb926 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()