Implemented access control for SFTP
This commit is contained in:
parent
3ad2a810f8
commit
ae8d5bff1d
6
pom.xml
6
pom.xml
@ -53,6 +53,12 @@
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-contrib</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-common</artifactId>
|
||||
|
@ -20,7 +20,7 @@ public class ConfigPasswordAuthenticator implements PasswordAuthenticator {
|
||||
{
|
||||
// Depending on our hash type, we have to try and figure out what we're doing.
|
||||
String HashType = SshdPlugin.instance.getConfig().getString("PasswordType");
|
||||
String ConfigHash = SshdPlugin.instance.getConfig().getString("Credentials." + username.trim());
|
||||
String ConfigHash = SshdPlugin.instance.getConfig().getString("Credentials." + username.trim() + ".password");
|
||||
|
||||
if (ConfigHash == null)
|
||||
SshdPlugin.instance.getLogger().warning("Config has no such user: " + username);
|
||||
|
@ -1,9 +1,13 @@
|
||||
package com.ryanmichela.sshd;
|
||||
|
||||
import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
|
||||
import org.apache.sshd.common.session.helpers.AbstractSession;
|
||||
import org.apache.sshd.server.SshServer;
|
||||
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
|
||||
import org.apache.sshd.server.session.ServerSession;
|
||||
import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
|
||||
import org.apache.sshd.server.subsystem.sftp.SimpleAccessControlSftpEventListener;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import com.ryanmichela.sshd.ConsoleShellFactory;
|
||||
@ -14,18 +18,35 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Copyright 2013 Ryan Michela
|
||||
*/
|
||||
public
|
||||
class SshdPlugin extends JavaPlugin
|
||||
public class SshdPlugin extends JavaPlugin
|
||||
{
|
||||
private SshServer sshd;
|
||||
public static SshdPlugin instance;
|
||||
|
||||
private SshServer sshd;
|
||||
public static SshdPlugin instance;
|
||||
public static List<ConfigurationSection> GetSections(ConfigurationSection source)
|
||||
{
|
||||
if (source == null)
|
||||
return null;
|
||||
|
||||
List<ConfigurationSection> nodes = new ArrayList<ConfigurationSection>();
|
||||
for (String key : source.getKeys(false))
|
||||
{
|
||||
if (source.isConfigurationSection(key))
|
||||
nodes.add(source.getConfigurationSection(key));
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@Override public void onLoad()
|
||||
{
|
||||
@ -73,9 +94,90 @@ class SshdPlugin extends JavaPlugin
|
||||
|
||||
if (getConfig().getBoolean("EnableSFTP"))
|
||||
{
|
||||
sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
|
||||
sshd.setFileSystemFactory(
|
||||
new VirtualFileSystemFactory(FileSystems.getDefault().getPath(getDataFolder().getAbsolutePath()).getParent().getParent()));
|
||||
// Handle access control for SFTP.
|
||||
SftpSubsystemFactory.Builder builder = new SftpSubsystemFactory.Builder();
|
||||
builder.addSftpEventListener(new SimpleAccessControlSftpEventListener() {
|
||||
protected boolean isAccessAllowed(ServerSession session, String remote, Path localpath)
|
||||
{
|
||||
try
|
||||
{
|
||||
ConfigurationSection UsernameNamespace = getConfig().getConfigurationSection("Credentials." + session.getUsername() + ".sftp");
|
||||
|
||||
// They don't have SFTP enabled so deny them.
|
||||
if (UsernameNamespace == null || !UsernameNamespace.getBoolean("enabled"))
|
||||
return false;
|
||||
|
||||
|
||||
List<ConfigurationSection> rules = GetSections(UsernameNamespace.getConfigurationSection("rules"));
|
||||
if (rules != null)
|
||||
{
|
||||
for (ConfigurationSection path : rules)
|
||||
{
|
||||
// Check if the requesting path matches
|
||||
if (localpath.toString().matches(path.getName()))
|
||||
{
|
||||
// Check if they have read permissions
|
||||
if (path.getBoolean("readable"))
|
||||
return true;
|
||||
|
||||
getLogger().info(String.format("Denied %s read access to \"%s\" matching rule \"%s\"", session.getUsername(), localpath.toString(), path.getName()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return UsernameNamespace.getString("default").equalsIgnoreCase("allow");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// Automatically deny.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isModificationAllowed(ServerSession session, String remote, Path localpath)
|
||||
{
|
||||
try
|
||||
{
|
||||
ConfigurationSection UsernameNamespace = getConfig().getConfigurationSection("Credentials." + session.getUsername() + ".sftp");
|
||||
|
||||
// They don't have SFTP enabled so deny them.
|
||||
if (UsernameNamespace == null || !UsernameNamespace.getBoolean("enabled"))
|
||||
return false;
|
||||
|
||||
// Check a list of files against a path trying to be accessed.
|
||||
List<ConfigurationSection> rules = GetSections(UsernameNamespace.getConfigurationSection("rules"));
|
||||
if (rules != null)
|
||||
{
|
||||
for (ConfigurationSection path : rules)
|
||||
{
|
||||
// Check if the requesting path matches
|
||||
if (localpath.toString().matches(path.getName()))
|
||||
{
|
||||
// Check if they have read permissions
|
||||
if (path.getBoolean("writeable"))
|
||||
return true;
|
||||
|
||||
getLogger().info(String.format("Denied %s modifications to \"%s\" matching rule \"%s\"", session.getUsername(), localpath.toString(), path.getName()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return UsernameNamespace.getString("default").equalsIgnoreCase("allow");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// Automatically deny.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sshd.setSubsystemFactories(Collections.singletonList(builder.build()));
|
||||
sshd.setFileSystemFactory(new VirtualFileSystemFactory(FileSystems.getDefault().getPath(getDataFolder().getAbsolutePath()).getParent().getParent()));
|
||||
}
|
||||
|
||||
this.getCommand("mkpasswd").setExecutor(new MkpasswdCommand());
|
||||
@ -95,11 +197,16 @@ class SshdPlugin extends JavaPlugin
|
||||
{
|
||||
try
|
||||
{
|
||||
sshd.stop();
|
||||
// Terminate any active sessions
|
||||
for (AbstractSession as : sshd.getActiveSessions())
|
||||
as.close(true);
|
||||
// Pass "true" to stop immediately!
|
||||
sshd.stop(true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// do nothing
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,5 +37,34 @@ PasswordType: bcrypt
|
||||
|
||||
# Associate each username with a password hash (or the password if the PasswordType is set to PLAIN)
|
||||
Credentials:
|
||||
# user1: password1
|
||||
# user2: password2
|
||||
# Username (should match SSH key if using key-based authentication)
|
||||
justasic:
|
||||
# Password hash from /mkpasswd command
|
||||
password: $2a$10$Oqk83FrypRrMF35EDeoQDuidJOQEWBE0joEQ7MJFi/Oeg26wQ3fm2
|
||||
# Whether they can read, write, or have read/write permissions to console.
|
||||
console: RW
|
||||
# SFTP access for this user.
|
||||
sftp:
|
||||
# Whether SFTP is enabled for this user.
|
||||
enabled: true
|
||||
# Whether to deny by default or allow by default
|
||||
default: allow
|
||||
# Rules regarding their SFTP access.
|
||||
# These rules are relative to the server root.
|
||||
# This acts as a chroot for the server root.
|
||||
# Each path can be an absolute path or a regular expression.
|
||||
rules:
|
||||
"/path/to/file":
|
||||
# Whether the user can read the file over SFTP
|
||||
readable: true
|
||||
# Whether the user can write/modify the file over SFTP
|
||||
writeable: true
|
||||
"/path/to/regex/*":
|
||||
readable: true
|
||||
writeable: false
|
||||
"/path/to/directory/":
|
||||
readable: false
|
||||
writeable: true
|
||||
"/another/example/path":
|
||||
readable: false
|
||||
writeable: false
|
||||
|
Loading…
Reference in New Issue
Block a user