Adding windows account validation api for sql migration extensions. (#1202)

* Adding validate file share api

* Making message endpoint camel case

* Adding validation for windows username
This commit is contained in:
Aasim Khan
2021-05-04 06:51:45 +00:00
committed by GitHub
parent 7fc07d08c0
commit 3ad2b2312a
2 changed files with 92 additions and 10 deletions

View File

@@ -11,7 +11,6 @@ using Microsoft.SqlServer.Management.Assessment;
using Microsoft.SqlServer.Management.Assessment.Checks;
using Microsoft.SqlServer.Migration.Assessment.Common.Contracts.Models;
using Microsoft.SqlServer.Migration.Assessment.Common.Engine;
using Microsoft.SqlServer.Migration.Assessment.Common.Models;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
@@ -19,7 +18,10 @@ using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.Migration.Contracts;
using Microsoft.SqlTools.ServiceLayer.SqlAssessment;
using Microsoft.SqlTools.ServiceLayer.SqlAssessment.Contracts;
using Microsoft.Win32.SafeHandles;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
namespace Microsoft.SqlTools.ServiceLayer.Migration
{
@@ -27,9 +29,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
/// Main class for Migration Service functionality
/// </summary>
public sealed class MigrationService : IDisposable
{
{
private static ConnectionService connectionService = null;
private static readonly Lazy<MigrationService> instance = new Lazy<MigrationService>(() => new MigrationService());
private bool disposed;
@@ -90,13 +92,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
{
this.ServiceHost = serviceHost;
this.ServiceHost.SetRequestHandler(MigrationAssessmentsRequest.Type, HandleMigrationAssessmentsRequest);
this.ServiceHost.SetRequestHandler(ValidateWindowsAccountRequest.Type, HandleValidateWindowsAccountRequest);
}
/// <summary>
/// Handle request to start a migration session
/// </summary>
internal async Task HandleMigrationAssessmentsRequest(
MigrationAssessmentsParams parameters,
MigrationAssessmentsParams parameters,
RequestContext<MigrationAssessmentResult> requestContext)
{
string randomUri = Guid.NewGuid().ToString();
@@ -141,7 +144,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
result.Items.AddRange(results);
await requestContext.SendResult(result);
}
catch(Exception e){
catch (Exception e)
{
await requestContext.SendError(e.ToString());
}
finally
@@ -150,7 +154,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
}
}
internal class AssessmentRequest : IAssessmentRequest
{
private readonly Check[] checks = null;
@@ -182,7 +186,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
{
DmaEngine engine = new DmaEngine(connectionString);
var assessmentResults = await engine.GetTargetAssessmentResultsList();
var result = new List<MigrationAssessmentInfo>();
foreach (var r in assessmentResults)
{
@@ -194,13 +198,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
var targetName = !string.IsNullOrWhiteSpace(migrationResult.DatabaseName)
? $"{target.ServerName}:{migrationResult.DatabaseName}"
: target.Name;
: target.Name;
var ruleId = migrationResult.FeatureId.ToString();
var item = new MigrationAssessmentInfo()
{
CheckId = r.Check.Id,
Description = r.Check.Description,
Description = r.Check.Description,
DisplayName = r.Check.DisplayName,
HelpLink = r.Check.HelpLink,
Level = r.Check.Level.ToString(),
@@ -248,5 +252,57 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
disposed = true;
}
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, out SafeAccessTokenHandle phToken);
internal async Task HandleValidateWindowsAccountRequest(
ValidateWindowsAccountRequestParams parameters,
RequestContext<ValidateWindowsAccountResult> 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)
{
await requestContext.SendResult(new ValidateWindowsAccountResult()
{
Success = false,
ErrorMessage = "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;
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
SafeAccessTokenHandle safeAccessTokenHandle;
bool returnValue = LogonUser(userName, domainName, parameters.Password,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
out safeAccessTokenHandle);
if (false == returnValue)
{
int ret = Marshal.GetLastWin32Error();
string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
await requestContext.SendResult(new ValidateWindowsAccountResult()
{
Success = returnValue,
ErrorMessage = errorMessage
});
return;
}
}
await requestContext.SendResult(new ValidateWindowsAccountResult()
{
Success = true,
ErrorMessage = ""
});
}
}
}