mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 14:07:46 +08:00
Merge branch 'v1.77.3-dev' of https://github.com/mRemoteNG/mRemoteNG into v1.77.3-dev
This commit is contained in:
@@ -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)),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
124
mRemoteNG/Connection/Protocol/RDP/RdGatewayAccessTokenHelper.cs
Normal file
124
mRemoteNG/Connection/Protocol/RDP/RdGatewayAccessTokenHelper.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
40
mRemoteNG/Language/Language.Designer.cs
generated
40
mRemoteNG/Language/Language.Designer.cs
generated
@@ -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 && ICA only).
|
||||
/// Looks up a localized string similar to Display reconnection dialog when disconnected from server (RDP && 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 && 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -2334,4 +2334,13 @@ Nightly Channel includes Alphas, Betas & 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>
|
||||
@@ -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 ||
|
||||
|
||||
Reference in New Issue
Block a user