Der vorerst letzte Eintrag in der bliebten Reihe „wir sichern alles mögliche mit MultiOTP“ 😀

RDWeb landet nach der Installation in C:\Windows\Web\RDWeb. Die Datei die uns interessiert befindet sich im Unterverzeichnis Pages und da im Verzeichnis der gewünschten Sprache: login.aspx.

Oben bei den @Import Zeilen fügen wir ein

<% @Import Namespace="System.Diagnostics" %>
<% @Import Namespace="System.Text.RegularExpressions" %>
<% @Import Namespace="System.Configuration" %>

ein.

Bei den Strings (unter Kommentar // Localizable Text) folgendes:

const string L_OTPLabel_Text = "OTP:";

In der Methode LoginPageLoadAsync() direkt vor dem Ende des if ( Request.QueryString != null ) Blocks:

            }
            // EINFÜGEN
            if( Request.Form["UserOTP"] != null ) Session["UserOTP"] = (string)Request.Form["UserOTP"];
            // EINFÜGEN
        }

        //
        // Special case to handle 'ServerConfigChanged' error from Response's Location header.
        //

Weiter unten in der gleichen Methode im zweiten if ( HttpContext.Current.User.Identity.IsAuthenticated == true ) Block ersetzen wir SafeRedirect(strReturnUrlPage); durch:

string strOTPUsername = HttpContext.Current.User.Identity.Name;
if (strOTPUsername.Split('\\').Length > 1) strOTPUsername = strOTPUsername.Split('\\')[1];
if (strOTPUsername.Split('@').Length > 0) strOTPUsername = strOTPUsername.Split('@')[0];
			
bool bOTPAuthenticated = false;

if (Session["UserOTP"] != null)
{
  string strOTP = (string)Session["UserOTP"];
  if (!string.IsNullOrEmpty(strOTP) && Regex.Match(strOTP,ConfigurationManager.AppSettings["OTPRegex"]).Success && !string.IsNullOrEmpty(strOTPUsername) && Regex.Match(strOTPUsername,ConfigurationManager.AppSettings["OTPUsernameRegex"]).Success)
  {
    ProcessStartInfo oOTPStartInfo = new ProcessStartInfo();
    oOTPStartInfo.FileName = ConfigurationManager.AppSettings["MultiOTPPathAndName"];
    oOTPStartInfo.Arguments = strOTPUsername + " " + strOTP;
    oOTPStartInfo.CreateNoWindow = true;
    oOTPStartInfo.UseShellExecute = true;
    Process oOTP = Process.Start(oOTPStartInfo);
    oOTP.WaitForExit();
    bOTPAuthenticated = (oOTP.ExitCode == 0);
  }
}

if(bOTPAuthenticated)
{
  if (String.IsNullOrEmpty(strReturnUrlPage))
    Response.Redirect("default.aspx");
  else
    SafeRedirect(strReturnUrlPage);
}
else
{
  FormsAuthentication.SignOut(); 
  bFailedLogon = true;
  if (bFailedAuthorization) bFailedAuthorization = false; 
}

Zuletzt fügen wir noch die notwendigen Parameter in C:\Windows\Web\Web.Config im appSettings Block ein:

<add key="MultiOTPPathAndName" value="C:\\Pfad\\zu\\multiotp\\multiotp.exe" />
<add key="OTPUsernameRegex" value="^[0-9a-zA-Z]*$" />
<add key="OTPRegex" value="^[0-9]{6}$" />

Das war der Code, nun müssen wir noch das OTP Inputfeld einfügen – das passiert nach dem Passwort-Feld (einfach nach „UserPass“ suchen) nach dem abschließenden

folgendes einfügen:

<tr>
  <td>
    <table width="300" border="0" cellpadding="0" cellspacing="0">
      <tr>
        <td width="130" align="right"><%=L_OTPLabel_Text%></td>
        <td width="7"></td>
        <td align="right">
          <label><input id="UserOTP" name="UserOTP" type="password" class="textInputField" runat="server" size="23" autocomplete="off" /></label>
        </td>
      </tr>
    </table>
  </td>
</tr>

Ein auf den konfigurierten Pfad kopiertes MultiOTP samt passendem .INI vorausgesetzt (aufpassen: wenn Logging eingeschaltet ist muss RDWeb Application Pool Account Schreibrechte haben!) sollte das Ganze dann ungefähr so aussehen:

Wie üblich der Warnhinweis: Das alles ist natürlich weit jenseits jeglichen Supports und MS Support wird (zurecht) das Weite suchen wenn er/sie/es sowas sieht und ein Problem daraus entstanden ist….zusätzlich sollte man die geänderten Dateien auch sichern, obwohl die Seiten seit 2008R2 praktisch unverändert geblieben sind weiß man nie was der nächste CU so bringt 😀