/* Myrtille: A native HTML4/5 Remote Desktop Protocol client. Copyright(c) 2014-2021 Cedric Coste Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Web; using System.Web.Configuration; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using Myrtille.Helpers; using Myrtille.Services.Contracts; using Myrtille.Web.Properties; namespace Myrtille.Web { public partial class Default : Page { private MFAAuthenticationClient _mfaAuthClient = new MFAAuthenticationClient(); private EnterpriseClient _enterpriseClient = new EnterpriseClient(); private ConnectionClient _connectionClient = new ConnectionClient(Settings.Default.ConnectionServiceUrl); private bool _allowRemoteClipboard; private bool _allowFileTransfer; private bool _allowPrintDownload; private bool _allowSessionSharing; private bool _allowAudioPlayback; private bool _allowShareSessionUrl; private bool _clientIPTracking; private bool _toolbarEnabled; private bool _loginEnabled; private string _loginUrl; private bool _httpSessionUseUri; private bool _authorizedRequest = true; private bool _localAdmin; private EnterpriseSession _enterpriseSession; protected RemoteSession RemoteSession; /// /// page init /// /// /// protected void Page_Init( object sender, EventArgs e) { // remote clipboard if (!bool.TryParse(ConfigurationManager.AppSettings["AllowRemoteClipboard"], out _allowRemoteClipboard)) { _allowRemoteClipboard = true; } // file transfer if (!bool.TryParse(ConfigurationManager.AppSettings["AllowFileTransfer"], out _allowFileTransfer)) { _allowFileTransfer = true; } // print download if (!bool.TryParse(ConfigurationManager.AppSettings["AllowPrintDownload"], out _allowPrintDownload)) { _allowPrintDownload = true; } // session sharing if (!bool.TryParse(ConfigurationManager.AppSettings["AllowSessionSharing"], out _allowSessionSharing)) { _allowSessionSharing = true; } // audio playback if (!bool.TryParse(ConfigurationManager.AppSettings["AllowAudioPlayback"], out _allowAudioPlayback)) { _allowAudioPlayback = true; } // share session by url (session spoofing protection if disabled) if (!bool.TryParse(ConfigurationManager.AppSettings["AllowShareSessionUrl"], out _allowShareSessionUrl)) { _allowShareSessionUrl = true; } // client ip tracking if (!bool.TryParse(ConfigurationManager.AppSettings["ClientIPTracking"], out _clientIPTracking)) { _clientIPTracking = false; } // toolbar control if (!bool.TryParse(ConfigurationManager.AppSettings["ToolbarEnabled"], out _toolbarEnabled)) { _toolbarEnabled = true; } // connect from a login page or url if (!bool.TryParse(ConfigurationManager.AppSettings["LoginEnabled"], out _loginEnabled)) { _loginEnabled = true; } // if enabled, url of the login page if (_loginEnabled) { _loginUrl = ConfigurationManager.AppSettings["LoginUrl"]; } // cookieless session var sessionStateSection = (SessionStateSection)ConfigurationManager.GetSection("system.web/sessionState"); _httpSessionUseUri = sessionStateSection.Cookieless == HttpCookieMode.UseUri; } /// /// page load (postback data is now available) /// /// /// protected void Page_Load( object sender, EventArgs e) { // client ip protection if (_clientIPTracking) { var clientIP = ClientIPHelper.ClientIPFromRequest(new HttpContextWrapper(HttpContext.Current).Request, true, new string[] { }); if (Session[HttpSessionStateVariables.ClientIP.ToString()] == null) { Session[HttpSessionStateVariables.ClientIP.ToString()] = clientIP; } else if (!((string)Session[HttpSessionStateVariables.ClientIP.ToString()]).Equals(clientIP)) { System.Diagnostics.Trace.TraceWarning("Failed to validate the client ip"); _authorizedRequest = false; UpdateControls(); return; } } // session spoofing protection if (_httpSessionUseUri) { if (Request.Cookies[HttpRequestCookies.ClientKey.ToString()] == null) { if (Session[HttpSessionStateVariables.ClientKey.ToString()] == null || _allowShareSessionUrl) { var cookie = new HttpCookie(HttpRequestCookies.ClientKey.ToString()); cookie.Value = Guid.NewGuid().ToString(); cookie.Path = "/"; Response.Cookies.Add(cookie); } else { System.Diagnostics.Trace.TraceWarning("Failed to validate the client key: missing key"); _authorizedRequest = false; UpdateControls(); return; } } else { var clientKey = Request.Cookies[HttpRequestCookies.ClientKey.ToString()].Value; if (Session[HttpSessionStateVariables.ClientKey.ToString()] == null) { Session[HttpSessionStateVariables.ClientKey.ToString()] = clientKey; } else if (!((string)Session[HttpSessionStateVariables.ClientKey.ToString()]).Equals(clientKey) && !_allowShareSessionUrl) { System.Diagnostics.Trace.TraceWarning("Failed to validate the client key: key mismatch"); _authorizedRequest = false; UpdateControls(); return; } } } // retrieve the active enterprise session, if any if (Session[HttpSessionStateVariables.EnterpriseSession.ToString()] != null) { try { _enterpriseSession = (EnterpriseSession)Session[HttpSessionStateVariables.EnterpriseSession.ToString()]; } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to retrieve the active enterprise session ({0})", exc); } } // retrieve the active remote session, if any if (Session[HttpSessionStateVariables.RemoteSession.ToString()] != null) { try { RemoteSession = (RemoteSession)Session[HttpSessionStateVariables.RemoteSession.ToString()]; // if using a connection service, send the connection state if (Session.SessionID.Equals(RemoteSession.OwnerSessionID) && RemoteSession.ConnectionService) { _connectionClient.SetConnectionState(RemoteSession.Id, string.IsNullOrEmpty(RemoteSession.VMAddress) ? RemoteSession.ServerAddress : RemoteSession.VMAddress, GuidHelper.ConvertFromString(RemoteSession.VMGuid), RemoteSession.State); } if (RemoteSession.State == RemoteSessionState.Disconnected) { // if connecting from a login page or url, show any connection failure into a dialog box // otherwise, this is delegated to the connection API used and its related UI if (_loginEnabled) { // handle connection failure var script = string.Format("handleRemoteSessionExit({0});", RemoteSession.ExitCode); // redirect to login page if (!string.IsNullOrEmpty(_loginUrl)) { script += string.Format("window.location.href = '{0}';", _loginUrl); } ClientScript.RegisterClientScriptBlock(GetType(), Guid.NewGuid().ToString(), script, true); } // cleanup Session[HttpSessionStateVariables.RemoteSession.ToString()] = null; if (Session[HttpSessionStateVariables.GuestInfo.ToString()] != null) { Session[HttpSessionStateVariables.GuestInfo.ToString()] = null; } RemoteSession = null; } } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to retrieve the active remote session ({0})", exc); } } // retrieve a shared remote session from url, if any else if (!string.IsNullOrEmpty(Request["gid"])) { var guestId = Guid.Empty; if (Guid.TryParse(Request["gid"], out guestId)) { var sharingInfo = GetSharingInfo(guestId); if (sharingInfo != null) { Session[HttpSessionStateVariables.RemoteSession.ToString()] = sharingInfo.RemoteSession; Session[HttpSessionStateVariables.GuestInfo.ToString()] = sharingInfo.GuestInfo; try { // remove the shared session guid from url Response.Redirect("~/", true); } catch (ThreadAbortException) { // occurs because the response is ended after redirect } } } } if (_httpSessionUseUri) { // if running myrtille into an iframe, the iframe url is registered (into a cookie) after the remote session is connected // this is necessary to prevent a new http session from being generated for the iframe if the page is reloaded, due to the missing http session id into the iframe url (!) // multiple iframes (on the same page), like multiple connections/tabs, requires cookieless="UseUri" for sessionState into web.config // problem is, there can be many cases where the cookie is not removed after the remote session is disconnected (network issue, server down, etc?) // if the page is reloaded, the iframe will use it's previously registered http session... which may not exist anymore or have its active remote session disconnected // if that happens, unregister the iframe url (from the cookie) and reload the page; that will provide a new connection identifier to the iframe and reconnect it if (!string.IsNullOrEmpty(Request["fid"]) && RemoteSession == null) { if (Request.Cookies[Request["fid"]] != null) { // remove the cookie for the given iframe Response.Cookies[Request["fid"]].Expires = DateTime.Now.AddDays(-1); // reload the page ClientScript.RegisterClientScriptBlock(GetType(), Guid.NewGuid().ToString(), "parent.location.href = parent.location.href;", true); } } } // local admin if (_enterpriseSession == null && RemoteSession == null && _enterpriseClient.GetMode() == EnterpriseMode.Local && !string.IsNullOrEmpty(Request["mode"]) && Request["mode"].Equals("admin")) { _localAdmin = true; } // postback events may redirect after execution; UI is updated from there if (!IsPostBack) { UpdateControls(); } // disable the browser cache; in addition to a "noCache" dummy param, with current time, on long-polling and xhr requests Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetNoStore(); } /// /// force remove the .net viewstate hidden fields from page (large bunch of unwanted data in url) /// /// protected override void Render( HtmlTextWriter writer) { var sb = new StringBuilder(); var sw = new StringWriter(sb); var tw = new HtmlTextWriter(sw); base.Render(tw); var html = sb.ToString(); html = Regex.Replace(html, "]*id=\"(__VIEWSTATE)\"[^>]*>", string.Empty, RegexOptions.IgnoreCase); html = Regex.Replace(html, "]*id=\"(__VIEWSTATEGENERATOR)\"[^>]*>", string.Empty, RegexOptions.IgnoreCase); writer.Write(html); } /// /// update the UI /// private void UpdateControls() { // remote session toolbar if (RemoteSession != null && (RemoteSession.State == RemoteSessionState.Connecting || RemoteSession.State == RemoteSessionState.Connected)) { if (_toolbarEnabled) { // interacting with the remote session is available to guests with control access, but only the remote session owner should have control on the remote session itself var controlEnabled = Session.SessionID.Equals(RemoteSession.OwnerSessionID) || (Session[HttpSessionStateVariables.GuestInfo.ToString()] != null && ((GuestInfo)Session[HttpSessionStateVariables.GuestInfo.ToString()]).Control); toolbar.Visible = true; toolbarToggle.Visible = true; serverInfo.Value = !string.IsNullOrEmpty(RemoteSession.VMGuid) ? RemoteSession.VMGuid : (!string.IsNullOrEmpty(RemoteSession.HostName) ? RemoteSession.HostName : RemoteSession.ServerAddress); userInfo.Value = !string.IsNullOrEmpty(RemoteSession.VMGuid) || RemoteSession.SecurityProtocol == SecurityProtocol.rdp ? string.Empty : (string.IsNullOrEmpty(RemoteSession.UserDomain) ? RemoteSession.UserName : string.Format("{0}\\{1}", RemoteSession.UserDomain, RemoteSession.UserName)); userInfo.Visible = !string.IsNullOrEmpty(userInfo.Value); scale.Value = RemoteSession.BrowserResize == BrowserResize.Scale ? "Scale ON" : "Scale OFF"; scale.Disabled = !Session.SessionID.Equals(RemoteSession.OwnerSessionID) || RemoteSession.HostType == HostType.SSH; reconnect.Value = RemoteSession.BrowserResize == BrowserResize.Reconnect ? "Reconnect ON" : "Reconnect OFF"; reconnect.Disabled = !Session.SessionID.Equals(RemoteSession.OwnerSessionID) || RemoteSession.HostType == HostType.SSH; keyboard.Disabled = !controlEnabled || (!string.IsNullOrEmpty(RemoteSession.VMGuid) && !RemoteSession.VMEnhancedMode); osk.Disabled = !controlEnabled || RemoteSession.HostType == HostType.SSH; clipboard.Disabled = !controlEnabled || RemoteSession.HostType == HostType.SSH || !RemoteSession.AllowRemoteClipboard || (!string.IsNullOrEmpty(RemoteSession.VMGuid) && !RemoteSession.VMEnhancedMode); files.Disabled = !Session.SessionID.Equals(RemoteSession.OwnerSessionID) || RemoteSession.HostType == HostType.SSH || !RemoteSession.AllowFileTransfer || (RemoteSession.ServerAddress.ToLower() != "localhost" && RemoteSession.ServerAddress != "127.0.0.1" && RemoteSession.ServerAddress != "[::1]" && RemoteSession.ServerAddress != Request.Url.Host && string.IsNullOrEmpty(RemoteSession.UserDomain)) || !string.IsNullOrEmpty(RemoteSession.VMGuid); cad.Disabled = !controlEnabled || RemoteSession.HostType == HostType.SSH; mrc.Disabled = !controlEnabled || RemoteSession.HostType == HostType.SSH; vswipe.Disabled = !controlEnabled || RemoteSession.HostType == HostType.SSH; share.Disabled = !Session.SessionID.Equals(RemoteSession.OwnerSessionID) || !RemoteSession.AllowSessionSharing; disconnect.Disabled = !Session.SessionID.Equals(RemoteSession.OwnerSessionID); imageQuality.Disabled = !Session.SessionID.Equals(RemoteSession.OwnerSessionID) || RemoteSession.HostType == HostType.SSH; } } // hosts list else if (_enterpriseSession != null && _enterpriseSession.AuthenticationErrorCode == EnterpriseAuthenticationErrorCode.NONE) { hosts.Visible = true; enterpriseUserInfo.Value = string.IsNullOrEmpty(_enterpriseSession.Domain) ? _enterpriseSession.UserName : string.Format("{0}\\{1}", _enterpriseSession.Domain, _enterpriseSession.UserName); enterpriseUserInfo.Visible = !string.IsNullOrEmpty(enterpriseUserInfo.Value); newRDPHost.Visible = _enterpriseSession.IsAdmin; newSSHHost.Visible = _enterpriseSession.IsAdmin; hostsList.DataSource = _enterpriseClient.GetSessionHosts(_enterpriseSession.SessionID); hostsList.DataBind(); } // login screen else { // connection params are sent when the login form is submitted, either through http post (the default form method) or http get (querystring) login.Visible = _loginEnabled; // MFA if (_mfaAuthClient.GetState()) { mfaDiv.Visible = true; mfaProvider.InnerText = _mfaAuthClient.GetPromptLabel(); mfaProvider.HRef = _mfaAuthClient.GetProviderURL(); } // enterprise mode if (_enterpriseClient.GetMode() == EnterpriseMode.Domain || _localAdmin) { hostConnectDiv.Visible = false; adminDiv.Visible = _localAdmin; if (adminDiv.Visible) { adminText.InnerText = "Home"; adminUrl.HRef = "~/"; } } // standard mode else { connect.Attributes["onclick"] = "initDisplay();"; adminDiv.Visible = _enterpriseClient.GetMode() == EnterpriseMode.Local; } } } /// /// enterprise mode from url: load the enterprise session (from querystring param) and proceed to connection; the user is non admin and the url is only usable once /// enterprise mode from login: authenticate the user against the enterprise active directory and list the servers available to the user; the user is admin if member of the "EnterpriseAdminGroup" defined into myrtille services config /// standard mode: connect the specified server; authentication is delegated to the remote server or connection broker (if applicable) /// if MFA is enabled and not already processed, authenticate the user against the configured MFA provider (OTP preferred) /// /// /// protected void ConnectButtonClick( object sender, EventArgs e) { if (!_authorizedRequest) return; // one time usage enterprise session url if (_enterpriseSession == null && Request["SI"] != null && Request["SD"] != null && Request["SK"] != null) { CreateEnterpriseSessionFromUrl(); } // MFA (OTP passcode) if (_enterpriseSession == null && _mfaAuthClient.GetState()) { var clientIP = ClientIPHelper.ClientIPFromRequest(new HttpContextWrapper(HttpContext.Current).Request, true, new string[] { }); if (!_mfaAuthClient.Authenticate(user.Value, mfaPassword.Value, clientIP)) { connectError.InnerText = "MFA Authentication failed!"; UpdateControls(); return; } } // enterprise mode from login if (_enterpriseSession == null && (_enterpriseClient.GetMode() == EnterpriseMode.Domain || _localAdmin)) { CreateEnterpriseSessionFromLogin(); } // connection from: // > standard mode // > enterprise mode: hosts list // > enterprise mode: one time session url else { // the display size is required to start a remote session // if missing, the client will provide it automatically if (string.IsNullOrEmpty(width.Value) || string.IsNullOrEmpty(height.Value)) { return; } // connect if (ConnectRemoteServer()) { // in enterprise mode from login, a new http session id was already generated (no need to do it each time an host is connected!) // in standard mode or enterprise mode from url, a new http session id must be generated if (_enterpriseSession == null || Request["SI"] != null) { // session fixation protection if (_httpSessionUseUri) { // generate a new http session id RemoteSession.OwnerSessionID = HttpSessionHelper.RegenerateSessionId(); } } try { // standard mode: switch to http get (standard login) or remove the connection params from url (auto-connect / start program from url) // enterprise mode: remove the host id from url Response.Redirect("~/", true); } catch (ThreadAbortException) { // occurs because the response is ended after redirect } } // connection failed from the hosts list or from a one time session url else if (_enterpriseSession != null && Request["SD"] != null) { try { // remove the host id from url Response.Redirect("~/", true); } catch (ThreadAbortException) { // occurs because the response is ended after redirect } } } } /// /// connect the remote server /// /// /// authentication is delegated to the remote server or connection broker (if applicable) /// private bool ConnectRemoteServer() { // connection parameters string loginHostName = null; var loginHostType = (HostType)Convert.ToInt32(hostType.Value); var loginProtocol = (SecurityProtocol)securityProtocol.SelectedIndex; var loginServer = string.IsNullOrEmpty(server.Value) ? "localhost" : server.Value; var loginVMGuid = vmGuid.Value; var loginVMAddress = string.Empty; var loginVMEnhancedMode = vmEnhancedMode.Checked; var loginDomain = domain.Value; var loginUser = user.Value; var loginPassword = string.IsNullOrEmpty(passwordHash.Value) ? password.Value : CryptoHelper.RDP_Decrypt(passwordHash.Value); var startProgram = program.Value; // allowed features var allowRemoteClipboard = _allowRemoteClipboard; var allowFileTransfer = _allowFileTransfer; var allowPrintDownload = _allowPrintDownload; var allowSessionSharing = _allowSessionSharing; var allowAudioPlayback = _allowAudioPlayback; // sharing parameters int maxActiveGuests = int.MaxValue; var connectionId = Guid.NewGuid(); // connect an host from the hosts list or from a one time session url if (_enterpriseSession != null && (!string.IsNullOrEmpty(Request["SD"]))) { long hostId; if (!long.TryParse(Request["SD"], out hostId)) { hostId = 0; } try { // retrieve the host connection details var connection = _enterpriseClient.GetSessionConnectionDetails(_enterpriseSession.SessionID, hostId, _enterpriseSession.SessionKey); if (connection == null) { System.Diagnostics.Trace.TraceInformation("Unable to retrieve host {0} connection details (invalid host or one time session url already used?)", hostId); return false; } loginHostName = connection.HostName; loginHostType = connection.HostType; loginProtocol = connection.Protocol; loginServer = !string.IsNullOrEmpty(connection.HostAddress) ? connection.HostAddress : connection.HostName; loginVMGuid = connection.VMGuid; loginVMEnhancedMode = connection.VMEnhancedMode; loginDomain = connection.Domain; loginUser = connection.Username; loginPassword = CryptoHelper.RDP_Decrypt(connection.Password); startProgram = connection.StartRemoteProgram; } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to retrieve host {0} connection details ({1})", hostId, exc); return false; } } // by using a connection service on a backend (connection API), the connection details can be hidden from querystring and mapped to a connection identifier else if (!string.IsNullOrEmpty(Request["cid"])) { if (!Guid.TryParse(Request["cid"], out connectionId)) { System.Diagnostics.Trace.TraceInformation("Invalid connection id {0}", Request["cid"]); return false; } try { // retrieve the connection details var connection = _connectionClient.GetConnectionInfo(connectionId); if (connection == null) { System.Diagnostics.Trace.TraceInformation("Unable to retrieve connection info {0}", connectionId); return false; } // ensure the user is allowed to connect the host if (!_connectionClient.IsUserAllowedToConnectHost(connection.User.Domain, connection.User.UserName, connection.Host.IPAddress, connection.VM != null ? connection.VM.Guid : Guid.Empty)) { System.Diagnostics.Trace.TraceInformation("User: domain={0}, name={1} is not allowed to connect host {2}", connection.User.Domain, connection.User.UserName, connection.Host.IPAddress); return false; } loginHostType = connection.Host.HostType; loginProtocol = connection.Host.SecurityProtocol; loginServer = connection.Host.IPAddress; loginVMGuid = connection.VM != null ? connection.VM.Guid.ToString() : string.Empty; loginVMAddress = connection.VM != null ? connection.VM.IPAddress : string.Empty; loginVMEnhancedMode = connection.VM != null ? connection.VM.EnhancedMode : false; loginDomain = connection.User.Domain; loginUser = connection.User.UserName; loginPassword = connection.User.Password; startProgram = connection.StartProgram; allowRemoteClipboard = allowRemoteClipboard && connection.AllowRemoteClipboard; allowFileTransfer = allowFileTransfer && connection.AllowFileTransfer; allowPrintDownload = allowPrintDownload && connection.AllowPrintDownload; allowSessionSharing = allowSessionSharing && connection.MaxActiveGuests > 0; allowAudioPlayback = allowAudioPlayback && connection.AllowAudioPlayback; maxActiveGuests = connection.MaxActiveGuests; } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to retrieve connection info {0} ({1})", connectionId, exc); return false; } } // if the connection from login screen or url is disabled, the connection must be done either by using a connection API or from the enterprise mode else if (!_loginEnabled) { return false; } // remove any active remote session (disconnected?) if (RemoteSession != null) { // unset the remote session for the current http session Session[HttpSessionStateVariables.RemoteSession.ToString()] = null; RemoteSession = null; } // create a new remote session try { Application.Lock(); // create the remote session RemoteSession = new RemoteSession( connectionId, loginHostName, loginHostType, loginProtocol, loginServer, loginVMGuid, loginVMAddress, loginVMEnhancedMode, !string.IsNullOrEmpty(loginDomain) ? loginDomain : AccountHelper.GetDomain(loginUser, loginPassword), AccountHelper.GetUserName(loginUser), loginPassword, int.Parse(width.Value), int.Parse(height.Value), startProgram, allowRemoteClipboard, allowFileTransfer, allowPrintDownload, allowSessionSharing, allowAudioPlayback, maxActiveGuests, Session.SessionID, (string)Session[HttpSessionStateVariables.ClientKey.ToString()], Request["cid"] != null ); // bind the remote session to the current http session Session[HttpSessionStateVariables.RemoteSession.ToString()] = RemoteSession; // register the remote session at the application level var remoteSessions = (IDictionary)Application[HttpApplicationStateVariables.RemoteSessions.ToString()]; remoteSessions.Add(RemoteSession.Id, RemoteSession); } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to create remote session ({0})", exc); RemoteSession = null; } finally { Application.UnLock(); } // connect it if (RemoteSession != null) { RemoteSession.State = RemoteSessionState.Connecting; } else { connectError.InnerText = "Failed to create remote session!"; return false; } return true; } #region enterprise mode /// /// create an enterprise session from a one time url /// private void CreateEnterpriseSessionFromUrl() { try { // create enterprise session from querystring params _enterpriseSession = new EnterpriseSession { IsAdmin = false, // simple host connection only (no hosts management) SessionID = Request["SI"], SessionKey = Request["SK"], SingleUseConnection = true }; // bind the enterprise session to the current http session Session[HttpSessionStateVariables.EnterpriseSession.ToString()] = _enterpriseSession; // session fixation protection if (_httpSessionUseUri) { // generate a new http session id HttpSessionHelper.RegenerateSessionId(); } } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to create enterprise session from url ({0})", exc); } } /// /// authenticate the user against the enterprise active directory and list the servers available to the user /// private void CreateEnterpriseSessionFromLogin() { try { // authenticate the user _enterpriseSession = _enterpriseClient.Authenticate(user.Value, password.Value); if (_enterpriseSession == null || _enterpriseSession.AuthenticationErrorCode != EnterpriseAuthenticationErrorCode.NONE) { if (_enterpriseSession == null) { connectError.InnerText = EnterpriseAuthenticationErrorHelper.GetErrorDescription(EnterpriseAuthenticationErrorCode.UNKNOWN_ERROR); } else if (_enterpriseSession.AuthenticationErrorCode == EnterpriseAuthenticationErrorCode.PASSWORD_EXPIRED) { ClientScript.RegisterClientScriptBlock(GetType(), Guid.NewGuid().ToString(), "window.onload = function() { " + string.Format("openPopup('changePasswordPopup', 'EnterpriseChangePassword.aspx?userName={0}" + (_localAdmin ? "&mode=admin" : string.Empty) + "');", user.Value) + " }", true); } else { connectError.InnerText = EnterpriseAuthenticationErrorHelper.GetErrorDescription(_enterpriseSession.AuthenticationErrorCode); } UpdateControls(); return; } // bind the enterprise session to the current http session Session[HttpSessionStateVariables.EnterpriseSession.ToString()] = _enterpriseSession; // session fixation protection if (_httpSessionUseUri) { // generate a new http session id HttpSessionHelper.RegenerateSessionId(); } // redirect to the hosts list Response.Redirect("~/", true); } catch (ThreadAbortException) { // occurs because the response is ended after redirect } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to create enterprise session from login ({0})", exc); } } /// /// populate the enterprise session hosts list /// /// /// protected void hostsList_ItemDataBound( object sender, RepeaterItemEventArgs e) { try { var host = e.Item.DataItem as EnterpriseHost; if (host.PromptForCredentials || string.IsNullOrEmpty(_enterpriseSession.Domain)) { var hostLink = e.Item.FindControl("hostLink") as HtmlAnchor; hostLink.HRef = null; hostLink.Attributes["onclick"] = string.Format("openPopup('editCredentialPopup', 'CredentialsPrompt.aspx?hostId={0}');", host.HostID); hostLink.Attributes["class"] = "hostLink"; } else { var hostLink = e.Item.FindControl("hostLink") as HtmlAnchor; hostLink.HRef = string.Format("?SD={0}&__EVENTTARGET=&__EVENTARGUMENT=&connect=Connect%21", host.HostID); hostLink.Attributes["class"] = "hostLink"; } var hostName = e.Item.FindControl("hostName") as HtmlGenericControl; hostName.InnerText = (_enterpriseSession.IsAdmin ? "Edit " : string.Empty) + host.HostName; if (_enterpriseSession.IsAdmin) { hostName.Attributes["class"] = "hostName"; hostName.Attributes["title"] = "edit"; hostName.Attributes["onclick"] = string.Format("openPopup('editHostPopup', 'EditHost.aspx?hostId={0}');", host.HostID); } } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to populate hosts for the enterprise session {0} ({1})", _enterpriseSession.SessionID, exc); } } /// /// logout the enterprise session /// /// /// protected void LogoutButtonClick( object sender, EventArgs e) { if (!_authorizedRequest) return; if (_enterpriseSession == null) return; try { // logout the enterprise session _enterpriseClient.Logout(_enterpriseSession.SessionID); Session[HttpSessionStateVariables.EnterpriseSession.ToString()] = null; _enterpriseSession = null; // redirect to the login screen Response.Redirect("~/", true); } catch (ThreadAbortException) { // occurs because the response is ended after redirect } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to logout the enterprise session {0} ({1})", _enterpriseSession.SessionID, exc); } } #endregion #region session sharing /// /// retrieve a shared remote session information /// /// /// private SharingInfo GetSharingInfo( Guid guestId) { SharingInfo sharingInfo = null; try { Application.Lock(); var sharedSessions = (IDictionary)Application[HttpApplicationStateVariables.SharedRemoteSessions.ToString()]; if (!sharedSessions.ContainsKey(guestId)) { connectError.InnerText = "Invalid sharing link"; } else { sharingInfo = sharedSessions[guestId]; if (sharingInfo.GuestInfo.Active) { connectError.InnerText = "The sharing link was already used"; sharingInfo = null; } else if (sharingInfo.RemoteSession.State != RemoteSessionState.Connected) { connectError.InnerText = "The session is not connected"; sharingInfo = null; } else if (sharingInfo.RemoteSession.ActiveGuests >= sharingInfo.RemoteSession.MaxActiveGuests) { connectError.InnerText = "The maximum number of active guests was reached for the session"; sharingInfo = null; } else { sharingInfo.HttpSession = Session; sharingInfo.RemoteSession.ActiveGuests++; sharingInfo.GuestInfo.Active = true; } } } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to retrieve the shared remote session for guest {0} ({1})", guestId, exc); } finally { Application.UnLock(); } return sharingInfo; } #endregion } }