Upload a file on SFTP server using SSH key or Username/Password in D365 using x++ (Part 2)

Harin PatelHarin Patel
4 min read

Hello, reader!
If you haven’t gone through Part 1 yet, I recommend checking it out first here (Part 1) for important context.

📌 What We’ll Cover in Part 2

In this part, we'll walk through how to upload a file to an SFTP server using SSH key authentication along with a username in Dynamics 365 Finance and Operations (D365FO) using X++ and C# integration.

🔧 Pre-requisites

Before we dive into the implementation, make sure you have the following set up:

  1. Install Renci.SshNet Library
    You'll need to install the Renci.SshNet library to interact with the SFTP server in Dynamics 365. You can follow the instructions from Part 1 to install this library.

  2. SSH Key Pair
    You’ll need an SSH key pair (private and public key) for authentication. This is a more secure way to connect to your SFTP server. Make sure you have the private key for your X++ code, and the public key should be added to the ~/.ssh/authorized_keys file on the SFTP server.

  3. Puttygen
    If you're using Windows, you'll need Puttygen to generate the SSH key pair. You can download it from Google or click-here.

    Why Use Puttygen?

    • Convert SSH Key for Code Usage: If you’ve used FileZilla or any other SFTP client with an SSH key, you'll need to convert that key into an RSA PRIVATE KEY format for it to be used in the code.

    • Skip This Step: If you already have your key in RSA PRIVATE KEY format, you can ignore this step

💻 Let’s Move to the Coding Part

Now that we’ve covered the prerequisites, let’s dive into the actual implementation. In this section, we’ll see how to upload a file to an SFTP server using SSH key authentication and a username, all within Dynamics 365 using X++ and C#.

  1. 🔑 Storing the SSH Key in Azure Blob Storage

    To make it easier to access the SSH key from within your code, I store the key in an Azure Blob Container. This allows me to easily read the key as a file stream directly from Azure when needed.

  2. 🗂️ Storing Credentials in the "SFTPCredentials" Custom Table

    To manage the SFTP connection details more efficiently, I store the username and host name in a custom table named "SFTPCredentials" within Dynamics 365. This allows me to easily retrieve these credentials when uploading the file to the SFTP server.

internal final class UploadFileToSFTP
{
    public static void uploadFileACH(StreamIo file, Filename filename, SFTPCredentials sftpCredentials)
    {
        System.IO.Stream input = file.getStream();

        // Azure Storage account details
        str storageAccountName = sftpCredentials.StorageAccountName;
        str storageAccountKey = sftpCredentials.StorageAccountKey;
        str containerName = sftpCredentials.ContainerName;
        str blobFileName = sftpCredentials.BlobFileName;

        try
        {
            // Create storage account and blob client
            var storageCredentials = new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(storageAccountName, storageAccountKey);

            CloudStorageAccount storageAccount = new Microsoft.WindowsAzure.Storage.CloudStorageAccount(storageCredentials, true);
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer cloudBlobContainer = blobClient.GetContainerReference(containerName);
            CloudBlockBlob blockBlob = cloudBlobContainer.GetBlockBlobReference(blobFileName);

            // Read the SSH key from the blob
            System.IO.Stream memory = blockBlob.OpenRead(null, null, null);

            // Create the SSH private key file for authentication
            Renci.SshNet.PrivateKeyFile keyFiles = new Renci.SshNet.PrivateKeyFile(memory, sftpCredentials.Password);

            input.Position = 0;

            // Initialize SFTP client
            Renci.SshNet.SftpClient sftp = new Renci.SshNet.SftpClient(
                sftpCredentials.ServerHost,
                sftpCredentials.SFTPPort,
                sftpCredentials.UserId,
                keyFiles
            );

            sftp.Connect();

            if (sftp.IsConnected)
            {
                // Change to the target directory on the SFTP server
                sftp.ChangeDirectory(@"/" + sftpCredentials.FilePath);

                // Set buffer size and upload the file
                sftp.BufferSize = 8 * 1024;
                sftp.UploadFile(input, filename, true, null);
            }
            else
            {
                Error('SFTP server connection failed.');
            }
        }
        catch (Exception::CLRError)
        {
            System.Exception ex = CLRInterop::getLastException();
            Error(ex.InnerException.Message);
        }
    }
}

Explanation

This code uploads a file to an SFTP server using SSH key authentication.

  1. Retrieve SSH Key from Azure Blob:
    It first retrieves the SSH private key stored in Azure Blob Storage using the details from the SFTPCredentials table.

  2. Create SFTP Client:
    It uses the Renci.SshNet.SftpClient to establish a connection to the SFTP server using the credentials (host, username, SSH key) from the SFTPCredentials table.

  3. Upload File:
    Once connected to the SFTP server, the method navigates to the target directory and uploads the file using the UploadFile method. It also sets a buffer size for the file upload.

  4. Error Handling:
    If any errors occur during the process, they are caught and displayed with a relevant error message.

0
Subscribe to my newsletter

Read articles from Harin Patel directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Harin Patel
Harin Patel

Dynamic D365 AX Developer