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

@@ -0,0 +1,26 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.Migration.Contracts
{
public class ValidateWindowsAccountRequestParams
{
public string Username { get; set; }
public string Password { get; set; }
}
public class ValidateWindowsAccountResult
{
public bool Success { get; set; }
public string ErrorMessage { get; set; }
}
public class ValidateWindowsAccountRequest
{
public static readonly RequestType<ValidateWindowsAccountRequestParams, ValidateWindowsAccountResult> Type = RequestType<ValidateWindowsAccountRequestParams, ValidateWindowsAccountResult>.Create("migration/validateWindowsAccount");
}
}

View File

@@ -11,7 +11,6 @@ using Microsoft.SqlServer.Management.Assessment;
using Microsoft.SqlServer.Management.Assessment.Checks; using Microsoft.SqlServer.Management.Assessment.Checks;
using Microsoft.SqlServer.Migration.Assessment.Common.Contracts.Models; using Microsoft.SqlServer.Migration.Assessment.Common.Contracts.Models;
using Microsoft.SqlServer.Migration.Assessment.Common.Engine; using Microsoft.SqlServer.Migration.Assessment.Common.Engine;
using Microsoft.SqlServer.Migration.Assessment.Common.Models;
using Microsoft.SqlTools.Hosting.Protocol; using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts; 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.Hosting;
using Microsoft.SqlTools.ServiceLayer.Migration.Contracts; using Microsoft.SqlTools.ServiceLayer.Migration.Contracts;
using Microsoft.SqlTools.ServiceLayer.SqlAssessment; 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 namespace Microsoft.SqlTools.ServiceLayer.Migration
{ {
@@ -27,9 +29,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
/// Main class for Migration Service functionality /// Main class for Migration Service functionality
/// </summary> /// </summary>
public sealed class MigrationService : IDisposable public sealed class MigrationService : IDisposable
{ {
private static ConnectionService connectionService = null; private static ConnectionService connectionService = null;
private static readonly Lazy<MigrationService> instance = new Lazy<MigrationService>(() => new MigrationService()); private static readonly Lazy<MigrationService> instance = new Lazy<MigrationService>(() => new MigrationService());
private bool disposed; private bool disposed;
@@ -90,13 +92,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
{ {
this.ServiceHost = serviceHost; this.ServiceHost = serviceHost;
this.ServiceHost.SetRequestHandler(MigrationAssessmentsRequest.Type, HandleMigrationAssessmentsRequest); this.ServiceHost.SetRequestHandler(MigrationAssessmentsRequest.Type, HandleMigrationAssessmentsRequest);
this.ServiceHost.SetRequestHandler(ValidateWindowsAccountRequest.Type, HandleValidateWindowsAccountRequest);
} }
/// <summary> /// <summary>
/// Handle request to start a migration session /// Handle request to start a migration session
/// </summary> /// </summary>
internal async Task HandleMigrationAssessmentsRequest( internal async Task HandleMigrationAssessmentsRequest(
MigrationAssessmentsParams parameters, MigrationAssessmentsParams parameters,
RequestContext<MigrationAssessmentResult> requestContext) RequestContext<MigrationAssessmentResult> requestContext)
{ {
string randomUri = Guid.NewGuid().ToString(); string randomUri = Guid.NewGuid().ToString();
@@ -141,7 +144,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
result.Items.AddRange(results); result.Items.AddRange(results);
await requestContext.SendResult(result); await requestContext.SendResult(result);
} }
catch(Exception e){ catch (Exception e)
{
await requestContext.SendError(e.ToString()); await requestContext.SendError(e.ToString());
} }
finally finally
@@ -150,7 +154,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
} }
} }
internal class AssessmentRequest : IAssessmentRequest internal class AssessmentRequest : IAssessmentRequest
{ {
private readonly Check[] checks = null; private readonly Check[] checks = null;
@@ -182,7 +186,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
{ {
DmaEngine engine = new DmaEngine(connectionString); DmaEngine engine = new DmaEngine(connectionString);
var assessmentResults = await engine.GetTargetAssessmentResultsList(); var assessmentResults = await engine.GetTargetAssessmentResultsList();
var result = new List<MigrationAssessmentInfo>(); var result = new List<MigrationAssessmentInfo>();
foreach (var r in assessmentResults) foreach (var r in assessmentResults)
{ {
@@ -194,13 +198,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
var targetName = !string.IsNullOrWhiteSpace(migrationResult.DatabaseName) var targetName = !string.IsNullOrWhiteSpace(migrationResult.DatabaseName)
? $"{target.ServerName}:{migrationResult.DatabaseName}" ? $"{target.ServerName}:{migrationResult.DatabaseName}"
: target.Name; : target.Name;
var ruleId = migrationResult.FeatureId.ToString(); var ruleId = migrationResult.FeatureId.ToString();
var item = new MigrationAssessmentInfo() var item = new MigrationAssessmentInfo()
{ {
CheckId = r.Check.Id, CheckId = r.Check.Id,
Description = r.Check.Description, Description = r.Check.Description,
DisplayName = r.Check.DisplayName, DisplayName = r.Check.DisplayName,
HelpLink = r.Check.HelpLink, HelpLink = r.Check.HelpLink,
Level = r.Check.Level.ToString(), Level = r.Check.Level.ToString(),
@@ -248,5 +252,57 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
disposed = true; 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 = ""
});
}
} }
} }