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
|
||||
|
||||
import sys
|
||||
import json
|
||||
from os.path import exists, join
|
||||
|
||||
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.util.encodingutil import argv_to_abspath
|
||||
from allmydata.util import fileutil
|
||||
|
||||
|
||||
class GenerateKeypairOptions(BaseOptions):
|
||||
|
||||
@ -46,10 +56,93 @@ def derive_pubkey(options):
|
||||
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):
|
||||
"""
|
||||
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
|
||||
|
||||
|
||||
@ -59,6 +152,9 @@ class AdminCommand(BaseOptions):
|
||||
"Generate a public/private keypair, write to stdout."),
|
||||
("derive-pubkey", None, DerivePubkeyOptions,
|
||||
"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):
|
||||
if not hasattr(self, 'subOptions'):
|
||||
|
@ -282,7 +282,39 @@ class StubServer(object):
|
||||
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
|
||||
key.
|
||||
@ -423,7 +455,7 @@ class NativeStorageServer(service.MultiService):
|
||||
return False
|
||||
for gm_key in self._grid_manager_keys:
|
||||
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))
|
||||
return True
|
||||
# print("didn't validate {} keys".format(len(self._grid_manager_keys)))
|
||||
|
Loading…
x
Reference in New Issue
Block a user