org.apache.sshd.server.config.keys.ServerIdentity Maven / Gradle / Ivy
/*
* 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.server.config.keys;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.util.Collections;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.function.Function;
import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.config.keys.IdentityUtils;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.MapEntryUtils;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.server.SshServer;
/**
* Loads server identity key files - e.g., {@code /etc/ssh/ssh_host_rsa_key}
*
* @author Apache MINA SSHD Project
* @see org.apache.sshd.common.util.security.SecurityUtils#getKeyPairResourceParser()
*/
public final class ServerIdentity {
public static final String ID_FILE_PREFIX = "ssh_host_";
public static final String ID_FILE_SUFFIX = "_key";
/**
* The server's keys configuration multi-value
*/
public static final String HOST_KEY_CONFIG_PROP = "HostKey";
public static final String HOST_CERT_CONFIG_PROP = "HostCertificate";
public static final Function ID_GENERATOR = ServerIdentity::getIdentityFileName;
private ServerIdentity() {
throw new UnsupportedOperationException("No instance");
}
/**
* Sets the server's {@link KeyPairProvider} with the loaded identities - if any
*
* @param The generic server type
* @param server The {@link SshServer} to configure
* @param props The {@link Properties} holding the server's configuration - ignored if
* {@code null}/empty
* @param supportedOnly If {@code true} then ignore identities that are not supported internally
* @return The updated server
* @throws IOException If failed to access the file system
* @throws GeneralSecurityException If failed to load the keys
* @see #loadKeyPairProvider(Properties, boolean, LinkOption...)
*/
public static S setKeyPairProvider(S server, Properties props, boolean supportedOnly)
throws IOException, GeneralSecurityException {
KeyPairProvider provider = loadKeyPairProvider(props, supportedOnly, IoUtils.getLinkOptions(true));
if (provider != null) {
server.setKeyPairProvider(provider);
}
return server;
}
/**
* @param props The {@link Properties} holding the server's configuration - ignored if
* {@code null}/empty
* @param supportedOnly If {@code true} then ignore identities that are not supported internally
* @param options The {@link LinkOption}s to use when checking files existence
* @return A {@link KeyPair} for the identities - {@code null} if no identities available
* (e.g., after filtering unsupported ones)
* @throws IOException If failed to access the file system
* @throws GeneralSecurityException If failed to load the keys
* @see #loadIdentities(Properties, LinkOption...)
* @see IdentityUtils#createKeyPairProvider(Map, boolean)
*/
public static KeyPairProvider loadKeyPairProvider(Properties props, boolean supportedOnly, LinkOption... options)
throws IOException, GeneralSecurityException {
Map ids = loadIdentities(props, options);
return IdentityUtils.createKeyPairProvider(ids, supportedOnly);
}
/**
* @param props The {@link Properties} holding the server's configuration - ignored if
* {@code null}/empty
* @param options The {@link LinkOption}s to use when checking files existence
* @return A {@link Map} of the identities where key=identity type (case
* insensitive), value=the {@link KeyPair} of the identity
* @throws IOException If failed to access the file system
* @throws GeneralSecurityException If failed to load the keys
* @see #findIdentities(Properties, LinkOption...)
*/
public static Map loadIdentities(Properties props, LinkOption... options)
throws IOException, GeneralSecurityException {
Map ids = findIdentities(props, options);
return IdentityUtils.loadIdentities(
null /* server keys are not loaded in a session context */, ids,
null /* server key files are never encrypted */, IoUtils.EMPTY_OPEN_OPTIONS);
}
/**
* @param props The {@link Properties} holding the server's configuration - ignored if {@code null}/empty
* @param options The {@link LinkOption}s to use when checking files existence
* @return A {@link Map} of the found identities where key=the identity type (case insensitive)
* and value=the {@link Path} of the file holding the specific type key
* @throws IOException If failed to access the file system
* @see #getIdentityType(String)
* @see #HOST_KEY_CONFIG_PROP
* @see org.apache.sshd.common.config.ConfigFileReaderSupport#readConfigFile(Path,
* java.nio.file.OpenOption...)
*/
public static Map findIdentities(Properties props, LinkOption... options) throws IOException {
return getLocations(HOST_KEY_CONFIG_PROP, props, options);
}
/**
* @param props The {@link Properties} holding the server's configuration - ignored if {@code null}/empty
* @param options The {@link LinkOption}s to use when checking files existence
* @return A {@link Map} of the found certificates where key=the identity type (case insensitive)
* and value=the {@link Path} of the file holding the specific type key
* @throws IOException If failed to access the file system
* @see #getIdentityType(String)
* @see #HOST_CERT_CONFIG_PROP
* @see org.apache.sshd.common.config.ConfigFileReaderSupport#readConfigFile(Path,
* java.nio.file.OpenOption...)
*/
public static Map findCertificates(Properties props, LinkOption... options) throws IOException {
return getLocations(HOST_CERT_CONFIG_PROP, props, options);
}
private static Map getLocations(String configPropKey, Properties props, LinkOption... options)
throws IOException {
if (MapEntryUtils.isEmpty(props)) {
return Collections.emptyMap();
}
String keyList = props.getProperty(configPropKey);
String[] paths = GenericUtils.split(keyList, ',');
if (GenericUtils.isEmpty(paths)) {
return Collections.emptyMap();
}
Map ids = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (String p : paths) {
File file = new File(p);
Path path = file.toPath();
if (!Files.exists(path, options)) {
continue;
}
String type = getIdentityType(path.getFileName().toString());
if (GenericUtils.isEmpty(type)) {
type = p; // just in case the file name does not adhere to the standard naming convention
}
Path prev = ids.put(type, path);
ValidateUtils.checkTrue(prev == null, "Multiple mappings for type=%s", type);
}
return ids;
}
/**
* @param name The file name - ignored if {@code null}/empty
* @return The identity type - {@code null} if cannot determine it - e.g., does not start/end with the
* {@link #ID_FILE_PREFIX}/{@link #ID_FILE_SUFFIX}
*/
public static String getIdentityType(String name) {
if (GenericUtils.isEmpty(name)
|| (name.length() <= (ID_FILE_PREFIX.length() + ID_FILE_SUFFIX.length()))
|| (!name.startsWith(ID_FILE_PREFIX))
|| (!name.endsWith(ID_FILE_SUFFIX))) {
return null;
} else {
return name.substring(ID_FILE_PREFIX.length(), name.length() - ID_FILE_SUFFIX.length());
}
}
public static String getIdentityFileName(NamedResource r) {
return getIdentityFileName((r == null) ? null : r.getName());
}
/**
* @param type The identity type - e.g., {@code rsa} - ignored if {@code null}/empty
* @return The matching file name for the identity - {@code null} if no name
* @see #ID_FILE_PREFIX
* @see #ID_FILE_SUFFIX
* @see IdentityUtils#getIdentityFileName(String, String, String)
*/
public static String getIdentityFileName(String type) {
return IdentityUtils.getIdentityFileName(ID_FILE_PREFIX, type, ID_FILE_SUFFIX);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy