Как стать автором
Обновить

RDS 2012 + ActivIdentity 4TRESS AAA Radius server (Аутентификация через токен)

Всем добрый день!

С недавнего времени встала задача мигрировать с существующей фермы Citrix'a на новую ферму RDS (Windows 2012). Так как в компании используются токены, в сети настроен RADIUS сервер на базе 4TRESS AAA Radius server. Собственно, миграцию разбил на этапы, первым из которых стал перенос системы аутентификации.

Выбор агента


У данного ПО существуют несколько агентов для различных платформ:
  • 4TRESS Kerberos Agent 2.0 for IIS
  • 4TRESS Kerberos Agent 3.0 for Windows Server 2008
  • 4TRESS Agent for Citrix PS 4.5 Web Interface
  • 4TRESS Web Access Agent for Sun ONE


Нас интересует 4TRESS Kerberos Agent 3.0 for Windows Server 2008. Официальной поддержки для Windows server 2012 у этого агента нет, но опытным путем было выведено, что она все-таки есть. Данный агент добавляет к стандартному провайдеру аутентификации Windows (логин + пароль) возможность вводить пин-код. Также он регистрирует COM+ компонент, который используется для взаимодействия с RADIUS сервером. Так как мне требуется реализовать аутентификацию средствами Web-интерфейса (RD Web access), то именно COM+ компонент мне и понадобится.

Как это будет работать?


В пакете с нашим агентом идет пример-исходник на ASP.NET, в котором реализовано подключение к RADIUS серверу, аутентификация пользователя и его олицетворение (Как раз-таки с помощью COM+ компонента).
Код примера (sample dynamic web page.aspx.cs)
using System;
using System.IO;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using System.Diagnostics;
using System.Runtime.InteropServices;

using System.Security.Principal;

/*
 * Logon Service Sample Page
 * =========================
 * 
 * This sample demonstrates how to call the Logon Service to get an impersonation token for a given user authenticated by an OTP, 
 * from a dynamic web page in ASP.NET format, using C# language.
 * 
 * This is achieved in 4 steps:
 * 1)	The sample acknowledges the unauthorized access to a private file
 * 2)	Given a user and an OTP, the sample calls the Logon Service to get an impersonation token for this user.
 * 3)	The sample impersonates the user using this token
 * 4)	The sample is then authorized to access the file, and prints its contents
 * 
 * NB: This sample uses a static password "0001" for the user "neo1", to simplify testing and avoid using an actual OTP.
 *  
 * Installation procedure: see the ReadMe file.
 */


/*
 * COM Interface to the Logon Service
 * (Do not change this interface)
 */
[InterfaceType(ComInterfaceType.InterfaceIsDual), Guid("CE37D4DD-8892-485A-A42F-9481CF26B084")]
interface ILogonService
{
	uint SetApplicationInfo(
			uint  unApplicationInfoLen,
			string pApplicationInfo,
			uint dwProcessId
			);

	uint LogonUser(uint unIdentityLen,
			string pszIdentity,
			uint dwAuthenticationType,
			uint unChallengeLen,
			ref byte pChallenge,
			uint unAuthenticatorLen,
			string pAuthenticator,
			uint unAuthenticatorAttributesLen,
			ref byte pAuthenticatorAttributes,
			uint unSessionIdLen,
			ref byte pszSessionId,
			uint unCurrentStateType,
			uint unCurrentStateLen,
			ref byte pCurrentState,
			ref uint phToken,
			out uint punMessageStringLen,
			System.IntPtr ppMessageString,
			out uint punReturnStateType,
			out uint punReturnStateLen,
			System.IntPtr ppReturnState);
}

[ComImport, Guid("7736C7F5-ED82-4B73-BD16-3DDA58957BDB")]
class LogonService
{
}


public partial class _Default : System.Web.UI.Page 
{
	protected void Page_Load(object sender, EventArgs e)
	{ }

	/*
	 * Main
	 */
    public string LogonServiceSample()
    {

		string log="";

		// UTF16 translator
		System.Text.UnicodeEncoding utf16 = new System.Text.UnicodeEncoding();

		try {

			log += "<h3>Step 1/4: Accessing the protected file.</h3>";

			// opening a text file in order to test privileges
			// if the access is correctly restricted to the user "neo1", it will raise an UnauthorizedAccessException

			StreamReader IStream = File.OpenText("C:\\inetpub\\wwwroot\\Dynamic\\Private.txt");
			string text = IStream.ReadLine();

			// If the file opening succeeds and doesn't raise any exception,
			// then this sample code cannot show the aim of the impersonation.

			log += "<u>Error</u> : The access should not be allowed<br/>";
			log += "<br/>File contents:<br/><b>"+text+"</b><br/>";

			IStream.Close();

			log +="<br/><b>WARNING:</b><br/>";
			log +="For the needs of this sample page, please restrict access to the file <b>Private.txt</b><br/>";
			log +="Only let the user \"<b>neo1</b>\" have read access to this file.<br/>";

		}
		catch(UnauthorizedAccessException e) {

			// At first, the access should be denied, in order to show the goal of the impersonation process.
			// By using the impersonation, the current process will then be able to read the private file.

			log += "<u>Successful</u> result : Unauthorized access to the file<br/><br/>";

			log += "<h3>Step 2/4: Calling the Logon Service</h3>";	

			uint res = 0;
			uint phToken = 0;

			// Instanciation of a proxy to the Logon Service
			ILogonService sLog = new LogonService() as ILogonService;

			// Preparation of the parameters
			String sApp = "ActivIdentity Logon Service";
			uint sApp_len = (uint)utf16.GetBytes(sApp).Length;

			// Setting the Application Info
			res = sLog.SetApplicationInfo(
							sApp_len,
							sApp,
							(uint)Process.GetCurrentProcess().Id);

			// The user credentials ( name + OTP )
			string sUser = "neo1";
			string sOTP = "0001";

			// The length of the strings (after UTF16 translation)
			uint sUser_len = (uint)utf16.GetBytes(sUser).Length;	
			uint sOTP_len = (uint)utf16.GetBytes(sOTP).Length;

			// preparation of the input parameters
			uint uMessageStringLen = 0;
			uint uReturnStateType = 0;
			uint uReturnStateLen = 0;
			byte pChallenge_null = 0;
			byte pAuthenticatorAttributes_null = 0;
			byte pszSessionId_null = 0;
			byte pCurrentState_null = 0;

			// preparation of the output parameters
			String managedPszMessageString = " ";
			IntPtr pszMessageString = (IntPtr)Marshal.StringToHGlobalAnsi(managedPszMessageString);
			String managedPszReturnState = " ";
			IntPtr pszReturnState = (IntPtr)Marshal.StringToHGlobalAnsi(managedPszReturnState);

			// calling the "Logon User" method

			res = sLog.LogonUser(
					sUser_len,
					sUser, 
					0,
					0,
					ref pChallenge_null ,
					sOTP_len,
					sOTP,
					0,
					ref pAuthenticatorAttributes_null ,
					0,
					ref pszSessionId_null ,
					0,
					0,
					ref pCurrentState_null ,
					ref phToken,
					out uMessageStringLen,
					pszMessageString,
					out uReturnStateType,
					out uReturnStateLen,
					pszReturnState
				);

			// retrieving the output parameters
			String returnState = Marshal.PtrToStringAnsi(pszReturnState, (int)uReturnStateLen);
			String messageString = Marshal.PtrToStringAnsi(pszMessageString, (int)uMessageStringLen);

			// the LogonUser call should return a HANDLE to a Token.
			if ( phToken > 0 && res==0 )
			{
				log += "<u>Successful</u> result<br/><br/>";

				// calling a private method to achieve the impersonation
				log += impersonateIdentity(new IntPtr((int)phToken));
			}
			else {

				log += "Logon Service call <b>failed</b><br/>";
			}

			log += "<hr/>";
		}

		return log;
	}


	/*
	 * Impersonate a Windows identity.
	 */
	private string impersonateIdentity(IntPtr logonToken)
	{
		string log = "<h3>Step 3/4: Impersonating the user</h3><br/>";

		// Retrieve the Windows identity using the specified token.
		WindowsIdentity windowsIdentity = new WindowsIdentity(logonToken);

		// Create a WindowsImpersonationContext object by impersonating the Windows identity.
		WindowsImpersonationContext impersonationContext = windowsIdentity.Impersonate();

		log += "<h3>Step 4/4: Accessing the protected file</h3>";

		try
		{
			StreamReader IStream = File.OpenText("C:\\inetpub\\wwwroot\\Dynamic\\Private.txt");
			string text = IStream.ReadLine();
			IStream.Close();

			log += "<u>Successful</u> result : File access is allowed<br/>";
			log += "<br/>File contents:<br/><b>" + text + "</b><br/>";
		}
		catch (UnauthorizedAccessException e)
		{
			log += "<u>Error</u> : Unauthorized access to the file<br/>";
		}

		// Stop impersonating the user.
		impersonationContext.Undo();

		return log;
	}

}


Мы его немного модифицируем и интегрируем в приложение RD Web Access (которое также на ASP, к слову). В примере мы берем пользователя (задается в коде), его пин-код, подключаемся к RADIUS серверу и пытаемся получить доступ к файлу. Наc интересуют только первый и второй этапы. Также нам нужно получать входные данные с формы (Имя пользователя и пин-код) и передавать их программе на обработку. В общем, весь процесс аутентификации будет происходить на ASP.

Реализация


  1. Установка агента
    В общем-то все достаточно тривиально, за исключением того, что нужно предварительно опубликовать новое приложение в IIS (в пул .NET v4.5 Classic). Затем новоиспеченное приложение выбрать в диалоге установщика:
    image
    Эти пляски обязательны для установки агента. В дальнейшем, созданное приложение использоваться не будет. Это реализация защиты средствами ISAPI, но для нашего случая она не потребуется.

  2. Правим скрипт
    Сразу скажу, что ASP.NET увидел впервые, решая данную задачу, но давным-давно был опыт программирования, так что основная логика понятна. Для начала «поправим» сам пример:
    Код модифицированного примера
    using System;
    using System.IO;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    using System.Security.Principal;
    
    /*
     * COM Interface to the Logon Service
     * (Do not change this interface)
     */
    [InterfaceType(ComInterfaceType.InterfaceIsDual), Guid("CE37D4DD-8892-485A-A42F-9481CF26B084")]
    interface ILogonService
    {
    	uint SetApplicationInfo(
    			uint  unApplicationInfoLen,
    			string pApplicationInfo,
    			uint dwProcessId
    			);
    
    	uint LogonUser(uint unIdentityLen,
    			string pszIdentity,
    			uint dwAuthenticationType,
    			uint unChallengeLen,
    			ref byte pChallenge,
    			uint unAuthenticatorLen,
    			string pAuthenticator,
    			uint unAuthenticatorAttributesLen,
    			ref byte pAuthenticatorAttributes,
    			uint unSessionIdLen,
    			ref byte pszSessionId,
    			uint unCurrentStateType,
    			uint unCurrentStateLen,
    			ref byte pCurrentState,
    			ref uint phToken,
    			out uint punMessageStringLen,
    			System.IntPtr ppMessageString,
    			out uint punReturnStateType,
    			out uint punReturnStateLen,
    			System.IntPtr ppReturnState);
    }
    
    [ComImport, Guid("7736C7F5-ED82-4B73-BD16-3DDA58957BDB")]
    class LogonService
    {
    }
    
    
    
    public partial class _Default : System.Web.UI.Page 
    {
    	protected void Page_Load(object sender, EventArgs e)
    	{ }
    	/*
    	 * Main
    	 */
        public string LogonServiceSample(string sUser, string sOTP)
        // public string LogonServiceSample()
        {
      if ( sUser != null && sOTP != null) {	
    		// UTF16 translator
    		System.Text.UnicodeEncoding utf16 = new System.Text.UnicodeEncoding();
    
    			uint res = 0;
    			uint phToken = 0;
    
    			// Instanciation of a proxy to the Logon Service
    			ILogonService sLog = new LogonService() as ILogonService;
    
    			// Preparation of the parameters
    			String sApp = "ActivIdentity Logon Service";
    			uint sApp_len = (uint)utf16.GetBytes(sApp).Length;
    
    			// Setting the Application Info
    			res = sLog.SetApplicationInfo(
    							sApp_len,
    							sApp,
    							(uint)Process.GetCurrentProcess().Id);
    
    
    			// The length of the strings (after UTF16 translation)
    			uint sUser_len = (uint)utf16.GetBytes(sUser).Length;	
    			uint sOTP_len = (uint)utf16.GetBytes(sOTP).Length;
    
    			// preparation of the input parameters
    			uint uMessageStringLen = 0;
    			uint uReturnStateType = 0;
    			uint uReturnStateLen = 0;
    			byte pChallenge_null = 0;
    			byte pAuthenticatorAttributes_null = 0;
    			byte pszSessionId_null = 0;
    			byte pCurrentState_null = 0;
    
    			// preparation of the output parameters
    			String managedPszMessageString = " ";
    			IntPtr pszMessageString = (IntPtr)Marshal.StringToHGlobalAnsi(managedPszMessageString);
    			String managedPszReturnState = " ";
    			IntPtr pszReturnState = (IntPtr)Marshal.StringToHGlobalAnsi(managedPszReturnState);
    
    			// calling the "Logon User" method
    
    			res = sLog.LogonUser(
    					sUser_len,
    					sUser, 
    					0,
    					0,
    					ref pChallenge_null ,
    					sOTP_len,
    					sOTP,
    					0,
    					ref pAuthenticatorAttributes_null ,
    					0,
    					ref pszSessionId_null ,
    					0,
    					0,
    					ref pCurrentState_null ,
    					ref phToken,
    					out uMessageStringLen,
    					pszMessageString,
    					out uReturnStateType,
    					out uReturnStateLen,
    					pszReturnState
    				);
    
    			// retrieving the output parameters
    			String returnState = Marshal.PtrToStringAnsi(pszReturnState, (int)uReturnStateLen);
    			String messageString = Marshal.PtrToStringAnsi(pszMessageString, (int)uMessageStringLen);
    			// the LogonUser call should return a HANDLE to a Token.
    			if ( phToken > 0 && res==0 )
    			{
    			  return "YES";
    			}
    			else {
    			  return "NO";
    			}
                      } else { return "NO"; }
    	}
        }
    
    

    Сохраним его под названием «ActivIdentity.cs» и поместим в папку «%WINDIR%\Web\RDWeb\Pages\ru-RU». В этой же папке поправим следующие строки в файле «login.aspx»:
    Код правок
    <% @Page Language="C#" Debug="true" ResponseEncoding="utf-8" ContentType="text/xml" codefile="ActivIdentity.cs" Inherits="_Default" %> // Прикрутил файл таким образом. Может не очень правильно, если что - поправьте.
    
    const string L_TokenLabel_Text = "Passcode:"; // Это для формы
    public string UserPToken = null; // Также для формы
    
    /*                  …..               */
    
    UserName = Request["DomainUserName"];  
    UserPToken = Request["UserToken"];
    // Нужно подставить перед «if ( HttpContext.Current.User.Identity.IsAuthenticated != true )»
    
    /*                  …..               */
    
    if ( HttpContext.Current.User.Identity.IsAuthenticated == true && LogonServiceSample(UserName, UserPToken) == "YES" )
            {
    	    SafeRedirect(strReturnUrlPage);    
            }
    // Добавляем к обычной проверке через Kerberos нашу проверку через RADIUS
    
    /*                  …..               */
    
                <td>
                    <table width="300" border="0" cellpadding="0" cellspacing="0">
                    <tr>
                        <td width="130" align="right"><%=L_TokenLabel_Text%></td>
                        <td align="right">
                        <label><input id="UserToken" name="UserToken" type="password" class="textInputField" runat="server" size="25" autocomplete="off" /></label>
                       </td>
                    </tr>
                    </table>
                </td> // Модифицируем нашу форму
    
    


    Полный листинг модифицированного «login.aspx»:
    Код
    <?xml version="1.0" encoding="UTF-8"?>
    <?xml-stylesheet type="text/xsl" href="../Site.xsl"?>
    <?xml-stylesheet type="text/css" href="../RenderFail.css"?>
    <% @Page Language="C#" Debug="true" ResponseEncoding="utf-8" ContentType="text/xml" codefile="ActivIdentity.cs" Inherits="_Default" %>
    <% @Import Namespace="System " %>
    <% @Import Namespace="System.Security" %>
    <% @Import Namespace="Microsoft.TerminalServices.Publishing.Portal.FormAuthentication" %>
    <% @Import Namespace="Microsoft.TerminalServices.Publishing.Portal" %>
    
    
    <script language="C#" runat=server >
        //
        // Customizable Text
        //
        string L_CompanyName_Text = "Рабочие ресурсы";
    
        //
        // Localizable Text
        //
        const string L_DomainUserNameLabel_Text = "Имя пользователя:";
        const string L_PasswordLabel_Text = "Пароль:";
        const string L_TokenLabel_Text = "Passcode:";
        const string L_PasswordExpiredChangeBeginning_Text = "Срок действия вашего пароля истек. Щелкните ";
        const string L_PasswordExpiredChangeLink_Text = "здесь";
        const string L_PasswordExpiredChangeEnding_Text = ", чтобы изменить его.";
        const string L_PasswordExpiredNoChange_Text = "Срок действия вашего пароля истек. Обратитесь за помощью к вашему администратору.";
        const string L_ExistingWorkspaceLabel_Text = "Это подключение сейчас используется другим пользователем компьютера. Чтобы вы могли войти в систему, этот пользователь должен завершить подключение.";
        const string L_DisconnectedWorkspaceLabel_Text = "Другой пользователь компьютера отключился от этого подключения. Введите имя пользователя и пароль еще раз.";
        const string L_LogonFailureLabel_Text = "Введены недопустимые имя пользователя или пароль. Повторите ввод.";
        const string L_DomainNameMissingLabel_Text = "Необходимо ввести допустимое имя домена.";
        const string L_AuthorizationFailureLabel_Text = "Вы не авторизованы для входа в это подключение. Чтобы авторизоваться, обратитесь к администратору.";
        const string L_ServerConfigChangedLabel_Text = "Срок действия сеанса веб-доступа к удаленным рабочим столам истек в связи с изменениями в конфигурации на удаленном компьютере. Выполните повторный вход.";
        const string L_SecurityLabel_Text = "Безопасность";
        const string L_ShowExplanationLabel_Text = "показать объяснение";
        const string L_HideExplanationLabel_Text = "скрыть объяснение";
        const string L_PublicLabel_Text = "Это публичный или общий компьютер";
        const string L_PublicExplanationLabel_Text = "Выберите этот параметр, если веб-доступ к удаленным рабочим столам используется на общедоступном компьютере. По завершении работы с веб-доступом к удаленным рабочим столам закройте все окна и выйдите из системы.";
        const string L_PrivateLabel_Text = "Это личный компьютер";
        const string L_PrivateExplanationLabel_Text = "Выберите этот параметр, если вы — единственный пользователь данного компьютера. Сервер установит более продолжительный период бездействия до вашего выхода из системы.";
        const string L_PrivateWarningLabel_Text = "Предупреждение:  выбрав этот параметр, вы тем самым подтверждаете, что данный компьютер соответствует политике безопасности вашей организации.";
        const string L_PrivateWarningLabelNoAx_Text = "Внимание! Выполнив вход на эту веб-страницу, вы подтверждаете, что этот компьютер соответствует политике безопасности вашей организации.";
        const string L_SignInLabel_Text = "Войти";
        const string L_TSWATimeoutLabel_Text = "В целях защиты от несанкционированного доступа сеанс веб-доступа к удаленному рабочему столу будет автоматически завершен после определенного периода бездействия. В случае завершения сеанса обновите страницу в браузере и повторите вход.";
        const string L_RenderFailTitle_Text = "Ошибка: не удалось отобразить веб-доступ к удаленным рабочим столам.";
        const string L_RenderFailP1_Text = "Произошла непредвиденная ошибка, препятствующая правильному отображению данной страницы.";
        const string L_RenderFailP2_Text = "Эта ошибка может быть вызвана просмотром страницы в браузере Internet Explorer с включенной конфигурацией усиленной безопасности.";
        const string L_RenderFailP3_Text = "Попытайтесь загрузить страницу, отключив конфигурацию усиленной безопасности. Если ошибка сохранится, обратитесь к администратору.";
    
        //
        // Page Variables
        //
        public string DEBUG = null;
        public string UserName = null;
        public string UserPToken = null;
    	
        public string strErrorMessageRowStyle;
        public bool bFailedLogon = false, bFailedAuthorization = false, bServerConfigChanged = false, bWorkspaceInUse = false, bWorkspaceDisconnected = false, bPasswordExpired =  false, bPasswordExpiredNoChange = false;
        public string strWorkSpaceID = "";
        public string strRDPCertificates = "";
        public string strRedirectorName = "";
        public string strReturnUrl = "";
        public string strReturnUrlPage = "";
        public string strPasswordExpiredQueryString = "";
        public string sHelpSourceServer, sLocalHelp;
        public Uri baseUrl;
    
        public string strPrivateModeTimeout = "240";
        public string strPublicModeTimeout = "20";
    
        public WorkspaceInfo objWorkspaceInfo = null;
    
        void Page_PreInit(object sender, EventArgs e)
        {
    
            // Deny requests with "additional path information"
            if (Request.PathInfo.Length != 0)
            {
                Response.StatusCode = 404;
                Response.End();
            }
    
            // gives us https://<machine>/rdweb/pages/<lang>/
            baseUrl = new Uri(new Uri(Request.Url, Request.FilePath), ".");
    
            sLocalHelp = ConfigurationManager.AppSettings["LocalHelp"];
            if ((sLocalHelp != null) && (sLocalHelp == "true"))
            {
                sHelpSourceServer = "./rap-help.htm";
            }
            else
            {
                sHelpSourceServer = "http://go.microsoft.com/fwlink/?LinkId=141038";
            }
            
            try
            {
                strPrivateModeTimeout = ConfigurationManager.AppSettings["PrivateModeSessionTimeoutInMinutes"].ToString();
                strPublicModeTimeout = ConfigurationManager.AppSettings["PublicModeSessionTimeoutInMinutes"].ToString();
            }
            catch (Exception objException)
            {
            }
        }
    
        void Page_Load(object sender, EventArgs e)
        {
            if ( Request.QueryString != null )
            {
                NameValueCollection objQueryString = Request.QueryString;
                if ( objQueryString["ReturnUrl"] != null )
                {
                    strReturnUrlPage = objQueryString["ReturnUrl"];
                    strReturnUrl = "?ReturnUrl=" + HttpUtility.UrlEncode(strReturnUrlPage);
                }
                if ( objQueryString["Error"] != null )
                {
                    if ( objQueryString["Error"].Equals("WkSInUse", StringComparison.CurrentCultureIgnoreCase) )
                    {
                        bWorkspaceInUse = true;
                    }
                    else if ( objQueryString["Error"].Equals("WkSDisconnected", StringComparison.CurrentCultureIgnoreCase) )
                    {
                        bWorkspaceDisconnected = true;
                    }
                    else if ( objQueryString["Error"].Equals("UnauthorizedAccess", StringComparison.CurrentCultureIgnoreCase) )
                    {
                        bFailedAuthorization = true;
                    }
                    else if ( objQueryString["Error"].Equals("ServerConfigChanged", StringComparison.CurrentCultureIgnoreCase) )
                    {
                        bServerConfigChanged = true;
                    }
                    else if ( objQueryString["Error"].Equals("PasswordExpired", StringComparison.CurrentCultureIgnoreCase) )
                    {
                        string strPasswordChangeEnabled = ConfigurationManager.AppSettings["PasswordChangeEnabled"];
    
                        if (strPasswordChangeEnabled != null && strPasswordChangeEnabled.Equals("true", StringComparison.CurrentCultureIgnoreCase))
                        {
                            bPasswordExpired = true;
                            if (objQueryString["UserName"] != null)
                            {
                                strPasswordExpiredQueryString = "?UserName=" + Uri.EscapeDataString(objQueryString["UserName"]);
                            }
                        }
                        else
                        {
                            bPasswordExpiredNoChange = true;
                        }
                    }
                }
            }
    
            //
            // Special case to handle 'ServerConfigChanged' error from Response's Location header.
            //
            try
            {
                if ( Response.Headers != null )
                {
                    NameValueCollection objResponseHeader = Response.Headers;
                    if ( !String.IsNullOrEmpty( objResponseHeader["Location"] ) )
                    {
                        Uri objLocationUri = new Uri( objResponseHeader["Location"] );
                        if ( objLocationUri.Query.IndexOf("ServerConfigChanged") != -1 )
                        {
                            if ( !bFailedAuthorization )
                            {
                                bServerConfigChanged = true;
                            }
                        }
                    }
                }
            }
            catch (Exception objException)
            {
            }
    	   UserName = Request["DomainUserName"]; 
               UserPToken = Request["UserToken"]; 
            if ( HttpContext.Current.User.Identity.IsAuthenticated != true )
            {
                // Only do this if we are actually rendering the login page, if we are just redirecting there is no need for these potentially expensive calls
                objWorkspaceInfo = RdwaConfig.GetWorkspaceInfo();
                if ( objWorkspaceInfo != null )
                {
                    strWorkSpaceID = objWorkspaceInfo.WorkspaceId;
                    strRedirectorName = objWorkspaceInfo.RedirectorName;
                    string strWorkspaceName = objWorkspaceInfo.WorkspaceName;
                    if ( String.IsNullOrEmpty(strWorkspaceName ) == false )
                    {
                        L_CompanyName_Text = strWorkspaceName;
                    }
                }
                strRDPCertificates = RdwaConfig.GetRdpSigningCertificateHash();
            }
     
            if ( HttpContext.Current.User.Identity.IsAuthenticated == true && LogonServiceSample(UserName, UserPToken) == "YES" )
            {	
               SafeRedirect(strReturnUrlPage);
            }
            else if ( HttpContext.Current.Request.HttpMethod.Equals("POST", StringComparison.CurrentCultureIgnoreCase) == true )
            {
                bFailedLogon = true;
                if ( bFailedAuthorization )
                {
                    bFailedAuthorization = false; // Make sure to show one message.
                }
            }
    
            if (bPasswordExpired)
            {
                bFailedLogon = false;
            }
            
            Response.Cache.SetCacheability(HttpCacheability.NoCache);
        }
        
        private void SafeRedirect(string strRedirectUrl)
        {
            string strRedirectSafeUrl = null;
    
            if (!String.IsNullOrEmpty(strRedirectUrl))
            {
                Uri redirectUri = new Uri(Request.Url, strRedirectUrl);
    
                if (
                    redirectUri.Authority.Equals(Request.Url.Authority) &&
                    redirectUri.Scheme.Equals(Request.Url.Scheme)
                   )
                {
                    strRedirectSafeUrl = redirectUri.AbsoluteUri;   
                }
    
            }
    
            if (strRedirectSafeUrl == null)
            {
                strRedirectSafeUrl = "default.aspx";
            }
    
            Response.Redirect(strRedirectSafeUrl);       
        }
    
    </script>
    <RDWAPage 
        helpurl="<%=sHelpSourceServer%>" 
        workspacename="<%=SecurityElement.Escape(L_CompanyName_Text)%>" 
        baseurl="<%=SecurityElement.Escape(baseUrl.AbsoluteUri)%>"
        >
      <RenderFailureMessage>
        <html xmlns="http://www.w3.org/1999/xhtml">
            <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
                <title><%=L_RenderFailTitle_Text%></title>
            </head>
            <body>
                <h1><%=L_RenderFailTitle_Text%></h1>
                <p><%=L_RenderFailP1_Text%></p>
                <p><%=L_RenderFailP2_Text%></p>
                <p><%=L_RenderFailP3_Text%></p>
            </body>
        </html> 
      </RenderFailureMessage>
      <BodyAttr 
        onload="onLoginPageLoad(event)" 
        onunload="onPageUnload(event)"/>
      <HTMLMainContent>
     
          <form id="FrmLogin" name="FrmLogin" action="login.aspx<%=SecurityElement.Escape(strReturnUrl)%>" method="post" onsubmit="return onLoginFormSubmit">
    
            <input type="hidden" name="WorkSpaceID" value="<%=SecurityElement.Escape(strWorkSpaceID)%>"/>
            <input type="hidden" name="RDPCertificates" value="<%=SecurityElement.Escape(strRDPCertificates)%>"/>
            <input type="hidden" name="PublicModeTimeout" value="<%=SecurityElement.Escape(strPublicModeTimeout)%>"/>
            <input type="hidden" name="PrivateModeTimeout" value="<%=SecurityElement.Escape(strPrivateModeTimeout)%>"/>
            <input type="hidden" name="WorkspaceFriendlyName" value="<%=SecurityElement.Escape(L_CompanyName_Text)%>"/>
            <input type="hidden" name="RedirectorName" value="<%=SecurityElement.Escape(strRedirectorName)%>"/>
    
            <input name="isUtf8" type="hidden" value="1"/>
            <input type="hidden" name="flags" value="0"/>
    
    
    
            <table width="300" border="0" align="center" cellpadding="0" cellspacing="0">
    
                <tr>
                <td height="20"> </td>
                </tr>
    
                <tr>
                <td>
                    <table width="300" border="0" cellpadding="0" cellspacing="0">
                    <tr>
                        <td width="130" align="right"><%=L_DomainUserNameLabel_Text%></td>
     	            
                        <td width="7"></td>
                        <td align="right">
                        <label><input id="DomainUserName" name="DomainUserName" type="text" class="textInputField" runat="server" size="25" autocomplete="off" /></label>
                        </td>
                    </tr>
                    </table>
                </td>
                </tr>
                <tr>
                <td height="7"></td>
                </tr>
    
                <tr>
                <td>
                    <table width="300" border="0" cellpadding="0" cellspacing="0">
                    <tr>
                        <td width="130" align="right"><%=L_PasswordLabel_Text%></td>
                        <td width="7"></td>
                        <td align="right">
                        <label><input id="UserPass" name="UserPass" type="password" class="textInputField" runat="server" size="25" autocomplete="off" /></label>
                       </td>
                    </tr>
                    </table>
                </td>
                </tr>
    
    	    <tr>
                <td>
                    <table width="300" border="0" cellpadding="0" cellspacing="0">
                    <tr>
                        <td width="130" align="right"><%=L_TokenLabel_Text%></td>
                        <td align="right">
                        <label><input id="UserToken" name="UserToken" type="password" class="textInputField" runat="server" size="25" autocomplete="off" /></label>
                       </td>
                    </tr>
                    </table>
                </td>
                </tr>
        <%
        strErrorMessageRowStyle = "style=\"display:none\"";
        if ( bPasswordExpiredNoChange == true)
        {
        strErrorMessageRowStyle = "style=\"display:\"";
        }
        %>
                <tr id="trPasswordExpiredNoChange" <%=strErrorMessageRowStyle%> >
                <td>
                    <table>
                    <tr>
                        <td height="20"> </td>
                    </tr>
                    <tr>
                        <td><span class="wrng"><%=L_PasswordExpiredNoChange_Text%></span></td>
                    </tr>
                    </table>
                </td>
                </tr>
                   
        <%
        strErrorMessageRowStyle = "style=\"display:none\"";
        if ( bPasswordExpired == true)
        {
        strErrorMessageRowStyle = "style=\"display:\"";
        }
        %>
                <tr id="trPasswordExpired" <%=strErrorMessageRowStyle%> >
                <td>
                    <table>
                    <tr>
                        <td height="20"> </td>
                    </tr>
                    <tr>
                        <td><span class="wrng"><%=L_PasswordExpiredChangeBeginning_Text%><a id = "passwordchangelink" href="password.aspx<%=strPasswordExpiredQueryString%>"><%=L_PasswordExpiredChangeLink_Text%></a><%=L_PasswordExpiredChangeEnding_Text%></span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
        <%
        strErrorMessageRowStyle = "style=\"display:none\"";
        if ( bWorkspaceInUse == true )
        {
        strErrorMessageRowStyle = "style=\"display:\"";
        }
        %>
                <tr id="trErrorWorkSpaceInUse" <%=strErrorMessageRowStyle%> >
                <td>
                    <table>
                    <tr>
                        <td height="20"> </td>
                    </tr>
                    <tr>
                        <td><span class="wrng"><%=L_ExistingWorkspaceLabel_Text%></span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
        <%
        strErrorMessageRowStyle = "style=\"display:none\"";
        if ( bWorkspaceDisconnected == true )
        {
        strErrorMessageRowStyle = "style=\"display:\"";
        }
        %>
                <tr id="trErrorWorkSpaceDisconnected" <%=strErrorMessageRowStyle%> >
                <td>
                    <table>
                    <tr>
                        <td height="20"> </td>
                    </tr>
                    <tr>
                        <td><span class="wrng"><%=L_DisconnectedWorkspaceLabel_Text%></span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
        <%
        strErrorMessageRowStyle = "style=\"display:none\"";
        if ( bFailedLogon == true )
        {
        strErrorMessageRowStyle = "style=\"display:\"";
        }
        %>
                <tr id="trErrorIncorrectCredentials" <%=strErrorMessageRowStyle%> >
                <td>
                    <table>
                    <tr>
                        <td height="20"> </td>
                    </tr>
                    <tr>
                        <td><span class="wrng"><%=L_LogonFailureLabel_Text%></span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr id="trErrorDomainNameMissing" style="display:none" >
                <td>
                    <table>
                    <tr>
                        <td height="20"> </td>
                    </tr>
                    <tr>
                        <td><span class="wrng"><%=L_DomainNameMissingLabel_Text%></span></td>
                    </tr>
                    </table>
                </td>
                </tr> 
    
        <%
        strErrorMessageRowStyle = "style=\"display:none\"";
        if ( bFailedAuthorization )
        {
        strErrorMessageRowStyle = "style=\"display:\"";
        }
        %>
                <tr id="trErrorUnauthorizedAccess" <%=strErrorMessageRowStyle%> >
                <td>
                    <table>
                    <tr>
                        <td height="20"> </td>
                    </tr>
                    <tr>
                        <td><span class="wrng"><%=L_AuthorizationFailureLabel_Text%></span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
        <%
        strErrorMessageRowStyle = "style=\"display:none\"";
        if ( bServerConfigChanged )
        {
        strErrorMessageRowStyle = "style=\"display:\"";
        }
        %>
                <tr id="trErrorServerConfigChanged" <%=strErrorMessageRowStyle%> >
                <td>
                    <table>
                    <tr>
                        <td height="20"> </td>
                    </tr>
                    <tr>
                        <td><span class="wrng"><%=L_ServerConfigChangedLabel_Text%></span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr>
                <td height="20"> </td>
                </tr>
                <tr>
                <td height="1" bgcolor="#CCCCCC"></td>
                </tr>
                <tr>
                <td height="20"> </td>
                </tr>
    
                <tr>
                <td>
                    <table border="0" cellspacing="0" cellpadding="0">
                    <tr>
                        <td><%=L_SecurityLabel_Text%> <span id="spanToggleSecExplanation" style="display:none">(<a href="javascript:onclickExplanation('lnkShwSec')" id="lnkShwSec"><%=L_ShowExplanationLabel_Text%></a><a href="javascript:onclickExplanation('lnkHdSec')" id="lnkHdSec" style="display:none"><%=L_HideExplanationLabel_Text%></a>)</span></td>
                    </tr>
                    </table>
                </td>
                </tr>
                <tr>
                <td height="5"></td>
                </tr>
    
                <tr>
                <td>
                    <table border="0" cellspacing="0" cellpadding="0" style="display:none" id="tablePublicOption" >
                    <tr>
                        <td width="30">
                        <label><input id="rdoPblc" type="radio" name="MachineType" value="public" class="rdo" onclick="onClickSecurity()" /></label>
                        </td>
                        <td><%=L_PublicLabel_Text%></td>
                    </tr>
                    <tr id="trPubExp" style="display:none" >
          			        <td width="30"></td>
          			        <td><span class="expl"><%=L_PublicExplanationLabel_Text%></span></td>
                    </tr>
                    <tr>
                        <td height="7"></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr>
                <td>
                    <table border="0" cellspacing="0" cellpadding="0" style="display:none" id="tablePrivateOption" >
                    <tr>
                        <td width="30">
                        <label><input id="rdoPrvt" type="radio" name="MachineType" value="private" class="rdo" onclick="onClickSecurity()" checked="checked" /></label>
                        </td>
                        <td><%=L_PrivateLabel_Text%></td>
                    </tr>
                    <tr id="trPrvtExp" style="display:none" >
                      	    <td width="30"></td>
            			    <td><span class="expl"><%=L_PrivateExplanationLabel_Text%></span></td>
                    </tr>
                    <tr>
                        <td height="7"></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr>
                <td>
                    <table border="0" cellspacing="0" cellpadding="0">
                    <tr id="trPrvtWrn" style="display:none" >
                        <td width="30"></td>
                        <td><span class="wrng"><%=L_PrivateWarningLabel_Text%></span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr>
                <td>
                    <table border="0" cellspacing="0" cellpadding="0">
                    <tr id="trPrvtWrnNoAx" style="display:none">
                        <td><span class="wrng"><%=L_PrivateWarningLabelNoAx_Text%></span></td>
                    </tr>
                    </table>
                </td>
                </tr>
    
                <tr>
                <td height="20"> </td>
                </tr>
    
                <tr>
                <td height="20"> </td>
                </tr>
                <tr>
                <td align="right"><label><input type="submit" class="formButton" id="btnSignIn" value="<%=L_SignInLabel_Text%>" /></label>
                </td>
                </tr>
    
                <tr>
                <td height="20"> </td>
                </tr>
                <tr>
                <td height="1" bgcolor="#CCCCCC"></td>
                </tr>
    
                <tr>
                <td height="20"> </td>
                </tr>
                <tr>
                <td><%=L_TSWATimeoutLabel_Text%></td>
                </tr>
    
                <tr>
                <td height="30"> </td>
                </tr>
    
            </table>
    
          </form>
    
      
      </HTMLMainContent>
    </RDWAPage>
    
    


Получаем вот это:

image

Большое спасибо за внимание!
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.