All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sshd.common.config.SshConfigFileReader Maven / Gradle / Ivy

There is a newer version: 2.12.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.
 */

package org.apache.sshd.common.config;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.function.Function;

import org.apache.sshd.common.BuiltinFactory;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.PropertyResolver;
import org.apache.sshd.common.cipher.BuiltinCiphers;
import org.apache.sshd.common.cipher.Cipher;
import org.apache.sshd.common.compression.BuiltinCompressions;
import org.apache.sshd.common.compression.Compression;
import org.apache.sshd.common.compression.CompressionFactory;
import org.apache.sshd.common.helpers.AbstractFactoryManager;
import org.apache.sshd.common.kex.BuiltinDHFactories;
import org.apache.sshd.common.kex.DHFactory;
import org.apache.sshd.common.kex.KeyExchange;
import org.apache.sshd.common.mac.BuiltinMacs;
import org.apache.sshd.common.mac.Mac;
import org.apache.sshd.common.signature.BuiltinSignatures;
import org.apache.sshd.common.signature.Signature;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;

/**
 * Reads and interprets some useful configurations from an OpenSSH
 * configuration file.
 *
 * @author Apache MINA SSHD Project
 * @see ssh_config(5)
 */
public final class SshConfigFileReader {
    private SshConfigFileReader() {
        throw new UnsupportedOperationException("No instance allowed");
    }

    /**
     * @param props The {@link PropertyResolver} - ignored if {@code null}/empty
     * @return A {@code ParseResult} of all the {@link NamedFactory}-ies
     * whose name appears in the string and represent a built-in cipher.
     * Any unknown name is ignored. The order of the returned result
     * is the same as the original order - bar the unknown ciphers.
     * Note: it is up to caller to ensure that the lists do not
     * contain duplicates
     * @see ConfigFileReaderSupport#CIPHERS_CONFIG_PROP CIPHERS_CONFIG_PROP
     * @see BuiltinCiphers#parseCiphersList(String)
     */
    public static BuiltinCiphers.ParseResult getCiphers(PropertyResolver props) {
        return BuiltinCiphers.parseCiphersList(
            (props == null) ? null : props.getString(ConfigFileReaderSupport.CIPHERS_CONFIG_PROP));
    }

    /**
     * @param props The {@link PropertyResolver} - ignored if {@code null}/empty
     * @return A {@code ParseResult} of all the {@link NamedFactory}-ies
     * whose name appears in the string and represent a built-in MAC. Any
     * unknown name is ignored. The order of the returned result
     * is the same as the original order - bar the unknown MACs.
     * Note: it is up to caller to ensure that the list does not
     * contain duplicates
     * @see ConfigFileReaderSupport#MACS_CONFIG_PROP MACS_CONFIG_PROP
     * @see BuiltinMacs#parseMacsList(String)
     */
    public static BuiltinMacs.ParseResult getMacs(PropertyResolver props) {
        return BuiltinMacs.parseMacsList(
            (props == null) ? null : props.getString(ConfigFileReaderSupport.MACS_CONFIG_PROP));
    }

    /**
     * @param props The {@link PropertyResolver} - ignored if {@code null}/empty
     * @return A {@code ParseResult} of all the {@link NamedFactory}
     * whose name appears in the string and represent a built-in signature. Any
     * unknown name is ignored. The order of the returned result is the
     * same as the original order - bar the unknown signatures. Note: it
     * is up to caller to ensure that the list does not contain duplicates
     * @see ConfigFileReaderSupport#HOST_KEY_ALGORITHMS_CONFIG_PROP HOST_KEY_ALGORITHMS_CONFIG_PROP
     * @see BuiltinSignatures#parseSignatureList(String)
     */
    public static BuiltinSignatures.ParseResult getSignatures(PropertyResolver props) {
        return BuiltinSignatures.parseSignatureList(
            (props == null) ? null : props.getString(ConfigFileReaderSupport.HOST_KEY_ALGORITHMS_CONFIG_PROP));
    }

    /**
     * @param props The {@link PropertyResolver} - ignored if {@code null}/empty
     * @return A {@code ParseResult} of all the {@link DHFactory}-ies
     * whose name appears in the string and represent a built-in value. Any
     * unknown name is ignored. The order of the returned result is the
     * same as the original order - bar the unknown ones. Note: it is
     * up to caller to ensure that the list does not contain duplicates
     * @see ConfigFileReaderSupport#KEX_ALGORITHMS_CONFIG_PROP KEX_ALGORITHMS_CONFIG_PROP
     * @see BuiltinDHFactories#parseDHFactoriesList(String)
     */
    public static BuiltinDHFactories.ParseResult getKexFactories(PropertyResolver props) {
        return BuiltinDHFactories.parseDHFactoriesList(
            (props == null) ? null : props.getString(ConfigFileReaderSupport.KEX_ALGORITHMS_CONFIG_PROP));
    }

    /**
     * @param props The {@link PropertyResolver} - ignored if {@code null}/empty
     * @return The matching {@link NamedFactory} for the configured value.
     * {@code null} if no configuration or unknown name specified
     * @see ConfigFileReaderSupport#COMPRESSION_PROP COMPRESSION_PROP
     */
    public static CompressionFactory getCompression(PropertyResolver props) {
        return CompressionConfigValue.fromName(
            (props == null) ? null : props.getString(ConfigFileReaderSupport.COMPRESSION_PROP));
    }

    /**
     * 

Configures an {@link AbstractFactoryManager} with the values read from * some configuration. Currently it configures:

*
    *
  • The {@link Cipher}s - via the {@link ConfigFileReaderSupport#CIPHERS_CONFIG_PROP}
  • *
  • The {@link Mac}s - via the {@link ConfigFileReaderSupport#MACS_CONFIG_PROP}
  • *
  • The {@link Signature}s - via the {@link ConfigFileReaderSupport#HOST_KEY_ALGORITHMS_CONFIG_PROP}
  • *
  • The {@link Compression} - via the {@link ConfigFileReaderSupport#COMPRESSION_PROP}
  • *
* * @param The generic factory manager * @param manager The {@link AbstractFactoryManager} to configure * @param props The {@link PropertyResolver} to use for configuration - Note: * if any known configuration value has a default and does not appear in the * properties, the default is used * @param lenient If {@code true} then any unknown configuration values are ignored. * Otherwise an {@link IllegalArgumentException} is thrown * @param ignoreUnsupported filter out unsupported configuration values (e.g., ciphers, * key exchanges, etc..). Note: if after filtering out all the unknown * or unsupported values there is an empty configuration exception is thrown * @return The configured manager */ public static M configure( M manager, PropertyResolver props, boolean lenient, boolean ignoreUnsupported) { configureCiphers(manager, props, lenient, ignoreUnsupported); configureSignatures(manager, props, lenient, ignoreUnsupported); configureMacs(manager, props, lenient, ignoreUnsupported); configureCompression(manager, props, lenient, ignoreUnsupported); return manager; } public static M configureCiphers(M manager, PropertyResolver props, boolean lenient, boolean ignoreUnsupported) { Objects.requireNonNull(props, "No properties to configure"); return configureCiphers(manager, props.getStringProperty(ConfigFileReaderSupport.CIPHERS_CONFIG_PROP, ConfigFileReaderSupport.DEFAULT_CIPHERS), lenient, ignoreUnsupported); } public static M configureCiphers( M manager, String value, boolean lenient, boolean ignoreUnsupported) { Objects.requireNonNull(manager, "No manager to configure"); BuiltinCiphers.ParseResult result = BuiltinCiphers.parseCiphersList(value); Collection unsupported = result.getUnsupportedFactories(); ValidateUtils.checkTrue(lenient || GenericUtils.isEmpty(unsupported), "Unsupported cipher(s) (%s) in %s", unsupported, value); List> factories = BuiltinFactory.setUpFactories(ignoreUnsupported, result.getParsedFactories()); manager.setCipherFactories(ValidateUtils.checkNotNullAndNotEmpty(factories, "No known/unsupported ciphers(s): %s", value)); return manager; } public static M configureSignatures(M manager, PropertyResolver props, boolean lenient, boolean ignoreUnsupported) { Objects.requireNonNull(props, "No properties to configure"); return configureSignatures(manager, props.getStringProperty(ConfigFileReaderSupport.HOST_KEY_ALGORITHMS_CONFIG_PROP, ConfigFileReaderSupport.DEFAULT_HOST_KEY_ALGORITHMS), lenient, ignoreUnsupported); } public static M configureSignatures( M manager, String value, boolean lenient, boolean ignoreUnsupported) { Objects.requireNonNull(manager, "No manager to configure"); BuiltinSignatures.ParseResult result = BuiltinSignatures.parseSignatureList(value); Collection unsupported = result.getUnsupportedFactories(); ValidateUtils.checkTrue(lenient || GenericUtils.isEmpty(unsupported), "Unsupported signatures (%s) in %s", unsupported, value); List> factories = BuiltinFactory.setUpFactories(ignoreUnsupported, result.getParsedFactories()); manager.setSignatureFactories(ValidateUtils.checkNotNullAndNotEmpty(factories, "No known/supported signatures: %s", value)); return manager; } public static M configureMacs( M manager, PropertyResolver resolver, boolean lenient, boolean ignoreUnsupported) { Objects.requireNonNull(resolver, "No properties to configure"); return configureMacs(manager, resolver.getStringProperty(ConfigFileReaderSupport.MACS_CONFIG_PROP, ConfigFileReaderSupport.DEFAULT_MACS), lenient, ignoreUnsupported); } public static M configureMacs( M manager, String value, boolean lenient, boolean ignoreUnsupported) { Objects.requireNonNull(manager, "No manager to configure"); BuiltinMacs.ParseResult result = BuiltinMacs.parseMacsList(value); Collection unsupported = result.getUnsupportedFactories(); ValidateUtils.checkTrue(lenient || GenericUtils.isEmpty(unsupported), "Unsupported MAC(s) (%s) in %s", unsupported, value); List> factories = BuiltinFactory.setUpFactories(ignoreUnsupported, result.getParsedFactories()); manager.setMacFactories(ValidateUtils.checkNotNullAndNotEmpty(factories, "No known/supported MAC(s): %s", value)); return manager; } /** * @param The generic factory manager * @param manager The {@link AbstractFactoryManager} to set up (may not be {@code null}) * @param props The (non-{@code null}) {@link PropertyResolver} containing the configuration * @param lenient If {@code true} then any unknown/unsupported configuration * values are ignored. Otherwise an {@link IllegalArgumentException} is thrown * @param xformer A {@link Function} to convert the configured {@link DHFactory}-ies * to {@link NamedFactory}-ies of {@link KeyExchange} * @param ignoreUnsupported Filter out any un-supported configurations - Note: * if after ignoring the unknown and un-supported values the result is an empty * list of factories and exception is thrown * @return The configured manager * @see ConfigFileReaderSupport#KEX_ALGORITHMS_CONFIG_PROP KEX_ALGORITHMS_CONFIG_PROP * @see ConfigFileReaderSupport#DEFAULT_KEX_ALGORITHMS DEFAULT_KEX_ALGORITHMS */ public static M configureKeyExchanges( M manager, PropertyResolver props, boolean lenient, Function> xformer, boolean ignoreUnsupported) { Objects.requireNonNull(props, "No properties to configure"); return configureKeyExchanges(manager, props.getStringProperty(ConfigFileReaderSupport.KEX_ALGORITHMS_CONFIG_PROP, ConfigFileReaderSupport.DEFAULT_KEX_ALGORITHMS), lenient, xformer, ignoreUnsupported); } public static M configureKeyExchanges( M manager, String value, boolean lenient, Function> xformer, boolean ignoreUnsupported) { Objects.requireNonNull(manager, "No manager to configure"); Objects.requireNonNull(xformer, "No DHFactory transformer"); BuiltinDHFactories.ParseResult result = BuiltinDHFactories.parseDHFactoriesList(value); Collection unsupported = result.getUnsupportedFactories(); ValidateUtils.checkTrue(lenient || GenericUtils.isEmpty(unsupported), "Unsupported KEX(s) (%s) in %s", unsupported, value); List> factories = NamedFactory.setUpTransformedFactories(ignoreUnsupported, result.getParsedFactories(), xformer); manager.setKeyExchangeFactories(ValidateUtils.checkNotNullAndNotEmpty(factories, "No known/supported KEXS(s): %s", value)); return manager; } /** * Configure the factory manager using one of the known {@link CompressionConfigValue}s. * * @param The generic factory manager * @param manager The {@link AbstractFactoryManager} to configure * @param props The configuration {@link Properties} * @param lenient If {@code true} and an unknown value is provided then * it is ignored * @param ignoreUnsupported If {@code false} then check if the compression * is currently supported before setting it * @return The configured manager - Note: if the result of filtering due * to lenient mode or ignored unsupported value is empty then no factories are set */ public static M configureCompression( M manager, PropertyResolver props, boolean lenient, boolean ignoreUnsupported) { Objects.requireNonNull(manager, "No manager to configure"); Objects.requireNonNull(props, "No properties to configure"); String value = props.getStringProperty(ConfigFileReaderSupport.COMPRESSION_PROP, ConfigFileReaderSupport.DEFAULT_COMPRESSION); CompressionFactory factory = CompressionConfigValue.fromName(value); ValidateUtils.checkTrue(lenient || (factory != null), "Unsupported compression value: %s", value); if ((factory != null) && factory.isSupported()) { manager.setCompressionFactories(Collections.singletonList(factory)); } return manager; } // accepts BOTH CompressionConfigValue(s) and/or BuiltinCompressions - including extensions public static M configureCompression(M manager, String value, boolean lenient, boolean ignoreUnsupported) { Objects.requireNonNull(manager, "No manager to configure"); CompressionFactory factory = CompressionConfigValue.fromName(value); if (factory != null) { // SSH can work without compression if (ignoreUnsupported || factory.isSupported()) { manager.setCompressionFactories(Collections.singletonList(factory)); } } else { BuiltinCompressions.ParseResult result = BuiltinCompressions.parseCompressionsList(value); Collection unsupported = result.getUnsupportedFactories(); ValidateUtils.checkTrue(lenient || GenericUtils.isEmpty(unsupported), "Unsupported compressions(s) (%s) in %s", unsupported, value); List> factories = BuiltinFactory.setUpFactories(ignoreUnsupported, result.getParsedFactories()); // SSH can work without compression if (GenericUtils.size(factories) > 0) { manager.setCompressionFactories(factories); } } return manager; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy