Merge branch 'v1.77.3-dev' of https://github.com/mRemoteNG/mRemoteNG into v1.77.3-dev

This commit is contained in:
Dimitrij
2023-08-02 12:24:16 +01:00
8 changed files with 221 additions and 8 deletions

View File

@@ -58,6 +58,7 @@ namespace mRemoteNG.Connection
private string _rdGatewayUsername;
private string _rdGatewayPassword;
private string _rdGatewayDomain;
private string _rdGatewayAccessToken;
private ExternalCredentialProvider _rdGatewayExternalCredentialProvider;
private string _rdGatewayUserViaAPI = "";
@@ -530,6 +531,17 @@ namespace mRemoteNG.Connection
set => SetField(ref _rdGatewayPassword, value, "RDGatewayPassword");
}
[LocalizedAttributes.LocalizedCategory(nameof(Language.RDPGateway), 4),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.RdpGatewayAccessToken)),
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionRdpGatewayAccessToken)),
PasswordPropertyText(true),
AttributeUsedInProtocol(ProtocolType.RDP)]
public string RDGatewayAccessToken
{
get => GetPropertyValue("RDGatewayAccessToken", _rdGatewayAccessToken);
set => SetField(ref _rdGatewayAccessToken, value, "RDGatewayAccessToken");
}
[LocalizedAttributes.LocalizedCategory(nameof(Language.RDPGateway), 4),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.RdpGatewayDomain)),
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionRDGatewayDomain)),

View File

@@ -15,6 +15,9 @@ namespace mRemoteNG.Connection.Protocol.RDP
SmartCard = 2,
[LocalizedAttributes.LocalizedDescription(nameof(Language.UseExternalCredentialProvider))]
ExternalCredentialProvider = 3
ExternalCredentialProvider = 3,
[LocalizedAttributes.LocalizedDescription(nameof(Language.UseAccessToken))]
AccessToken = 4
}
}

View File

@@ -0,0 +1,124 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace mRemoteNG.Connection.Protocol.RDP
{
internal static class RdGatewayAccessTokenHelper
{
public static string EncryptAuthCookieString(string cookieString)
{
byte[] cookieBytes = TsCryptEncryptString(cookieString);
if (cookieBytes != null)
{
return Convert.ToBase64String(cookieBytes);
}
return null;
}
public static string DecryptAuthCookieString(string cookieString) //TODO: decrypt is newer use, should we remove it?
{
return TsCryptDecryptString(Convert.FromBase64String(cookieString));
}
[StructLayout(LayoutKind.Sequential)]
struct CryptProtectPromptStruct
{
public int Size;
public int Flags;
public IntPtr Window;
public string Message;
}
[StructLayout(LayoutKind.Sequential)]
struct DataBlob
{
public int Size;
public IntPtr Data;
}
private const int CRYPTPROTECT_LOCAL_MACHINE = 0x00000004;
private const int CRYPTPROTECT_UI_FORBIDDEN = 0x00000001;
private const int CRYPTPROTECT_AUDIT = 0x00000010;
[DllImport("crypt32.dll", CharSet = CharSet.Unicode)]
private static extern bool CryptProtectData(
ref DataBlob dataIn,
IntPtr description,
IntPtr optionalEntropy,
IntPtr reserved,
IntPtr promptStruct,
int flags,
out DataBlob dataOut);
[DllImport("crypt32.dll", CharSet = CharSet.Unicode)] //TODO: decrypt is newer use, should we remove it?
private static extern bool CryptUnprotectData(
ref DataBlob dataIn,
IntPtr description,
IntPtr optionalEntropy,
IntPtr reserved,
IntPtr promptStruct,
int flags,
out DataBlob dataOut);
private static byte[] TsCryptEncryptString(string inputString)
{
DataBlob inputBlob;
DataBlob outputBlob;
byte[] outputData = null;
byte[] stringBytes = Encoding.Unicode.GetBytes(inputString);
byte[] inputData = new byte[stringBytes.Length + 2];
Buffer.BlockCopy(stringBytes, 0, inputData, 0, stringBytes.Length);
inputBlob.Size = inputData.Length;
inputBlob.Data = Marshal.AllocHGlobal(inputData.Length);
Marshal.Copy(inputData, 0, inputBlob.Data, inputBlob.Size);
if (CryptProtectData(ref inputBlob, IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, IntPtr.Zero, CRYPTPROTECT_UI_FORBIDDEN, out outputBlob))
{
outputData = new byte[outputBlob.Size];
Marshal.Copy(outputBlob.Data, outputData, 0, outputBlob.Size);
}
Marshal.FreeHGlobal(inputBlob.Data);
Marshal.FreeHGlobal(outputBlob.Data);
return outputData;
}
private static string TsCryptDecryptString(byte[] inputBytes) //TODO: decrypt is newer use, should we remove it?
{
DataBlob inputBlob;
DataBlob outputBlob;
byte[] outputData = null;
inputBlob.Size = inputBytes.Length;
inputBlob.Data = Marshal.AllocHGlobal(inputBytes.Length);
Marshal.Copy(inputBytes, 0, inputBlob.Data, inputBlob.Size);
if (CryptUnprotectData(ref inputBlob, IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, IntPtr.Zero, CRYPTPROTECT_UI_FORBIDDEN, out outputBlob))
{
outputData = new byte[outputBlob.Size];
Marshal.Copy(outputBlob.Data, outputData, 0, outputBlob.Size);
}
Marshal.FreeHGlobal(inputBlob.Data);
Marshal.FreeHGlobal(outputBlob.Data);
if (outputData != null)
{
return Encoding.Unicode.GetString(outputData).TrimEnd((Char)0);
}
return null;
}
}
}

View File

@@ -428,9 +428,18 @@ namespace mRemoteNG.Connection.Protocol.RDP
}
}
_rdpClient.TransportSettings2.GatewayUsername = gwu;
_rdpClient.TransportSettings2.GatewayPassword = gwp;
_rdpClient.TransportSettings2.GatewayDomain = gwd;
if (connectionInfo.RDGatewayUseConnectionCredentials != RDGatewayUseConnectionCredentials.AccessToken)
{
_rdpClient.TransportSettings2.GatewayUsername = gwu;
_rdpClient.TransportSettings2.GatewayPassword = gwp;
_rdpClient.TransportSettings2.GatewayDomain = gwd;
}
else
{
//TODO: should we check client version and throw if it is less than 7
}
break;
}
}

View File

@@ -37,6 +37,15 @@ namespace mRemoteNG.Connection.Protocol.RDP
if (connectionInfo.UseEnhancedMode)
RdpClient7.AdvancedSettings7.PCB += ";EnhancedMode=1";
}
if (connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.AccessToken)
{
var authToken = connectionInfo.RDGatewayAccessToken;
var encryptedAuthToken = RdGatewayAccessTokenHelper.EncryptAuthCookieString(authToken);
RdpClient7.TransportSettings3.GatewayEncryptedAuthCookie = encryptedAuthToken;
RdpClient7.TransportSettings3.GatewayEncryptedAuthCookieSize = (uint)encryptedAuthToken.Length;
RdpClient7.TransportSettings3.GatewayCredsSource = 5;
}
}
catch (Exception ex)
{

View File

@@ -646,7 +646,7 @@ namespace mRemoteNG.Resources.Language {
}
/// <summary>
/// Looks up a localized string similar to Automatically try to reconnect when disconnected from server (RDP &amp;&amp; ICA only).
/// Looks up a localized string similar to Display reconnection dialog when disconnected from server (RDP &amp;&amp; ICA only).
/// </summary>
internal static string CheckboxAutomaticReconnect {
get {
@@ -663,6 +663,15 @@ namespace mRemoteNG.Resources.Language {
}
}
/// <summary>
/// Looks up a localized string similar to Automatically try to reconnect when disconnected from server (RDP &amp;&amp; ICA only).
/// </summary>
internal static string CheckboxNoReconnect {
get {
return ResourceManager.GetString("CheckboxNoReconnect", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This proxy server requires authentication.
/// </summary>
@@ -1547,7 +1556,7 @@ namespace mRemoteNG.Resources.Language {
}
/// <summary>
/// Looks up a localized string similar to Disable Cursor blinking.
/// Looks up a localized string similar to Disable Cursor Blinking.
/// </summary>
internal static string DisableCursorBlinking {
get {
@@ -4053,6 +4062,15 @@ namespace mRemoteNG.Resources.Language {
}
}
/// <summary>
/// Looks up a localized string similar to Specifies the access token for Remote Desktop Gateway server..
/// </summary>
internal static string PropertyDescriptionRdpGatewayAccessToken {
get {
return ResourceManager.GetString("PropertyDescriptionRdpGatewayAccessToken", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Specifies the password of the Remote Desktop Gateway server..
/// </summary>
@@ -4133,8 +4151,8 @@ namespace mRemoteNG.Resources.Language {
return ResourceManager.GetString("PropertyDescriptionRedirectDiskDrivesCustom", resourceCulture);
}
}
/// <summary>
/// <summary>
/// Looks up a localized string similar to Select whether local disk drives should be shown on the remote host..
/// </summary>
internal static string PropertyDescriptionRedirectDrives {
@@ -4909,6 +4927,15 @@ namespace mRemoteNG.Resources.Language {
}
}
/// <summary>
/// Looks up a localized string similar to RDP-Gateway Access Token.
/// </summary>
internal static string RdpGatewayAccessToken {
get {
return ResourceManager.GetString("RdpGatewayAccessToken", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to RDP-Gateway Domain.
/// </summary>
@@ -6334,6 +6361,15 @@ namespace mRemoteNG.Resources.Language {
}
}
/// <summary>
/// Looks up a localized string similar to Use RD Gateway access token.
/// </summary>
internal static string UseAccessToken {
get {
return ResourceManager.GetString("UseAccessToken", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Use Console Session.
/// </summary>

View File

@@ -2334,4 +2334,13 @@ Nightly Channel includes Alphas, Betas &amp; Release Candidates.</value>
<data name="RedirectDiskDrivesCustom" xml:space="preserve">
<value>Custom Drives</value>
</data>
<data name="PropertyDescriptionRdpGatewayAccessToken" xml:space="preserve">
<value>Specifies the access token for Remote Desktop Gateway server.</value>
</data>
<data name="RdpGatewayAccessToken" xml:space="preserve">
<value>RDP-Gateway Access Token</value>
</data>
<data name="UseAccessToken" xml:space="preserve">
<value>Use RD Gateway access token</value>
</data>
</root>

View File

@@ -267,6 +267,7 @@ namespace mRemoteNG.UI.Controls.ConnectionInfoPropertyGrid
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayPassword));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayUseConnectionCredentials));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayUsername));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayAccessToken));
}
else if (SelectedConnectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.Yes ||
SelectedConnectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.SmartCard)
@@ -276,12 +277,22 @@ namespace mRemoteNG.UI.Controls.ConnectionInfoPropertyGrid
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayUsername));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayExternalCredentialProvider));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayUserViaAPI));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayAccessToken));
}
else if (SelectedConnectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.ExternalCredentialProvider)
{
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayDomain));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayPassword));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayUsername));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayAccessToken));
}
else if (SelectedConnectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.AccessToken)
{
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayDomain));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayPassword));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayUsername));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayExternalCredentialProvider));
strHide.Add(nameof(AbstractConnectionRecord.RDGatewayUserViaAPI));
}
if (!(SelectedConnectionInfo.Resolution == RDPResolutions.FitToWindow ||