Skip to content

Commit

Permalink
resynced FreeRDP with master repository (fixes the NLA issue introdu…
Browse files Browse the repository at this point in the history
…ced with Windows updates KB4088776, KB4088787, KB4088876, KB4088875)

added support for MFA (one time password and one time host session url) (thanks Paul Oliver). Refer to documentation for activation
added enterprise mode (AD pre-authentication and hosts list management) (thanks Paul Oliver). Refer to documentation for activation
in enterprise mode, the security mode for the host connection is now configurable (NLA, TLS, RDP, etc.)
most FreeRDP connection params are now configurable (myrtille\bin\Myrtille.Services.exe.config)
the remote clipboard can now be disabled, for enhanced security (myrtille\Web.config)
replaced client redirects by server redirects (cleaner and more friendly to proxies)
added more connection details to myrtille logs
  • Loading branch information
cedrozor committed Mar 29, 2018
1 parent d775015 commit b7c8f5f
Show file tree
Hide file tree
Showing 77 changed files with 5,217 additions and 916 deletions.
12 changes: 11 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
2018-02-07 Version 1.7.0 (stable)
2018-03-29 Version 1.8.0 (beta)
resynced FreeRDP with master repository (fixes the NLA issue introduced with Windows updates KB4088776, KB4088787, KB4088876, KB4088875)
added support for MFA (one time password and one time host session url) (thanks Paul Oliver). Refer to documentation for activation
added enterprise mode (AD pre-authentication and hosts list management) (thanks Paul Oliver). Refer to documentation for activation
in enterprise mode, the security mode for the host connection is now configurable (NLA, TLS, RDP, etc.)
most FreeRDP connection params are now configurable (myrtille\bin\Myrtille.Services.exe.config)
the remote clipboard can now be disabled, for enhanced security (myrtille\Web.config)
replaced client redirects by server redirects (cleaner and more friendly to proxies)
added more connection details to myrtille logs

2018-02-07 Version 1.7.0 (stable)
resynced FreeRDP with master repository; FreeRDP 2.0-RC2 milestone: https://github.com/FreeRDP/FreeRDP/milestone/8
FreeRDP HOTFIX: connection using FQDN is broken (either direct connection or through a connection broker redirection), using target IP instead
FreeRDP HOTFIX: fixed client IP resolution when using an ipv6 connection
Expand Down
2 changes: 1 addition & 1 deletion DISCLAIMERS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## FreeRDP, Myrtille, Log4net
## FreeRDP, Myrtille, Log4net, OASIS

Apache License
Version 2.0, January 2004
Expand Down
64 changes: 62 additions & 2 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
# Introduction
[Introduction](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#introduction)
[History](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#history)
[Installation](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#installation)
[Auto-connect / Start remote application from URL](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#auto-connect--start-remote-application-from-url)
[Syntax](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#syntax)
[Password Hash](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#password-hash)
[File transfer](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#file-transfer)
[Security](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#security)
[Configuration / Performance tweaks](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#configuration--performance-tweaks)
[Code organization](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#code-organization)
[Build](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#build)
[Startup projects](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#startup-projects)
[Communication](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#communication)
[Overview](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#overview)
[Protocols](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#protocols)
[Multifactor Authentication](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#multifactor-authentication)
[Enterprise Mode](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#enterprise-mode)
[Notes and limitations](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#notes-and-limitations)
[Troubleshoot](https://github.com/cedrozor/myrtille/blob/master/DOCUMENTATION.md#troubleshoot)

# Introduction
I worked hard to make Myrtille as straightforward as possible, with commented code, but some points may needs additional information.

If you have any issue, question or suggestion that isn't addressed into this synthetic documentation, FAQ or Wiki, please don't hesitate to contact me ([email protected]) or ask the community (https://groups.google.com/forum/#!forum/myrtille_rdp).
Expand Down Expand Up @@ -46,7 +66,6 @@ The pre version 1.5.0 syntax ("&password=*password*") is still supported, but it
The parameters values **must be URL encoded**. You can use a tool like http://www.url-encode-decode.com/ (just copy & paste the encoded parameters into the URL).

### Password Hash

To generate a password hash, you can use the powershell script "password51.ps1" on the myrtille gateway (requires access to the machine). The script is located into the myrtille bin folder at runtime or into the "Myrtille.Services" project under Visual Studio.
- Run the script (from its location folder): ". .\password51.ps1" (if needed, see powershell script execution policy: https://technet.microsoft.com/en-us/library/ee176961.aspx)
- Call the encrypt function: "Encrypt-RDP-Password -Password *password*"
Expand Down Expand Up @@ -145,6 +164,47 @@ However, I'm fully aware that it breaks the distributed architecture pattern. Th

This is a thing to consider if you want to isolate the web gateway from your intranet (into a DMZ for instance) and still be able to connect a machine on it.

## Multifactor Authentication
Enabling this option allows you to require users to provide a one-time passcode which is validated against a cloud based 2fa authentication platform. This requires a mobile application which can be used to scan QR codes and generate the one-time passcodes; these applications are free from app stores and a popular choice is google authenticator.

In addition to 2fa, an access control could be enforced to allow connections only from given areas (geo ip location) and time (not implemented for now).

The adapter has been written to use a platform provided by Olive Innovations and named OASIS. It's free to use up to 10 users; to use this service follow these instructions:

1) Visit https://oasis.oliveinnovations.com and register for free
2) Once logged in, create a User Group (into the menu select User Groups), then click New, input a Name (i.e. Myrtille) and save
3) Create a user (choose Users from the menu), then click New, input user details and tick the box to send register by email (**IMPORTANT** the username must be the same as the username you will login with myrtille; when registering via email, the user will have a link to complete the registration) and save. Into the user details page, select the user group created in Step 2
NOTE: If you have enabled Enterprise Mode and wish to sync your Active Directory with OASIS, visit http://www.oliveinnovations.com, go to download area and download the Gateway application; instructions for configuration can be found into the docs on the same website
4) Create an application (choose Applications from the menu), then click New, enter a Name and save. You will be directed to the application details page, grant access to the user group created in Step 2
5) Within the application page, click the button Application Key, this will display the information to configure myrtille

Once these steps are completed, edit the app.config file of Myrtille.Services and uncomment the following appSettings:
- `MFAAuthAdapter`, this is the OASIS MFA adapter
- `OASISApiKey`, this is the API Key found when you clicked Application Key in step 5
- `OASISAppID`, this is the App ID found when you clicked Application Key in step 5
- `OASISAppKey`, this is the App Key found when you clicked Application Key in step 5
- Restart Myrtille.Services windows service to use the new settings

The included MFA adapter is written by Olive Innovations Ltd for use with the OASIS platform. This adapter uses a nuget package, OASIS.Integration (https://www.nuget.org/packages/OASIS.Integration/) available open source (https://github.com/OliveInnovations/OASIS/).
If you wish to create your own MFA adapter, `Myrtille.Services.Contracts` contains the interfaces you need.

## Enterprise Mode
When enabled, the enterprise mode authenticates users against a domain and allows administrators to create hosts connections which can be restricted to the security groups the authenticated users belongs to.

The enterprise mode provides the following additional features:
- Authenticate users against a domain/active directory instead of a host they wish to connect to
- Allow administrators to define a list of hosts; these hosts are the only hosts the users can connect to
- Access to hosts can be restricted based on the groups the authenticated users belongs to
- Administrators can create a single use session url to a specific host (with specific login credentials) which can be shared with external (non domain) users and only be used once

To enable enterprise mode, edit the app.config file of Myrtille.Services and uncomment the following appSettings:
- `EnterpriseAdapter`, this is the adapter to use for enterprise mode
- `EnterpriseAdminGroup`, this is the security group which will define a user as an administrator who can create, edit, delete hosts, define access to hosts and create single use sessions
- `EnterpriseDomain`, this is the NETBIOS name (i.e. MYDOMAIN) or FQDN (i.e. mydomain.local) of your domain
- Restart Myrtille.Services windows service to use the new settings

If you wish to create your own enterprise adapter (with a different authentication, database or behavior), `Myrtille.Services.Contracts` contains the interfaces you need.

## Notes and limitations
- Starting from myrtille version 1.2.0, the packaged FreeRDP and OpenSSL binaries use a statically-linked runtime; that means there is no longer need for the Microsoft Visual C++ redistributables (x86). It's still a good idea to install them however as they will be required if the build options are changed.

Expand Down
154 changes: 154 additions & 0 deletions Myrtille.Common/Helpers/ClientIPHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Web;

namespace Myrtille.Helpers
{
public static class ClientIPHelper
{
// based on http://www.grantburton.com/2008/11/30/fix-for-incorrect-ip-addresses-in-wordpress-comments/
public static string ClientIPFromRequest(this HttpRequestBase request, bool skipPrivate, string[] ignoreAddresses)
{
foreach (var item in s_HeaderItems)
{
var ipString = (item.ServerVariable ? request.ServerVariables[item.Key] : request.Headers[item.Key]);

if (String.IsNullOrEmpty(ipString))
continue;

if (item.Split)
{
foreach (var ip in ipString.Split(','))
if (ValidIP(ip, skipPrivate) && !ignoreAddresses.Contains(ip))
return ip;
}
else
{
if (ValidIP(ipString, skipPrivate) && !ignoreAddresses.Contains(ipString))
return ipString;
}
}

return request.UserHostAddress;
}

private static bool ValidIP(string ip, bool skipPrivate)
{
IPAddress ipAddr;

ip = ip == null ? String.Empty : ip.Trim();

if (0 == ip.Length
|| false == IPAddress.TryParse(ip, out ipAddr)
|| (ipAddr.AddressFamily != AddressFamily.InterNetwork
&& ipAddr.AddressFamily != AddressFamily.InterNetworkV6))
return false;

if (skipPrivate && ipAddr.AddressFamily == AddressFamily.InterNetwork)
{
var addr = IpRange.AddrToUInt64(ipAddr);
foreach (var range in s_PrivateRanges)
{
if (range.Encompasses(addr))
return false;
}
}

return true;
}

/// <summary>
/// Provides a simple class that understands how to parse and
/// compare IP addresses (IPV4) ranges.
/// </summary>
private sealed class IpRange
{
private readonly UInt64 _start;
private readonly UInt64 _end;

public IpRange(string startStr, string endStr)
{
_start = ParseToUInt64(startStr);
_end = ParseToUInt64(endStr);
}

public static UInt64 AddrToUInt64(IPAddress ip)
{
var ipBytes = ip.GetAddressBytes();
UInt64 value = 0;

foreach (var abyte in ipBytes)
{
value <<= 8; // shift
value += abyte;
}

return value;
}

public static UInt64 ParseToUInt64(string ipStr)
{
var ip = IPAddress.Parse(ipStr);
return AddrToUInt64(ip);
}

public bool Encompasses(UInt64 addrValue)
{
return _start <= addrValue && addrValue <= _end;
}

public bool Encompasses(IPAddress addr)
{
var value = AddrToUInt64(addr);
return Encompasses(value);
}
};

private static readonly IpRange[] s_PrivateRanges =
new IpRange[] {
new IpRange("0.0.0.0","2.255.255.255"),
new IpRange("10.0.0.0","10.255.255.255"),
new IpRange("127.0.0.0","127.255.255.255"),
new IpRange("169.254.0.0","169.254.255.255"),
new IpRange("172.16.0.0","172.31.255.255"),
new IpRange("192.0.2.0","192.0.2.255"),
new IpRange("192.168.0.0","192.168.255.255"),
new IpRange("255.255.255.0","255.255.255.255")
};

/// <summary>
/// Describes a header item (key) and if it is expected to be
/// a comma-delimited string
/// </summary>
private sealed class HeaderItem
{
public readonly string Key;
public readonly bool Split;
public readonly bool ServerVariable;

public HeaderItem(string key, bool split, bool serverVariable)
{
Key = key;
Split = split;
ServerVariable = serverVariable;
}
}

// order is in trust/use order top to bottom
private static readonly HeaderItem[] s_HeaderItems =
new HeaderItem[] {
new HeaderItem("X-Client-IP",false,true),
new HeaderItem("HTTP_CLIENT_IP",false,false),
new HeaderItem("X-Forwarded-For",true,true),
new HeaderItem("HTTP_X_FORWARDED_FOR",true,false),
new HeaderItem("HTTP_X_FORWARDED",false,false),
new HeaderItem("HTTP_X_CLUSTER_CLIENT_IP",false,false),
new HeaderItem("HTTP_FORWARDED_FOR",false,false),
new HeaderItem("HTTP_FORWARDED",false,false),
new HeaderItem("HTTP_VIA",false,false),
new HeaderItem("REMOTE_ADDR",false,false)
};
}
}
1 change: 1 addition & 0 deletions Myrtille.Common/Myrtille.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Helpers\CertificateHelper.cs" />
<Compile Include="Helpers\ClientIPHelper.cs" />
<Compile Include="Helpers\FileHelper.cs" />
<Compile Include="Helpers\FirewallHelper.cs" />
<Compile Include="Helpers\IISHelper.cs" />
Expand Down
2 changes: 1 addition & 1 deletion Myrtille.Common/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@
//
// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de révision et de build par défaut
// en utilisant '*', comme indiqué ci-dessous :
[assembly: AssemblyVersion("1.7.0.0")]
[assembly: AssemblyVersion("1.8.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
Loading

0 comments on commit b7c8f5f

Please sign in to comment.