Application of SMB in Java

Posted by The Wise One on Tue, 28 Jan 2020 05:42:22 +0100

Catalog

SMB Service Operation

Introduction to_SMB

SMB (full name Server Message Block) is a protocol name that can be used for Web connections and information communication between clients and servers.As a local area network file sharing transport protocol, SMB protocol is often used as a platform for the research of secure file transfer.
The Windows operating system includes both client and server SMB protocol support.Microsoft provides an open source version of SMB for the Internet, the Universal Internet File System CIFS.CIFS is more flexible than existing Internet applications such as File Transfer Protocol FTP.For UNIX systems, a shared software called Samba can be used.

II SMB Configuration

2.1 Windows SMB

2.1.1 Configuration Services

On the local machine, take Windows10 for example: In Control Panel --> Programs --> Programs and Functions --> Enable or Close Windows Functions --> SMB 1.0/cifs file sharing support Check SMB 1.0/CIFS Client and SMB 1.0/CIFS Server

2.1.2 Authentication Services

After opening, verify that SMB is properly opened: Use PowerShell command entry program in DOS command window to enter Get-SmbServerConfiguration | Select EnableSMB1Protocol, EnableSMB2Protocol to view service status, as shown:

2.1.3 Shared Files

Create a new test file on disk D:\Test\SmbTest\GoalTest, right-click menu-->Grant access-->Select a user for authorization for a specific user, as shown in the following figure:

When authorized to users, your folder will be prompted to be shared. Enter the Shared Connection \DESKTOP-D5DVINV\Test in the DOS window to enter the shared folder. Right-click on the shared folder to set the access password, change the access user, and so on.

III Add SMB Dependency

Add SMB service-related dependencies to pom.xml:

<!-- Quote SmbFile Class jar package  -->
<dependency>
       <groupId>jcifs</groupId>
       <artifactId>jcifs</artifactId>
       <version>1.3.17</version>
</dependency>

IV Path Format

There are three SMB path request formats in Java:

  • If you share without a password, the format is similar: smb://ip/sharefolder (for example: smb://192.168.0.77/test)
  • If a user name and password are required, the format is similar: smb://username:password@ip/sharefolder (example: smb://chb:123456@192.168.0.1/test)
  • If the username password and domain name are similar in format: smb: domain name; username: password@destination IP/folder/file name.xxx (example: smb://orcl;wangjp:Password123@192.168.193.13/Test)

V Operation Sharing

After the above steps, you have finished setting up an SMB file server on Windows and necessary preparations. The next step is a simple code step. The logic for uploading and downloading is also simple. The operation for SMB shared files is actually to process SmbFile objects.

import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileInputStream;
import jcifs.smb.SmbFileOutputStream;
import org.springframework.util.FileCopyUtils;
import java.io.*;
/**
 * @author: Create By WangJP
 * @description: SMB Service operation related
 * @date: 2020/1/1
 */
public class Demo {

    private static final String SMB_SHARE_FOLDER = "smb://username:password@192.168.1.103/Test/";
    private static final String SHARE_FOLDER_PATH = "SmbTest\\GoalTest";
    private static final String FILE_NAME = "test.txt";
    private static final String LOCAL_DIR = "D:\\LocalTest";

    public static void main(String[] args) {
        downloadSmbFile(SMB_SHARE_FOLDER, SHARE_FOLDER_PATH, FILE_NAME, LOCAL_DIR);
        uploadFile(SMB_SHARE_FOLDER, SHARE_FOLDER_PATH, FILE_NAME, LOCAL_DIR);
    }

    /**
     * Download files from SMB shared folder to local location
     * @param remoteUrl       SMB Request Path Url
     * @param shareFolderPath Full path to SMB target file storage in shared folder
     * @param fileName        file name
     * @param localDir        Local Folder
     */
    public static void downloadSmbFile(String remoteUrl, String shareFolderPath, String fileName, String localDir) {
        InputStream in = null;
        OutputStream out = null;
        try {
            SmbFile smbfile = new SmbFile(remoteUrl + shareFolderPath + File.separator + fileName);
            File localFile = new File(localDir + File.separator + fileName);
            in = new BufferedInputStream(new SmbFileInputStream(smbfile));
            out = new BufferedOutputStream(new FileOutputStream(localFile));
            FileCopyUtils.copy(in, out);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeStreanm(in, out);
        }
    }

    /**
     * Upload files from local folders to SMB shared folders (similar to downloading)
     * @param remoteUrl       SMB Request Path Url
     * @param shareFolderPath Full path to SMB target file storage in shared folder
     * @param fileName        file name
     * @param localDir        Local Folder
     */
    private static void uploadFile(String remoteUrl, String shareFolderPath, String fileName, String localDir) {
        InputStream in = null;
        OutputStream out = null;
        try {
            SmbFile smbfile = new SmbFile(remoteUrl + shareFolderPath + File.separator + fileName);
            File localFile = new File(localDir + File.separator + fileName);
            in = new BufferedInputStream(new FileInputStream(localFile));
            out = new BufferedOutputStream(new SmbFileOutputStream(smbfile));
            FileCopyUtils.copy(in, out);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeStreanm(in, out);
        }
    }

    private static void closeStreanm(InputStream in, OutputStream out) {
        try {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

A business requirement in my own work is to detect the existence of a file in the SMB shared directory. By downloading the uploaded example, I learned that getting SmbFile objects requires specific properties (url canon, etc.) to be built. There are many ways to handle them similar to File objects. The code examples are as follows:

 /**
     * Verify the existence of SMB shared files
     * @param remoteUrl       SMB Request Path Url
     * @param shareFolderPath Full path to SMB target file storage in shared folder
     * @param fileName        file name
     * @return true:Existence false: does not exist
     */
    public static boolean checkSmbFile(String remoteUrl, String shareFolderPath, String fileName) {
        boolean result = false;
        try {
            SmbFile smbfile = new SmbFile(remoteUrl + shareFolderPath + File.separator + fileName);
            result = smbfile.exists();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

VI Logon Verification

SMB login verification is mainly to solve the problem of special characters in account passwords (such as escape characters, specific characters in links). Account passwords with special characters often report the following exceptions:

Connected to the target VM, address: '127.0.0.1:54593', transport: 'socket'
jcifs.smb.SmbAuthException: Logon failure: unknown user name or bad password.

In order to build a valid SmbFile object, we need to validate the login before trying to build it:

private static String domainip = "192.168.170.13";
private static String username = "username";
private static String password = "password";
private static String remoteurl = "smb://192.168.170.13/share";
//Perform account IP address login verification
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(domainip, username, password);  
SmbFile smbfile = new SmbFile(remoteurl+"//"+folderpath,auth);

Topics: Java Windows network ftp