Advanced .NET Authentication Extensions

Simple .NET Authentication Extensions can usually be used to accomplish what extension developers require. However at other times more complicated scenarios may require more flexibility.

As with simple extensions, advanced .NET Authentication Extension classes must extend EnterpriseDT.Net.FtpServer.Core.Authenticator.

However instead of overriding the LoadUserInfo method, they override the CheckUserName and Authenticate methods. In the EnterpriseDT.Net.FtpServer.Core.Authenticator base class implementation, LoadUserInfo is called by CheckUserName. But LoadUserInfo need not be overridden - instead CheckUserName can be overridden and LoadUserInfo need not be called at all.

Similarly, the Authenticate method is implemented in the Authenticator class, and if it is provided in CheckUserName or indirectly via LoadUserInfo, the LoadedUserInfo class containing the user's data will automatically be used to authenticate the user. However Authenticate can be overridden to authenticate in whatever way the extension writer prefers.

The primary requirement when overriding CheckUserName is to ensure that the IsValidUserName property of the supplied IUserInfo argument is set to true for a valid user. When overriding Authenticate, ensure that the IsCorrectPassword property of the supplied IAuthenticationInfo argument is set to true for password authentication, or IsValidKey is set to true for public key authentication. IAuthenticationInfo.AuthenticationMethod can be inspected to determine if password or public key authentication is being used. IsValidRSAKey and IsValidDSAKey can be used to determine if a key blob is the correct public key matching that which the user has supplied as part of their public key authentication process.

See the class reference for more details of the classes and interfaces involved.

Example 1

Below is the source-code for a sample authenticator, which allows a user to log in with the username, myusername, and the password, mypassword. The user's home directory will be C:\Temp if the defaultExtension's home-directory is set to %ExternalHomeFolder%.

using EnterpriseDT.Net.FtpServer.Core;

namespace MyTestAuthenticator
{
	public class PasswordAuthenticator : Authenticator
	{
		public override void CheckUserName(IUserInfo userInfo)
		{
			if (userInfo.UserName == "myusername")
				userInfo.IsValidUserName = true;
		}

		public override void Authenticate(IAuthenticationInfo authInfo)
		{
			if (authInfo.AuthenticationMethod == AuthenticationMethod.Password && authInfo.Password == "mypassword")
			{
				authInfo.IsCorrectPassword = true;
				authInfo.HomeDirectory = "C:\\Temp";
			}
		}
	}
}

Add the code above into the project and build the project.

Add .NET authentication extensions.

Enable the Authentication in the User panel.

Login with WinSCP via SFTP with username = "myusername" and password = "mypassword".

Login successful.

Example 2

Below is the source-code for a sample authenticator which allows a user to log in with the username, myusername via public key authentication. For simplicity, the public keys of the user are hard coded, whereas in production code they would be created as shown here. The user's home directory will be C:\Temp if the defaultExtension's home-directory is set to %ExternalHomeFolder%.

using System.Text;
using EnterpriseDT.Net.FtpServer.Core;

namespace MyTestAuthenticator
{
	public class PublicKeyAuthenticator : Authenticator
	{
		public override void CheckUserName(IUserInfo userInfo)
		{
			if (userInfo.UserName == "myusername")
				userInfo.IsValidUserName = true;
		}

		public override void Authenticate(IAuthenticationInfo authInfo)
		{
			if (authInfo.AuthenticationMethod == AuthenticationMethod.PublicKey)
			{
				if (authInfo.KeyAlgorithm == PublicKeyAlgorithm.DSA)
				{
					authInfo.IsValidKey = IsValidDSAKey(DSAPublicKey, authInfo);
				}
				else
				{
					authInfo.IsValidKey = IsValidRSAKey(RSAPublicKey, authInfo);
				}
				if (authInfo.IsValidKey)
					authInfo.HomeDirectory = "C:\\Temp";
			}
		}
    
		private byte[] RSAPublicKey
		{
			get
			{
				string key = "---- BEGIN SSH2 PUBLIC KEY ----\r\n" +
					"Comment: \"imported-openssh-key\"\r\n" +
					"AAAAB3NzaC1yc2EAAAABIwAAAIEA44J6LBloMWVvhOjMHZPnmgJWw+UWBl9nFEWa\r\n" +
					"62IFDrJDg6+kJ2DQD8vOTsQmNjk88O3v+r0r/rr+QrotuLrdjrXBvrRrQNMfEbMo\r\n" +
					"LhSmUVEFR/Yy3HjVRT6DHhJYPpr1xaXE6++fo5b2ax1zw+d1fPsh53lbAhrCHV9b\r\n" +
					"NIOimDk=\r\n" +
					"---- END SSH2 PUBLIC KEY ----";
				return Encoding.ASCII.GetBytes(key);
			}
		}

		private byte[] DSAPublicKey
		{
			get
			{
				string key = "---- BEGIN SSH2 PUBLIC KEY ----\r\n" +
					"Comment: \"imported-openssh-key\"\r\n" +
					"AAAAB3NzaC1kc3MAAACBAPos9tWoXLcd//dOGbaA+1TCO9vEi0jQOQM85j34E4Ua\r\n" +
					"Sza5yjS3vI9K9XchJirbNYrRQNmgM2yn3fUDdTPU5eES+mZRy9K9qpAesk4Ghpwu\r\n" +
					"btWc3e0APkQTUAoRHL8yiW1tHrRdV6yrowgKDPrIccnL90wYAZFHmUmwIeiESjTB\r\n" +
					"AAAAFQDhvm9w83LDeixC3oPW+FOKk673dQAAAIBObehA6t+eRtNTocY1sb7Dly0O\r\n" +
					"ReeRWo+mHEyUts78ayAN7YFNzTd8UXmUgw8gyGFtO/tXrkeLG46vMhL/0402ek9Z\r\n" +
					"jNcDq2vF1InYIaOxceuRqg99VGQUqrjEWchIG5egDgtOKRAUtUyK7I52CXG3wN9/\r\n" +
					"2Oq+WOoUztJCSwgmwwAAAIEAu4G5CHifmoTsBVcObaRkW8UqrTCmz7C84W6AaXA5\r\n" +
					"uBlwtTIBlAUnKzfqStpC76rucJ6i3R9Nk+gHrDb4v6uA6at2UZDlHZlwPCg88fk7\r\n" +
					"Nbi5umH9B/QSfm+GQOd+ttD54FOcR+lwmerJ+f1mzSX9v9ZrVi+xJJ6Jp+5NDa7g\r\n" +
					"KtM=\r\n" +
					"---- END SSH2 PUBLIC KEY ----";
				return Encoding.ASCII.GetBytes(key);
			}
		}
	}
}

Firstly, go to CompleteFTP, generate the key pair for the user (public key and private key). Add the public key to the code.

Build the project again.

Go to the setting in Default Sites/SFTP/SCP/AdvanceSFTP/authentication method = publickey and password.

Log with WinSCP via SFTP with username = "myusername" and add private key for this login (Advanced/SSH/Authentication/Private key file).

Login successful.