Search in sources :

Example 1 with CliException

use of com.quorum.tessera.cli.CliException in project tessera by ConsenSys.

the class KeyGenCommandTest method hashicorpNoKeyOutDefinedRaisesCliException.

@Test
public void hashicorpNoKeyOutDefinedRaisesCliException() throws Exception {
    CommandLine commandLine = new CommandLine(keyGenCommand);
    commandLine.setExecutionExceptionHandler(executionExceptionHandler);
    int result = commandLine.execute("--vault.type=HASHICORP", "--vault.url=someurl");
    assertThat(executionExceptionHandler.getExceptions()).hasSize(1);
    assertThat(result).isEqualTo(executionExceptionHandler.getExitCode());
    CliException cliException = executionExceptionHandler.getExceptions().stream().map(CliException.class::cast).findFirst().get();
    assertThat(cliException).hasMessage("At least one -filename must be provided when saving generated keys in a Hashicorp Vault");
}
Also used : CommandLine(picocli.CommandLine) CliException(com.quorum.tessera.cli.CliException) Test(org.junit.Test)

Example 2 with CliException

use of com.quorum.tessera.cli.CliException in project tessera by ConsenSys.

the class OverrideUtil method setValue.

/**
 * Directly set field values using reflection.
 *
 * @param root
 * @param path
 * @param value
 */
static void setValue(Object root, String path, String value) {
    if (root == null) {
        return;
    }
    final ListIterator<String> pathTokens = Arrays.asList(path.split("\\.")).listIterator();
    final Class rootType = root.getClass();
    if (rootType.isAnonymousClass()) {
        return;
    }
    if (Map.class.isAssignableFrom(rootType)) {
        Map.class.cast(root).put(path, value);
        return;
    }
    while (pathTokens.hasNext()) {
        final String token = pathTokens.next();
        final String target;
        final String position;
        final String collectionPattern = "^(.*)\\[([0-9].*)\\]$";
        final Pattern r = Pattern.compile(collectionPattern);
        final Matcher m = r.matcher(token);
        if (m.matches()) {
            target = m.group(1);
            position = m.group(2);
            LOGGER.debug("Setting {} at position {}", target, position);
        } else {
            target = token;
            position = null;
        }
        final Field field = resolveField(rootType, target);
        field.setAccessible(true);
        final Class fieldType = field.getType();
        if (Collection.class.isAssignableFrom(fieldType)) {
            if (Objects.isNull(position)) {
                throw new CliException(path + ": position not provided for Collection parameter override " + token);
            }
            final int i = Integer.parseInt(position);
            final Class genericType = resolveCollectionParameter(field.getGenericType());
            List list = (List) Optional.ofNullable(getValue(root, field)).orElse(new ArrayList<>());
            if (isSimple(genericType)) {
                Object convertedValue = convertTo(genericType, value);
                List updated = new ArrayList(list);
                while (updated.size() <= i) {
                    Class convertedType = PRIMITIVE_LOOKUP.getOrDefault(fieldType, fieldType);
                    Object emptyValue = convertTo(convertedType, null);
                    updated.add(emptyValue);
                }
                updated.set(i, convertedValue);
                setValue(root, field, updated);
            } else {
                List<String> builder = new ArrayList<>();
                pathTokens.forEachRemaining(builder::add);
                String nestedPath = builder.stream().collect(Collectors.joining("."));
                while (list.size() <= i) {
                    final Object newObject = createInstance(genericType);
                    initialiseNestedObjects(newObject);
                    list.add(newObject);
                }
                final Object nestedObject = list.get(i);
                // update the collection's complex object
                setValue(nestedObject, nestedPath, value);
                // update the root object with the updated collection
                setValue(root, field, list);
            }
        } else if (isSimple(fieldType)) {
            Class convertedType = PRIMITIVE_LOOKUP.getOrDefault(fieldType, fieldType);
            Object convertedValue = convertTo(convertedType, value);
            setValue(root, field, convertedValue);
        } else {
            Object nestedObject = getOrCreate(root, field);
            List<String> builder = new ArrayList<>();
            pathTokens.forEachRemaining(builder::add);
            String nestedPath = builder.stream().collect(Collectors.joining("."));
            setValue(nestedObject, nestedPath, value);
            setValue(root, field, nestedObject);
        }
    }
}
Also used : Pattern(java.util.regex.Pattern) Matcher(java.util.regex.Matcher) Field(java.lang.reflect.Field) CliException(com.quorum.tessera.cli.CliException)

Example 3 with CliException

use of com.quorum.tessera.cli.CliException in project tessera by ConsenSys.

the class TesseraCommand method call.

@Override
public CliResult call() throws Exception {
    // all subcmds
    if (Objects.isNull(config)) {
        throw new NoTesseraConfigfileOptionException();
    }
    // overrides using '-o <KEY>=<VALUE>'
    overrides.forEach(this::overrideConfigValue);
    // legacy overrides using unmatched options
    if (Objects.nonNull(unmatchedEntries)) {
        LOGGER.warn("Using unmatched CLI options for config overrides is deprecated.  Use the --override option instead.");
        List<String> unmatched = new ArrayList<>(unmatchedEntries);
        for (int i = 0; i < unmatched.size(); i += 2) {
            String line = unmatched.get(i);
            if (!line.startsWith("-")) {
                throw new CliException(LEGACY_OVERRIDE_EXCEPTION_MSG);
            }
            final String target = line.replaceFirst("-{1,2}", "");
            final int nextIndex = i + 1;
            if (nextIndex > (unmatched.size() - 1)) {
                throw new CliException(LEGACY_OVERRIDE_EXCEPTION_MSG);
            }
            final String value = unmatched.get(nextIndex);
            try {
                overrideConfigValue(target, value);
            } catch (CliException ex) {
                throw new CliException(String.join("\n", LEGACY_OVERRIDE_EXCEPTION_MSG, ex.getMessage()));
            }
        }
    }
    if (recover) {
        config.setRecoveryMode(true);
    }
    final Set<ConstraintViolation<Config>> violations = validator.validate(config);
    if (!violations.isEmpty()) {
        throw new ConstraintViolationException(violations);
    }
    keyPasswordResolver.resolveKeyPasswords(config);
    pidFileMixin.createPidFile();
    serverURIOutputPath.updateConfig(config);
    return new CliResult(0, false, config);
}
Also used : CliException(com.quorum.tessera.cli.CliException) CliResult(com.quorum.tessera.cli.CliResult) ConstraintViolation(jakarta.validation.ConstraintViolation) ConstraintViolationException(jakarta.validation.ConstraintViolationException)

Example 4 with CliException

use of com.quorum.tessera.cli.CliException in project tessera by ConsenSys.

the class TesseraCommand method overrideConfigValue.

private void overrideConfigValue(String target, String newValue) {
    LOGGER.debug("Setting : {} with value(s) {}", target, newValue);
    try {
        OverrideUtil.setValue(config, target, newValue);
    } catch (ReflectException ex) {
        throw new CliException(ex.getMessage());
    }
    LOGGER.debug("Set : {} with value(s) {}", target, newValue);
}
Also used : CliException(com.quorum.tessera.cli.CliException) ReflectException(com.quorum.tessera.reflect.ReflectException)

Example 5 with CliException

use of com.quorum.tessera.cli.CliException in project tessera by ConsenSys.

the class KeyGenCommand method call.

@Override
public CliResult call() throws IOException {
    if (Objects.nonNull(fileUpdateOptions) && Objects.isNull(fileUpdateOptions.getConfig())) {
        throw new CliException("Missing required argument(s): --configfile=<config>");
    }
    final EncryptorConfig encryptorConfig = Optional.ofNullable(fileUpdateOptions).map(KeyGenFileUpdateOptions::getConfig).map(Config::getEncryptor).orElseGet(() -> Optional.ofNullable(encryptorOptions).map(EncryptorOptions::parseEncryptorConfig).orElse(EncryptorConfig.getDefault()));
    final KeyVaultOptions keyVaultOptions = Optional.ofNullable(keyVaultConfigOptions).map(KeyVaultConfigOptions::getHashicorpSecretEnginePath).map(KeyVaultOptions::new).orElse(null);
    final KeyVaultConfig keyVaultConfig;
    if (keyVaultConfigOptions == null) {
        keyVaultConfig = null;
    } else if (keyVaultConfigOptions.getVaultType() == null) {
        throw new CliException("Key vault type either not provided or not recognised");
    } else if (fileUpdateOptions != null) {
        keyVaultConfig = Optional.of(fileUpdateOptions).map(KeyGenFileUpdateOptions::getConfig).map(Config::getKeys).flatMap(c -> c.getKeyVaultConfig(keyVaultConfigOptions.getVaultType())).orElse(null);
    } else {
        final KeyVaultHandler keyVaultHandler = new DispatchingKeyVaultHandler();
        keyVaultConfig = keyVaultHandler.handle(keyVaultConfigOptions);
        if (keyVaultConfig.getKeyVaultType() == KeyVaultType.HASHICORP) {
            if (Objects.isNull(keyOut)) {
                throw new CliException("At least one -filename must be provided when saving generated keys in a Hashicorp Vault");
            }
        }
        final Set<ConstraintViolation<KeyVaultConfig>> violations = validator.validate(keyVaultConfig);
        if (!violations.isEmpty()) {
            throw new ConstraintViolationException(violations);
        }
    }
    final KeyGenerator keyGenerator = keyGeneratorFactory.create(keyVaultConfig, encryptorConfig);
    final List<String> newKeyNames = Optional.ofNullable(keyOut).filter(Predicate.not(List::isEmpty)).map(List::copyOf).orElseGet(() -> List.of(""));
    final List<ConfigKeyPair> newConfigKeyPairs = newKeyNames.stream().map(name -> keyGenerator.generate(name, argonOptions, keyVaultOptions)).collect(Collectors.toList());
    final List<char[]> newPasswords = newConfigKeyPairs.stream().filter(Objects::nonNull).map(ConfigKeyPair::getPassword).collect(Collectors.toList());
    final List<KeyData> newKeyData = newConfigKeyPairs.stream().map(keyDataMarshaller::marshal).collect(Collectors.toList());
    if (Objects.isNull(fileUpdateOptions)) {
        return new CliResult(0, true, null);
    }
    // prepare config for addition of new keys if required
    prepareConfigForNewKeys(fileUpdateOptions.getConfig());
    if (Objects.nonNull(fileUpdateOptions.getConfigOut())) {
        if (Objects.nonNull(fileUpdateOptions.getPwdOut())) {
            passwordFileUpdaterWriter.updateAndWrite(newPasswords, fileUpdateOptions.getConfig(), fileUpdateOptions.getPwdOut());
            fileUpdateOptions.getConfig().getKeys().setPasswordFile(fileUpdateOptions.getPwdOut());
        }
        configFileUpdaterWriter.updateAndWrite(newKeyData, keyVaultConfig, fileUpdateOptions.getConfig(), fileUpdateOptions.getConfigOut());
    } else {
        configFileUpdaterWriter.updateAndWriteToCLI(newKeyData, keyVaultConfig, fileUpdateOptions.getConfig());
    }
    return new CliResult(0, true, fileUpdateOptions.getConfig());
}
Also used : ConstraintViolation(jakarta.validation.ConstraintViolation) ConfigKeyPair(com.quorum.tessera.config.keypairs.ConfigKeyPair) Validation(jakarta.validation.Validation) java.util(java.util) Predicate(java.util.function.Predicate) Validator(jakarta.validation.Validator) IOException(java.io.IOException) Callable(java.util.concurrent.Callable) ConstraintViolationException(jakarta.validation.ConstraintViolationException) KeyVaultOptions(com.quorum.tessera.key.generation.KeyVaultOptions) Collectors(java.util.stream.Collectors) KeyGeneratorFactory(com.quorum.tessera.key.generation.KeyGeneratorFactory) PasswordFileUpdaterWriter(com.quorum.tessera.config.util.PasswordFileUpdaterWriter) com.quorum.tessera.config(com.quorum.tessera.config) KeyGenerator(com.quorum.tessera.key.generation.KeyGenerator) CliException(com.quorum.tessera.cli.CliException) CliResult(com.quorum.tessera.cli.CliResult) ConfigFileUpdaterWriter(com.quorum.tessera.config.util.ConfigFileUpdaterWriter) CommandLine(picocli.CommandLine) KeyVaultOptions(com.quorum.tessera.key.generation.KeyVaultOptions) ConfigKeyPair(com.quorum.tessera.config.keypairs.ConfigKeyPair) CliException(com.quorum.tessera.cli.CliException) CliResult(com.quorum.tessera.cli.CliResult) ConstraintViolation(jakarta.validation.ConstraintViolation) ConstraintViolationException(jakarta.validation.ConstraintViolationException) KeyGenerator(com.quorum.tessera.key.generation.KeyGenerator)

Aggregations

CliException (com.quorum.tessera.cli.CliException)8 CliResult (com.quorum.tessera.cli.CliResult)3 ConstraintViolation (jakarta.validation.ConstraintViolation)3 ConstraintViolationException (jakarta.validation.ConstraintViolationException)3 Test (org.junit.Test)3 CommandLine (picocli.CommandLine)3 com.quorum.tessera.config (com.quorum.tessera.config)1 Config (com.quorum.tessera.config.Config)1 ConfigException (com.quorum.tessera.config.ConfigException)1 PicoCliDelegate (com.quorum.tessera.config.cli.PicoCliDelegate)1 ConfigKeyPair (com.quorum.tessera.config.keypairs.ConfigKeyPair)1 ConfigFileUpdaterWriter (com.quorum.tessera.config.util.ConfigFileUpdaterWriter)1 PasswordFileUpdaterWriter (com.quorum.tessera.config.util.PasswordFileUpdaterWriter)1 RuntimeContext (com.quorum.tessera.context.RuntimeContext)1 Discovery (com.quorum.tessera.discovery.Discovery)1 Enclave (com.quorum.tessera.enclave.Enclave)1 KeyGenerator (com.quorum.tessera.key.generation.KeyGenerator)1 KeyGeneratorFactory (com.quorum.tessera.key.generation.KeyGeneratorFactory)1 KeyVaultOptions (com.quorum.tessera.key.generation.KeyVaultOptions)1 ResidentGroupHandler (com.quorum.tessera.privacygroup.ResidentGroupHandler)1