Problem background:
Other systems need to get files on the server when requesting my interface, but I don’t want to give them to users with more permissions.
So I want to create a new user sftpuser on Linux. This user can only download files from the directory and subdirectories I provided, and cannot perform other operations, such as logging in, uploading, modifying files, etc.
User relationship:
I need three users in total.
Because the server where my jar package is located and the file server are separate.
The files generated by the jar package interface are first generated to the local /sftp/files/, and then uploaded to the file server through jsch and channelsftp, and then the local temporary files are deleted.
Two file server users and one server user where the jar package is located.
The user jaruser of the server where the jar package is located needs /sftp permissions.
chown -R jaruser:jaruser /sftp
A file server user fileuser requires /sftp permissions. Used to create directories and upload files through jsch, channelsftp. This user can have more permissions and be more normal.
There is also a file server user that I want to provide to other systems, sftpuser. This user can only download files from the directory and subdirectories I provide, and cannot perform other operations, such as logging in, uploading, modifying files, etc.
Switch to root user
Create new user
useradd sftpuser passwd sftpuser # Disable sftpuser login. # This can be executed now or later. If you execute it at the end, you can log in to test whether the setfacl command works. Test cd, ls, etc. usermod -s /sbin/nologin sftpuser mkdir -p /sftp/files/ # This file can be created anywhere, it will not affect it, it is just for running a script. vim batchACL.sh
batchACL.sh
#!/bin/bash # Traverse all directories under the root directory, but exclude /sftp and / directories directories=($(find / -maxdepth 1 -type d ! -wholename "/sftp" ! -wholename "/" -exec echo {<!-- -->} \;)) # Set ACL entries for dir in "${directories[@]}"; do setfacl -m u:sftpuser:- "$dir" done
chmod 700 batchACL.sh ./batchACL.sh
I configured it both on my computer’s virtual machine and on the server. The only difference is that using jsch, you can connect from your own computer, but not from the server.
Java code reports error,
com.jcraft.jsch.JSchException: java.io.IOException: Pipe closed Caused by: java.io.IOException:Pipe closed
At this time, you need to configure /etc/ssh/sshd_config
vim /etc/ssh/sshd_config
Whether PasswordAuthentication is set or not has no effect.
Subsystem sftp internal-sftp Match User sftpuser
systemctl restart sshd # User who starts the jar package that generates files (I haven’t tested this, but it seems that you don’t need chown, and you can generate files in this directory without chown) chown -R jaruser:jaruser /sftp #Use jsch, channelsftp to create directories and upload files (this must be chown) chown -R fileuser:fileuser /sftp
Tracking pit:
1. There are many people on the Internet talking about setting /etc/ssh/sshd_config. I have tried countless times, but I can’t restrict login at all. I can also cd to other directories. The summary is that it doesn’t work! ! ! ! ! ! !
The Linux command setfacl must be simple and crude.
For the use of this command, please refer to: setfacl linux command online Chinese manual (51yip.com)
setfacl command – Set file ACL policy rules – Linux command list (manual) (linuxcool.com)
2. What a huge pit! ! ! ! ! ! !
If you hit a breakpoint in jsch or channel-related code, and the code reports an error java.util.InterruptedException, you can just cancel the breakpoints or not debug.
It should be related to the timeout setting. I can’t remember clearly. I seem to have set session.connect(10000); and channel.connect(10000); to a relatively large value so that I can debug without reporting errors. This is 10 seconds.
3. This is a big pitfall. It does not affect user permissions. I don’t quite understand what this file does, but changing this file will not help my needs.
vim /etc/sudoers
Some other problems encountered during the pitfall process.
1. If you do not want to prohibit the sftpuser user from logging in first, and see if the cd cannot reach other directories, the batchACL.sh script can change the value of directories.
#!/bin/bash # Traverse all directories under the root directory, but exclude /D and /directory /lib64. If not excluded, an error will be reported. # [root@localhost ~]# su sftpuser # su: failed to execute /bin/bash: Permission denied directories=($(find / -maxdepth 1 -type d ! -wholename "/sftp" ! -wholename "/" ! -wholename "/bin" ! -wholename "/lib64" ! - wholename "/home" -exec echo {<!-- -->} \;)) # Set ACL entries for dir in "${directories[@]}"; do setfacl -m u:sftpuser:- "$dir" done
2. Some commands involved in testing the setfacl command
# Set sftpuser pair/file acl rules setfacl -m u:sftpuser:- / # This -R must be at the front to clear the sftpuser user and the /file acl rule setfacl -R -x u:sftpuser / # Clear all acl setfacl -b sftpuser
3. This is a screenshot when testing with jsch and channelexec. This is very clear. It means that the service only allows sftp connections. Why? Because I configured ForceCommand internal-sftp.
4. Some codes for testing.
import com.jcraft.jsch.*; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; /** * <dependency> * <groupId>com.jcraft</groupId> * <artifactId>jsch</artifactId> * <version>0.1.55</version> * </dependency> * session.connect();, channel.connect(); It is best to set the timeout, otherwise the default is to wait indefinitely. * Just add a number session.connect(1000);, channel.connect(1000);, the specific size depends on the actual situation. */ public class SftpDemo {<!-- --> public static void main(String[] args) throws JSchException, SftpException, IOException {<!-- --> String host = "192.168.1.200"; int port = 22; String username = "sftpuser"; String password = "sftpuser"; JSch jsch = new JSch(); Session session = jsch.getSession(username, host, port); session.setPassword(password); // If this is not set, an error will be reported. The reason is not clear. If you are interested, you can study it. session.setConfig("StrictHostKeyChecking", "no"); session.connect(); //Open a channel Channel channel = session.openChannel("exec"); // According to; split, executed in sequence. String cmd = "cd /sftp;mkdir 3.json;"; ((ChannelExec) channel).setCommand(cmd); InputStream in = channel.getInputStream(); channel.connect(); //Read command output byte[] buffer = new byte[1024]; int bytesRead; StringBuilder result = new StringBuilder(); while ((bytesRead = in.read(buffer)) > 0) {<!-- --> result.append(new String(buffer, 0, bytesRead)); } // Close channel and session channel.disconnect(); session.disconnect(); //Print command output System.out.println("Command output:\\ " + result); /* ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp.connect(); String remoteFilePath = "/sftp/upload/1.txt"; // String remoteFilePath2 = "/opt/software/2.txt"; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); channelSftp.get(remoteFilePath, byteArrayOutputStream); // channelSftp.get(remoteFilePath2, byteArrayOutputStream); String fileContent = new String(byteArrayOutputStream.toByteArray(), StandardCharsets.UTF_8); System.out.println("File content:\\ " + fileContent); channelSftp.disconnect(); session.disconnect(); */ } }
5. Various commands.
# Monitor user creation, deletion, connection, etc. tailf /var/log/secure [root@localhost ~]# getent passwd sftpuser sftpuser:x:1004:1004::/home/sftpuser:/bin/bash [root@localhost ~]# grep sftpuser /etc/passwd sftpuser:x:1004:1004::/home/sftpuser:/bin/bash [root@localhost home]# passwd -u sftpuser Unlocking password for user sftpuser. passwd: Success
6. In Linux, when we use the mkdir -p /A/B/C/
command to create a directory, if the directory /A/B/C/
already exists, It will not have any bad impact on existing directories and files. This is because the mkdir
command ignores existing directories by default.