mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-02-02 01:08:20 +00:00
'tahoe admin add-grid-manager-cert' command
This commit is contained in:
parent
08937c6acf
commit
d302a98672
@ -1,7 +1,17 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
from os.path import exists, join
|
||||||
|
|
||||||
from twisted.python import usage
|
from twisted.python import usage
|
||||||
|
#from allmydata.node import read_config
|
||||||
|
from allmydata.client import read_config
|
||||||
|
from allmydata.scripts.cli import _default_nodedir
|
||||||
from allmydata.scripts.common import BaseOptions
|
from allmydata.scripts.common import BaseOptions
|
||||||
|
from allmydata.util.encodingutil import argv_to_abspath
|
||||||
|
from allmydata.util import fileutil
|
||||||
|
|
||||||
|
|
||||||
class GenerateKeypairOptions(BaseOptions):
|
class GenerateKeypairOptions(BaseOptions):
|
||||||
|
|
||||||
@ -46,10 +56,93 @@ def derive_pubkey(options):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
class AddGridManagerCertOptions(BaseOptions):
|
||||||
|
|
||||||
|
optParameters = [
|
||||||
|
['filename', 'f', None, "Filename of the certificate ('-', a dash, for stdin)"],
|
||||||
|
['name', 'n', "default", "Name to give this certificate"],
|
||||||
|
]
|
||||||
|
|
||||||
|
def getSynopsis(self):
|
||||||
|
return "Usage: tahoe [global-options] admin add-grid-manager-cert [options]"
|
||||||
|
|
||||||
|
def postOptions(self):
|
||||||
|
if self['filename'] is None:
|
||||||
|
raise usage.UsageError(
|
||||||
|
"Must provide --filename option"
|
||||||
|
)
|
||||||
|
if self['filename'] == '-':
|
||||||
|
print >>self.parent.parent.stderr, "reading certificate from stdin"
|
||||||
|
data = sys.stdin.read()
|
||||||
|
if len(data) == 0:
|
||||||
|
raise usage.UsageError(
|
||||||
|
"Reading certificate from stdin failed"
|
||||||
|
)
|
||||||
|
from allmydata.storage_client import parse_grid_manager_data
|
||||||
|
try:
|
||||||
|
self.certificate_data = parse_grid_manager_data(data)
|
||||||
|
except ValueError as e:
|
||||||
|
print >>self.parent.parent.stderr, "Error parsing certificate: {}".format(e)
|
||||||
|
self.certificate_data = None
|
||||||
|
else:
|
||||||
|
with open(self['filename'], 'r') as f:
|
||||||
|
self.certificate_data = f.read()
|
||||||
|
|
||||||
|
def getUsage(self, width=None):
|
||||||
|
t = BaseOptions.getUsage(self, width)
|
||||||
|
t += (
|
||||||
|
"Adds a Grid Manager certificate to a Storage Server.\n\n"
|
||||||
|
"The certificate will be copied into the base-dir and config\n"
|
||||||
|
"will be added to 'tahoe.cfg', which will be re-written. A\n"
|
||||||
|
"restart is required for changes to take effect.\n\n"
|
||||||
|
"The human who operates a Grid Manager would produce such a\n"
|
||||||
|
"certificate and communicate it securely to you.\n"
|
||||||
|
)
|
||||||
|
return t
|
||||||
|
|
||||||
|
|
||||||
def add_grid_manager_cert(options):
|
def add_grid_manager_cert(options):
|
||||||
"""
|
"""
|
||||||
Add a new Grid Manager certificate to our config
|
Add a new Grid Manager certificate to our config
|
||||||
"""
|
"""
|
||||||
|
if options.certificate_data is None:
|
||||||
|
return 1
|
||||||
|
# XXX is there really not already a function for this?
|
||||||
|
if options.parent.parent['node-directory']:
|
||||||
|
nd = argv_to_abspath(options.parent.parent['node-directory'])
|
||||||
|
else:
|
||||||
|
nd = _default_nodedir
|
||||||
|
|
||||||
|
config = read_config(nd, "portnum")
|
||||||
|
config_path = join(nd, "tahoe.cfg")
|
||||||
|
cert_fname = "{}.cert".format(options['name'])
|
||||||
|
cert_path = config.get_config_path(cert_fname)
|
||||||
|
cert_bytes = json.dumps(options.certificate_data, indent=4) + '\n'
|
||||||
|
cert_name = options['name']
|
||||||
|
|
||||||
|
if exists(cert_path):
|
||||||
|
print >>options.parent.parent.stderr, "Already have file '{}'".format(cert_path)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
cfg = config.config # why aren't methods we call on cfg in _Config itself?
|
||||||
|
|
||||||
|
gm_certs = config.get_config("storage", "grid_manager_certificate_files", "").split()
|
||||||
|
if cert_fname not in gm_certs:
|
||||||
|
gm_certs.append(cert_fname)
|
||||||
|
cfg.set("storage", "grid_manager_certificate_files", " ".join(gm_certs))
|
||||||
|
|
||||||
|
# print("grid_manager_certificate_files in {}: {}".format(config_path, len(gm_certs)))
|
||||||
|
|
||||||
|
# write all the data out
|
||||||
|
|
||||||
|
fileutil.write(cert_path, cert_bytes)
|
||||||
|
# print("created {}: {} bytes".format(cert_fname, len(cert_bytes)))
|
||||||
|
with open(config_path, "w") as f:
|
||||||
|
cfg.write(f)
|
||||||
|
# print("wrote {}".format(config_fname))
|
||||||
|
|
||||||
|
print >>options.parent.parent.stderr, "There are now {} certificates".format(len(gm_certs))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
@ -59,6 +152,9 @@ class AdminCommand(BaseOptions):
|
|||||||
"Generate a public/private keypair, write to stdout."),
|
"Generate a public/private keypair, write to stdout."),
|
||||||
("derive-pubkey", None, DerivePubkeyOptions,
|
("derive-pubkey", None, DerivePubkeyOptions,
|
||||||
"Derive a public key from a private key."),
|
"Derive a public key from a private key."),
|
||||||
|
("add-grid-manager-cert", None, AddGridManagerCertOptions,
|
||||||
|
"Add a Grid Manager-provided certificate to a storage "
|
||||||
|
"server's config."),
|
||||||
]
|
]
|
||||||
def postOptions(self):
|
def postOptions(self):
|
||||||
if not hasattr(self, 'subOptions'):
|
if not hasattr(self, 'subOptions'):
|
||||||
|
@ -282,7 +282,39 @@ class StubServer(object):
|
|||||||
return "?"
|
return "?"
|
||||||
|
|
||||||
|
|
||||||
def _validate_grid_manager_certificate(gm_key, alleged_cert):
|
def parse_grid_manager_data(gm_data):
|
||||||
|
"""
|
||||||
|
:param gm_data: some data that might be JSON that might be a valid
|
||||||
|
Grid Manager Certificate
|
||||||
|
|
||||||
|
:returns: json data of a valid Grid Manager certificate, or an
|
||||||
|
exception if the data is not valid.
|
||||||
|
"""
|
||||||
|
|
||||||
|
required_keys = allowed_keys = [
|
||||||
|
'certificate',
|
||||||
|
'signature',
|
||||||
|
]
|
||||||
|
|
||||||
|
js = json.loads(gm_data)
|
||||||
|
for k in js.keys():
|
||||||
|
if k not in allowed_keys:
|
||||||
|
raise ValueError(
|
||||||
|
"Grid Manager certificate JSON may not contain '{}'".format(
|
||||||
|
k,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for k in allowed_keys:
|
||||||
|
if k not in js:
|
||||||
|
raise ValueError(
|
||||||
|
"Grid Manager certificate JSON must contain '{}'".format(
|
||||||
|
k,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return js
|
||||||
|
|
||||||
|
|
||||||
|
def validate_grid_manager_certificate(gm_key, alleged_cert):
|
||||||
"""
|
"""
|
||||||
:param gm_key: a VerifyingKey instance, a Grid Manager's public
|
:param gm_key: a VerifyingKey instance, a Grid Manager's public
|
||||||
key.
|
key.
|
||||||
@ -423,7 +455,7 @@ class NativeStorageServer(service.MultiService):
|
|||||||
return False
|
return False
|
||||||
for gm_key in self._grid_manager_keys:
|
for gm_key in self._grid_manager_keys:
|
||||||
for cert in self._grid_manager_certificates:
|
for cert in self._grid_manager_certificates:
|
||||||
if _validate_grid_manager_certificate(gm_key, cert):
|
if validate_grid_manager_certificate(gm_key, cert):
|
||||||
# print("valid: {}\n{}".format(gm_key, cert))
|
# print("valid: {}\n{}".format(gm_key, cert))
|
||||||
return True
|
return True
|
||||||
# print("didn't validate {} keys".format(len(self._grid_manager_keys)))
|
# print("didn't validate {} keys".format(len(self._grid_manager_keys)))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user