mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-29 09:35:38 -05:00
Adding network share validation in sql migration. (#1203)
* adding network file validator contract * Adding UNC path validation * Using helper methods for sanity checks * Fixed the validation variable type * Fixing if condition
This commit is contained in:
@@ -22,7 +22,8 @@ using Microsoft.Win32.SafeHandles;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using System.Security.Principal;
|
||||
using System.IO;
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Migration
|
||||
{
|
||||
/// <summary>
|
||||
@@ -93,6 +94,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
|
||||
this.ServiceHost = serviceHost;
|
||||
this.ServiceHost.SetRequestHandler(MigrationAssessmentsRequest.Type, HandleMigrationAssessmentsRequest);
|
||||
this.ServiceHost.SetRequestHandler(ValidateWindowsAccountRequest.Type, HandleValidateWindowsAccountRequest);
|
||||
this.ServiceHost.SetRequestHandler(ValidateNetworkFileShareRequest.Type, HandleValidateNetworkFileShareRequest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -259,24 +261,18 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
|
||||
|
||||
internal async Task HandleValidateWindowsAccountRequest(
|
||||
ValidateWindowsAccountRequestParams parameters,
|
||||
RequestContext<ValidateWindowsAccountResult> requestContext)
|
||||
RequestContext<bool> requestContext)
|
||||
{
|
||||
var domainUserRegex = new Regex(@"^[A-Za-z0-9\\\._-]{7,}$");
|
||||
// Checking if the username string is in 'domain\name' format
|
||||
if (!domainUserRegex.Match(parameters.Username).Success)
|
||||
if (!ValidateWindowsDomainUsername(parameters.Username))
|
||||
{
|
||||
await requestContext.SendResult(new ValidateWindowsAccountResult()
|
||||
{
|
||||
Success = false,
|
||||
ErrorMessage = "Invalid user name format. Example: Domain\\username"
|
||||
});
|
||||
await requestContext.SendError("Invalid user name format. Example: Domain\\username");
|
||||
return;
|
||||
}
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
int separator = parameters.Username.IndexOf("\\");
|
||||
string domainName = (separator > -1) ? parameters.Username.Substring(0, separator) : string.Empty;
|
||||
string userName = (separator > -1) ? parameters.Username.Substring(separator + 1, parameters.Username.Length - separator - 1) : string.Empty;
|
||||
string domainName = parameters.Username.Substring(0, separator);
|
||||
string userName = parameters.Username.Substring(separator + 1, parameters.Username.Length - separator - 1);
|
||||
|
||||
const int LOGON32_PROVIDER_DEFAULT = 0;
|
||||
const int LOGON32_LOGON_INTERACTIVE = 2;
|
||||
@@ -286,23 +282,102 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
|
||||
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
|
||||
out safeAccessTokenHandle);
|
||||
|
||||
if (false == returnValue)
|
||||
if (!returnValue)
|
||||
{
|
||||
int ret = Marshal.GetLastWin32Error();
|
||||
string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
|
||||
await requestContext.SendResult(new ValidateWindowsAccountResult()
|
||||
{
|
||||
Success = returnValue,
|
||||
ErrorMessage = errorMessage
|
||||
});
|
||||
await requestContext.SendError(errorMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
await requestContext.SendResult(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await requestContext.SendResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task HandleValidateNetworkFileShareRequest(
|
||||
ValidateNetworkFileShareRequestParams parameters,
|
||||
RequestContext<bool> requestContext)
|
||||
{
|
||||
if (!ValidateWindowsDomainUsername(parameters.Username))
|
||||
{
|
||||
await requestContext.SendError("Invalid user name format. Example: Domain\\username");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateUNCPath(parameters.Path))
|
||||
{
|
||||
await requestContext.SendError("Invalid network share path. Example: \\\\Servername.domainname.com\\Backupfolder");
|
||||
return;
|
||||
}
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
int separator = parameters.Username.IndexOf("\\");
|
||||
string domainName = parameters.Username.Substring(0, separator);
|
||||
string userName = parameters.Username.Substring(separator + 1, parameters.Username.Length - separator - 1);
|
||||
|
||||
const int LOGON32_PROVIDER_WINNT50 = 3;
|
||||
const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
|
||||
|
||||
SafeAccessTokenHandle safeAccessTokenHandle;
|
||||
bool returnValue = LogonUser(
|
||||
userName,
|
||||
domainName,
|
||||
parameters.Password,
|
||||
LOGON32_LOGON_NEW_CREDENTIALS,
|
||||
LOGON32_PROVIDER_WINNT50,
|
||||
out safeAccessTokenHandle);
|
||||
|
||||
if (!returnValue)
|
||||
{
|
||||
int ret = Marshal.GetLastWin32Error();
|
||||
string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
|
||||
await requestContext.SendError(errorMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
await requestContext.SendResult(new ValidateWindowsAccountResult()
|
||||
await WindowsIdentity.RunImpersonated(
|
||||
safeAccessTokenHandle,
|
||||
// User action
|
||||
async () =>
|
||||
{
|
||||
if(!Directory.Exists(parameters.Path)){
|
||||
await requestContext.SendError("Cannot connect to file share");
|
||||
} else {
|
||||
await requestContext.SendResult(true);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Success = true,
|
||||
ErrorMessage = ""
|
||||
});
|
||||
await requestContext.SendResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the username is in 'domain\username' format.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal bool ValidateWindowsDomainUsername(string username)
|
||||
{
|
||||
var domainUserRegex = new Regex(@"^(?<domain>[A-Za-z0-9\._-]*)\\(?<username>[A-Za-z0-9\._-]*)$");
|
||||
return domainUserRegex.IsMatch(username);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the file path is in UNC format '\\Servername.domainname.com\Backupfolder'
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
internal bool ValidateUNCPath(string path)
|
||||
{
|
||||
return new Uri(path).IsUnc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user