# Generating TOTPs for CyberArk (now Idira) Privileged Session Manager Webapp Connectors using a PreConnect DLL

With version 13.0 of CyberArk (now Idira)'s Privileged Session Manager, as part of a Webapp PSM connector, you can inject a time-based one-time password. You can even [store the secret for the TOTP in a separate account and link it as a logon account to secure it](https://timschindler.blog/generating-time-based-one-time-passwords-in-privileged-session-manager-webapp-connectors).

As the latest [LTS version is 12.6](https://docs.cyberark.com/EOL/en/Content/EOL-Self-hosted-products.htm#CyberArkPAMSelfHostedVaultPVWACPMPSMPSMforSSHPTA), many customers are 'stuck' without TOTP injection support but by using a custom [PreConnect DLL](https://docs.cyberark.com/PAS/12.2/en/Content/PASIMP/psm_WebApplication_Preconnect.htm?tocpath=Developer%7CCreate%20extensions%7CPSM%20Connectors%7CWeb%20applications%20for%20PSM%7C_____1) for Webapp PSM connectors -- a feature introduced in PSM version 12.2-- we can achieve the same functionality and have TOTP injection with PSMs as early as version 12.2

# What is a PreConnect DLL?

A PreConnect DLL is a piece of code that is run before a Webapp PSM connector's `WebFormFields` is executed. [Account properties can be passed to the DLL as parameters and return values can be used in the connector's `WebFormFields`' input fields.](https://docs.cyberark.com/PAS/12.2/en/Content/PASIMP/psm_WebApplication_Preconnect.htm?tocpath=Developer%7CCreate%20extensions%7CPSM%20Connectors%7CWeb%20applications%20for%20PSM%7C_____1#Configurethewebapplication) CyberArk provides [straightforward documentation](https://docs.cyberark.com/PAS/12.2/en/Content/PASIMP/psm_WebApplication_Preconnect.htm?tocpath=Developer%7CCreate%20extensions%7CPSM%20Connectors%7CWeb%20applications%20for%20PSM%7C_____1#ImplementthePreConnectDLLfile) on how to develop and configure a PreConnect DLL.

# Creating the PreConnect DLL

We will keep the PreConnect DLL simple.

It will take a single parameter -- `logonaccount_password` -- being the TOTP secret, generate a six-digit TOTP using it, and return the TOTP. We will use `&MfaCode&` to represent the TOTP for use in the `WebFormFields`.

As version 12.2 of the PSM comes with [Otp.NET](https://github.com/kspearrin/Otp.NET) out of the box in the `Components` folder, we will re-use the library to do the OTP generating and leave our PreConnect DLL to handle just the receiving of the parameter and the returning of the TOTP. With this, we have only a single file we need to distribute to each PSM.

```csharp
using CyberArk.PSM.WebAppDispatcher.PreconnectUtils;
using OtpNet;
using System;
using System.Collections.Generic;
using System.Net;
using System.Security;
using System.Text;

namespace CyberArk.PSM.GenerateTOTPPreconnect
{   
    
    public class GenerateTOTP : IPreconnectContract
    {
        private readonly string TOTP_OUTPUT_PARAMETER = "MFACode";

        public Dictionary<string, SecureString> GetParameters(Dictionary<string, SecureString> parameters, LogUtils.WriteToLogHandler writeToLogMethod)
        {
            string totpCode;

            try
            {
                byte[] totpSecretBytes = Encoding.UTF8.GetBytes(new NetworkCredential(string.Empty, parameters["logonaccount_password"]).Password);

                writeToLogMethod("Generating TOTP.", Consts.LOG_LEVEL_INFO);
                
                var totp = new Totp(totpSecretBytes);
                totpCode = totp.ComputeTotp();
            }
            catch (KeyNotFoundException ex)
            {
                writeToLogMethod(string.Format("Key not found in parameters dictionary: {0}", ex.ToString()), Consts.LOG_LEVEL_ERROR);
                throw new PreconnectException("Key not found in parameters dictionary");
            }
            catch (Exception ex)
            {
                writeToLogMethod(string.Format("Error while generating TOTP: {0}", ex.ToString()), Consts.LOG_LEVEL_ERROR);
                throw new PreconnectException("Error while generating TOTP");
            }

            writeToLogMethod("Successfully generated TOTP.", Consts.LOG_LEVEL_INFO);

            return new Dictionary<string, SecureString> {
                {
                    TOTP_OUTPUT_PARAMETER,
                    new NetworkCredential(string.Empty, totpCode).SecurePassword
                }
            };
        }
    }
}
```

<center><i>Note: I am not a C# developer so there is room for improvement!</i></center>

After compiling the DLL and moving it to the `Components` folder of our PSM, we are ready to leverage it with the Webapp PSM connector.

You can find the code and Visual Studio project, including [a compiled DLL](https://github.com/aaearon/CyberArk.PSM.GenerateTOTPPreconnect/releases/), in my GitHub repository below:

[https://github.com/aaearon/CyberArk.PSM.GenerateTOTPPreconnect](https://github.com/aaearon/CyberArk.PSM.GenerateTOTPPreconnect)

# Configuring the Webapp PSM Connector

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">This was tested in a PAM self-hosted environment with Vault version 13.0 and PSM 12.2. The 12.2 PSM is the <strong>second PSM</strong> installed, after one running version 13.0.</div>
</div>

With the compiled DLL copied to all PSMs,

1.  Ensure that the Webapp PSM connector has `LogonAccount` added under Component Parameters > Target Settings > Supported Capabilities.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1697112511393/ecdea847-3a62-459d-8758-27d026757569.png align="center")
    
2.  Add the required parameters `PreConnectDllName` and `PreConnectParameters` as described in [step three](https://docs.cyberark.com/PAS/12.2/en/Content/PASIMP/psm_WebApplication_Preconnect.htm?tocpath=Developer%7CCreate%20extensions%7CPSM%20Connectors%7CWeb%20applications%20for%20PSM%7C_____1#Configurethewebapplication). For `PreConnectDllName`, specify the name of the DLL (`CyberArk.PSM.GenerateTOTPPreconnect.dll` if downloaded from my GitHub repository) and for `PreConnectParameters` provide just `logonaccount_password`.
    
    ![a screenshot of the PreConnectDllName parameter](https://cdn.hashnode.com/res/hashnode/image/upload/v1697112557290/cf71ddcf-f383-4f28-b323-e748abe5614e.png align="center")
    
    ![a screenshot of the PreConnectParameters parameter](https://cdn.hashnode.com/res/hashnode/image/upload/v1697112580674/f51f78b5-26d2-4841-9dc7-47473d84a600.png align="center")
    
3.  In `WebFormFields`, use `&MfaCode&` to inject the TOTP in the desired input field.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1697112762884/229028a2-6838-4883-88f6-5c77be306695.png align="center")
    

Connecting with our Webapp PSM connector, the TOTP is generated based on a secret that is stored as the password for the account's linked logon account.

![a screenshot showing the generated TOTP being injected](https://cdn.hashnode.com/res/hashnode/image/upload/v1697112416490/ea46cec0-f74c-4159-abd7-deb0f3d124d9.png align="center")

The code and a compiled DLL can be found at [https://github.com/aaearon/CyberArk.PSM.GenerateTOTPPreconnect](https://github.com/aaearon/CyberArk.PSM.GenerateTOTPPreconnect).
