mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 18:47:57 -05:00
Add login management handlers (#1868)
* update contracts * finish creating/loading login for SQL Server * support role read for azure and add more handlers * fix advanced option flags --------- Co-authored-by: Karl Burtram <karlb@microsoft.com>
This commit is contained in:
@@ -12,14 +12,24 @@ using Newtonsoft.Json.Converters;
|
|||||||
namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
public enum LoginType
|
public enum LoginAuthenticationType
|
||||||
{
|
{
|
||||||
[EnumMember(Value = "Windows")]
|
[EnumMember(Value = "Windows")]
|
||||||
Windows,
|
Windows,
|
||||||
[EnumMember(Value = "Sql")]
|
[EnumMember(Value = "Sql")]
|
||||||
Sql,
|
Sql,
|
||||||
[EnumMember(Value = "AAD")]
|
[EnumMember(Value = "AAD")]
|
||||||
AzureActiveDirectory
|
AAD,
|
||||||
|
[EnumMember(Value = "Others")]
|
||||||
|
Others
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ServerLoginDatabaseUserMapping
|
||||||
|
{
|
||||||
|
public string Database { get; set; }
|
||||||
|
public string User { get; set; }
|
||||||
|
public string DefaultSchema { get; set; }
|
||||||
|
public string[] DatabaseRoles { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -27,27 +37,22 @@ namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class LoginInfo
|
public class LoginInfo
|
||||||
{
|
{
|
||||||
public string LoginName { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public LoginType LoginType { get; set; }
|
public LoginAuthenticationType AuthenticationType { get; set; }
|
||||||
|
|
||||||
public string CertificateName { get; set; }
|
|
||||||
|
|
||||||
public string AsymmetricKeyName { get; set; }
|
|
||||||
|
|
||||||
public bool WindowsGrantAccess { get; set; }
|
public bool WindowsGrantAccess { get; set; }
|
||||||
|
|
||||||
public bool MustChange { get; set; }
|
public bool MustChangePassword { get; set; }
|
||||||
|
|
||||||
public bool IsDisabled { get; set; }
|
public bool IsEnabled { get; set; }
|
||||||
|
public bool ConnectPermission { get; set; }
|
||||||
|
|
||||||
public bool IsLockedOut { get; set; }
|
public bool IsLockedOut { get; set; }
|
||||||
|
|
||||||
public bool EnforcePolicy { get; set; }
|
public bool EnforcePasswordPolicy { get; set; }
|
||||||
|
|
||||||
public bool EnforceExpiration { get; set; }
|
public bool EnforcePasswordExpiration { get; set; }
|
||||||
|
|
||||||
public bool WindowsAuthSupported { get; set; }
|
|
||||||
|
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
@@ -56,5 +61,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
|||||||
public string DefaultLanguage { get; set; }
|
public string DefaultLanguage { get; set; }
|
||||||
|
|
||||||
public string DefaultDatabase { get; set; }
|
public string DefaultDatabase { get; set; }
|
||||||
|
|
||||||
|
public string[] ServerRoles {get; set;}
|
||||||
|
|
||||||
|
public ServerLoginDatabaseUserMapping[] UserMapping;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
|
||||||
using Microsoft.SqlTools.Utility;
|
using Microsoft.SqlTools.Utility;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
||||||
@@ -16,20 +15,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class CreateLoginParams : GeneralRequestDetails
|
public class CreateLoginParams : GeneralRequestDetails
|
||||||
{
|
{
|
||||||
public string OwnerUri { get; set; }
|
public string ContextId { get; set; }
|
||||||
|
|
||||||
public LoginInfo Login { get; set; }
|
public LoginInfo Login { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create Login result
|
|
||||||
/// </summary>
|
|
||||||
public class CreateLoginResult : ResultStatus
|
|
||||||
{
|
|
||||||
public LoginInfo Login { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create Login request type
|
/// Create Login request type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -39,8 +29,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
|||||||
/// Request definition
|
/// Request definition
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly
|
public static readonly
|
||||||
RequestType<CreateLoginParams, CreateLoginResult> Type =
|
RequestType<CreateLoginParams, object> Type =
|
||||||
RequestType<CreateLoginParams, CreateLoginResult>.Create("security/createlogin");
|
RequestType<CreateLoginParams, object>.Create("objectManagement/createLogin");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -48,9 +38,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DeleteLoginParams : GeneralRequestDetails
|
public class DeleteLoginParams : GeneralRequestDetails
|
||||||
{
|
{
|
||||||
public string OwnerUri { get; set; }
|
public string ConnectionUri { get; set; }
|
||||||
|
|
||||||
public string LoginName { get; set; }
|
public string Name { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -62,7 +52,78 @@ namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
|||||||
/// Request definition
|
/// Request definition
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly
|
public static readonly
|
||||||
RequestType<DeleteLoginParams, ResultStatus> Type =
|
RequestType<DeleteLoginParams, object> Type =
|
||||||
RequestType<DeleteLoginParams, ResultStatus>.Create("security/deletelogin");
|
RequestType<DeleteLoginParams, object>.Create("objectManagement/deleteLogin");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update Login params
|
||||||
|
/// </summary>
|
||||||
|
public class UpdateLoginParams : GeneralRequestDetails
|
||||||
|
{
|
||||||
|
public string ContextId { get; set; }
|
||||||
|
|
||||||
|
public LoginInfo Login { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update Login request type
|
||||||
|
/// </summary>
|
||||||
|
public class UpdateLoginRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Request definition
|
||||||
|
/// </summary>
|
||||||
|
public static readonly
|
||||||
|
RequestType<UpdateLoginParams, object> Type =
|
||||||
|
RequestType<UpdateLoginParams, object>.Create("objectManagement/updateLogin");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update Login params
|
||||||
|
/// </summary>
|
||||||
|
public class DisposeLoginViewRequestParams : GeneralRequestDetails
|
||||||
|
{
|
||||||
|
public string ContextId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update Login request type
|
||||||
|
/// </summary>
|
||||||
|
public class DisposeLoginViewRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Request definition
|
||||||
|
/// </summary>
|
||||||
|
public static readonly
|
||||||
|
RequestType<DisposeLoginViewRequestParams, object> Type =
|
||||||
|
RequestType<DisposeLoginViewRequestParams, object>.Create("objectManagement/disposeLoginView");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize Login View Request params
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
public class InitializeLoginViewRequestParams : GeneralRequestDetails
|
||||||
|
{
|
||||||
|
public string ConnectionUri { get; set; }
|
||||||
|
public string ContextId { get; set; }
|
||||||
|
public bool IsNewObject { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize Login View request type
|
||||||
|
/// </summary>
|
||||||
|
public class InitializeLoginViewRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Request definition
|
||||||
|
/// </summary>
|
||||||
|
public static readonly
|
||||||
|
RequestType<InitializeLoginViewRequestParams, LoginViewInfo> Type =
|
||||||
|
RequestType<InitializeLoginViewRequestParams, LoginViewInfo>.Create("objectManagement/initializeLoginView");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
||||||
|
{
|
||||||
|
public class LoginViewInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
public LoginInfo ObjectInfo { get; set; }
|
||||||
|
public bool SupportWindowsAuthentication { get; set; }
|
||||||
|
public bool SupportAADAuthentication { get; set; }
|
||||||
|
public bool SupportSQLAuthentication { get; set; }
|
||||||
|
public bool CanEditLockedOutState { get; set; }
|
||||||
|
public string[] Databases;
|
||||||
|
public string[] Languages;
|
||||||
|
public string[] ServerRoles;
|
||||||
|
public bool SupportAdvancedPasswordOptions;
|
||||||
|
public bool SupportAdvancedOptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
|
||||||
@@ -560,6 +561,50 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
|
|
||||||
private bool initialized;
|
private bool initialized;
|
||||||
|
|
||||||
|
// query to list all Sql and AAD logins with their role membership, ref: https://learn.microsoft.com/en-us/azure/azure-sql/database/security-server-roles?view=azuresql
|
||||||
|
// this is a temporary workaround for SMO not supporting server role population for Azure SQL
|
||||||
|
private static string AZURE_SERVER_ROLE_MEMBERSHIP_QUERY =
|
||||||
|
@"SELECT
|
||||||
|
member.principal_id AS MemberPrincipalID
|
||||||
|
, member.name AS MemberPrincipalName
|
||||||
|
, roles.principal_id AS RolePrincipalID
|
||||||
|
, roles.name AS RolePrincipalName
|
||||||
|
FROM sys.server_role_members AS server_role_members
|
||||||
|
INNER JOIN sys.server_principals AS roles
|
||||||
|
ON server_role_members.role_principal_id = roles.principal_id
|
||||||
|
INNER JOIN sys.server_principals AS member
|
||||||
|
ON server_role_members.member_principal_id = member.principal_id
|
||||||
|
LEFT OUTER JOIN sys.sql_logins AS sql_logins
|
||||||
|
ON server_role_members.member_principal_id = sql_logins.principal_id
|
||||||
|
WHERE member.principal_id NOT IN (-- prevent SQL Logins from interfering with resultset
|
||||||
|
SELECT principal_id FROM sys.sql_logins AS sql_logins
|
||||||
|
WHERE member.principal_id = sql_logins.principal_id)
|
||||||
|
|
||||||
|
UNION
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
sql_logins.principal_id AS MemberPrincipalID
|
||||||
|
, sql_logins.name AS MemberPrincipalName
|
||||||
|
, roles.principal_id AS RolePrincipalID
|
||||||
|
, roles.name AS RolePrincipalName
|
||||||
|
FROM sys.server_role_members AS server_role_members
|
||||||
|
INNER JOIN sys.server_principals AS roles
|
||||||
|
ON server_role_members.role_principal_id = roles.principal_id
|
||||||
|
INNER JOIN sys.sql_logins AS sql_logins
|
||||||
|
ON server_role_members.member_principal_id = sql_logins.principal_id
|
||||||
|
";
|
||||||
|
|
||||||
|
private static string[] AZURE_SERVER_ROLES =
|
||||||
|
{
|
||||||
|
"##MS_DatabaseConnector##",
|
||||||
|
"##MS_DatabaseManager##",
|
||||||
|
"##MS_DefinitionReader##",
|
||||||
|
"##MS_LoginManager##",
|
||||||
|
"##MS_SecurityDefinitionReader##",
|
||||||
|
"##MS_ServerStateReader##",
|
||||||
|
"##MS_ServerStateManager##"
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Simple description, isMember pair - used as the value in the serverRoles map
|
/// Simple description, isMember pair - used as the value in the serverRoles map
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -688,7 +733,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
|
|
||||||
if (0 != String.Compare(serverRoleName, "public", StringComparison.Ordinal))
|
if (0 != String.Compare(serverRoleName, "public", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
((ServerRoleInfo) serverRoles[serverRoleName]).isMember = isMember;
|
var roleInfo = ((ServerRoleInfo) serverRoles[serverRoleName]);
|
||||||
|
roleInfo.isMember = isMember;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,6 +778,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
serverRoles.Clear();
|
serverRoles.Clear();
|
||||||
|
|
||||||
|
if (server.DatabaseEngineType == DatabaseEngineType.SqlAzureDatabase)
|
||||||
|
{
|
||||||
|
PopulateServerRolesForAzure();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (ServerRole role in server.Roles)
|
foreach (ServerRole role in server.Roles)
|
||||||
@@ -758,6 +810,52 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PopulateServerRolesForAzure()
|
||||||
|
{
|
||||||
|
Dictionary<string, HashSet<string>> roleToMembership = new Dictionary<string, HashSet<string>>();
|
||||||
|
DataSet dataset = server.ExecutionManager.ConnectionContext.ExecuteWithResults(AZURE_SERVER_ROLE_MEMBERSHIP_QUERY);
|
||||||
|
|
||||||
|
if (dataset != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (int i = 0; i < dataset.Tables[0].Rows.Count; i++)
|
||||||
|
{
|
||||||
|
string login = dataset.Tables[0].Rows[i][1].ToString();
|
||||||
|
string role = dataset.Tables[0].Rows[i][3].ToString();
|
||||||
|
|
||||||
|
if (!roleToMembership.ContainsKey(role))
|
||||||
|
{
|
||||||
|
roleToMembership.Add(role, new HashSet<string>());
|
||||||
|
}
|
||||||
|
HashSet<string> members;
|
||||||
|
roleToMembership.TryGetValue(role, out members);
|
||||||
|
|
||||||
|
if (members != null)
|
||||||
|
{
|
||||||
|
members.Add(login);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string role in AZURE_SERVER_ROLES)
|
||||||
|
{
|
||||||
|
bool isRoleMember = false;
|
||||||
|
|
||||||
|
if (this.loginExists)
|
||||||
|
{
|
||||||
|
HashSet<string> members;
|
||||||
|
roleToMembership.TryGetValue(role, out members);
|
||||||
|
|
||||||
|
if (members != null && members.Contains(this.loginName))
|
||||||
|
{
|
||||||
|
isRoleMember = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string roleDescription = String.Empty; // role.Description;
|
||||||
|
this.serverRoles.Add(role, new ServerRoleInfo(roleDescription, isRoleMember));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -816,6 +914,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
private Microsoft.SqlServer.Management.Smo.Server server;
|
private Microsoft.SqlServer.Management.Smo.Server server;
|
||||||
private static string defaultLanguageDisplay;
|
private static string defaultLanguageDisplay;
|
||||||
private bool windowsAuthSupported = true;
|
private bool windowsAuthSupported = true;
|
||||||
|
private bool aADAuthSupported = false;
|
||||||
|
|
||||||
private StringCollection credentials = null;
|
private StringCollection credentials = null;
|
||||||
#endregion
|
#endregion
|
||||||
@@ -953,7 +1052,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (this.server.DatabaseEngineEdition == DatabaseEngineEdition.SqlManagedInstance)
|
if (this.server.ServerType == DatabaseEngineType.SqlAzureDatabase)
|
||||||
{
|
{
|
||||||
this.windowsAuthSupported = false;
|
this.windowsAuthSupported = false;
|
||||||
}
|
}
|
||||||
@@ -962,6 +1061,19 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AADAuthSupported
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.server.ServerType == DatabaseEngineType.SqlAzureDatabase)
|
||||||
|
{
|
||||||
|
this.aADAuthSupported = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.aADAuthSupported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string DefaultLanguageDisplay
|
public static string DefaultLanguageDisplay
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -1344,7 +1456,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
|
|
||||||
bool useSqlAuthentication = (login.LoginType == SqlServer.Management.Smo.LoginType.SqlLogin);
|
bool useSqlAuthentication = (login.LoginType == SqlServer.Management.Smo.LoginType.SqlLogin);
|
||||||
|
|
||||||
this.windowsGrantAccess = !login.DenyWindowsLogin;
|
this.windowsGrantAccess = this.server.ServerType != DatabaseEngineType.SqlAzureDatabase ? !login.DenyWindowsLogin : false;
|
||||||
|
|
||||||
this.sqlPassword = useSqlAuthentication ? LoginPrototype.fakePassword : string.Empty;
|
this.sqlPassword = useSqlAuthentication ? LoginPrototype.fakePassword : string.Empty;
|
||||||
this.sqlPasswordConfirm = useSqlAuthentication ? LoginPrototype.fakePassword : string.Empty;
|
this.sqlPasswordConfirm = useSqlAuthentication ? LoginPrototype.fakePassword : string.Empty;
|
||||||
@@ -1365,7 +1477,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
|
|
||||||
if (isYukon)
|
if (isYukon)
|
||||||
{
|
{
|
||||||
if (login.LoginType == SqlServer.Management.Smo.LoginType.SqlLogin)
|
if (login.LoginType == SqlServer.Management.Smo.LoginType.SqlLogin && this.server.ServerType != DatabaseEngineType.SqlAzureDatabase)
|
||||||
{
|
{
|
||||||
// these properties make sense only for Yukon+ with SQL Authentication
|
// these properties make sense only for Yukon+ with SQL Authentication
|
||||||
this.mustChange = login.MustChangePassword;
|
this.mustChange = login.MustChangePassword;
|
||||||
@@ -1400,7 +1512,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
{
|
{
|
||||||
this.credentials.Add(login.Credential);
|
this.credentials.Add(login.Credential);
|
||||||
}
|
}
|
||||||
else if (server.Information.Version.Major >= 10)
|
else if (server.Information.Version.Major >= 10 && server.ServerType != DatabaseEngineType.SqlAzureDatabase)
|
||||||
{
|
{
|
||||||
this.credentials.Clear();
|
this.credentials.Clear();
|
||||||
foreach (string str in login.EnumCredentials())
|
foreach (string str in login.EnumCredentials())
|
||||||
@@ -1521,6 +1633,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AADAuthSupported
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.currentState.AADAuthSupported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the Windows account is granted server access (e.g. true == grant access, false == deny access)
|
/// Whether the Windows account is granted server access (e.g. true == grant access, false == deny access)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1963,12 +2083,31 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
this.originalState = (LoginPrototypeData) this.currentState.Clone();
|
this.originalState = (LoginPrototypeData) this.currentState.Clone();
|
||||||
this.comparer = new SqlCollationSensitiveStringComparer(server.Information.Collation);
|
this.comparer = new SqlCollationSensitiveStringComparer(server.Information.Collation);
|
||||||
|
|
||||||
this.LoginName = login.LoginName;
|
this.LoginName = login.Name;
|
||||||
this.SqlPassword = login.Password;
|
this.SqlPassword = login.Password;
|
||||||
this.OldPassword = login.OldPassword;
|
this.OldPassword = login.OldPassword;
|
||||||
this.LoginType = SqlServer.Management.Smo.LoginType.SqlLogin;
|
this.LoginType = GetLoginType(login);
|
||||||
this.DefaultLanguage = login.DefaultLanguage;
|
this.DefaultLanguage = login.DefaultLanguage;
|
||||||
this.DefaultDatabase = login.DefaultDatabase;
|
this.DefaultDatabase = login.DefaultDatabase;
|
||||||
|
this.EnforcePolicy = login.EnforcePasswordPolicy;
|
||||||
|
this.EnforceExpiration = login.EnforcePasswordPolicy ? login.EnforcePasswordExpiration : false;
|
||||||
|
this.IsLockedOut = login.IsLockedOut;
|
||||||
|
this.IsDisabled = !login.IsEnabled;
|
||||||
|
this.MustChange = login.EnforcePasswordPolicy ? login.MustChangePassword : false;
|
||||||
|
this.WindowsGrantAccess = login.ConnectPermission;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoginType GetLoginType(LoginInfo loginInfo)
|
||||||
|
{
|
||||||
|
switch (loginInfo.AuthenticationType)
|
||||||
|
{
|
||||||
|
case LoginAuthenticationType.AAD:
|
||||||
|
return SqlServer.Management.Smo.LoginType.ExternalUser;
|
||||||
|
case LoginAuthenticationType.Windows:
|
||||||
|
return SqlServer.Management.Smo.LoginType.WindowsUser; // TODO handle windows group
|
||||||
|
default:
|
||||||
|
return SqlServer.Management.Smo.LoginType.SqlLogin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -2030,7 +2169,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
changesMade = true;
|
changesMade = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (9 <= server.Information.Version.Major)
|
if (9 <= server.Information.Version.Major && server.ServerType != DatabaseEngineType.SqlAzureDatabase)
|
||||||
{
|
{
|
||||||
if (!this.Exists || (this.currentState.CertificateName != this.originalState.CertificateName))
|
if (!this.Exists || (this.currentState.CertificateName != this.originalState.CertificateName))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -93,7 +93,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
|
|
||||||
// Login request handlers
|
// Login request handlers
|
||||||
this.ServiceHost.SetRequestHandler(CreateLoginRequest.Type, HandleCreateLoginRequest, true);
|
this.ServiceHost.SetRequestHandler(CreateLoginRequest.Type, HandleCreateLoginRequest, true);
|
||||||
|
this.ServiceHost.SetRequestHandler(UpdateLoginRequest.Type, HandleUpdateLoginRequest, true);
|
||||||
this.ServiceHost.SetRequestHandler(DeleteLoginRequest.Type, HandleDeleteLoginRequest, true);
|
this.ServiceHost.SetRequestHandler(DeleteLoginRequest.Type, HandleDeleteLoginRequest, true);
|
||||||
|
this.ServiceHost.SetRequestHandler(InitializeLoginViewRequest.Type, HandleInitializeLoginViewRequest, true);
|
||||||
|
this.ServiceHost.SetRequestHandler(DisposeLoginViewRequest.Type, HandleDisposeLoginViewRequest, true);
|
||||||
|
|
||||||
// User request handlers
|
// User request handlers
|
||||||
this.ServiceHost.SetRequestHandler(InitializeUserViewRequest.Type, HandleInitializeUserViewRequest, true);
|
this.ServiceHost.SetRequestHandler(InitializeUserViewRequest.Type, HandleInitializeUserViewRequest, true);
|
||||||
@@ -107,14 +110,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handle request to create a login
|
/// Handle request to create a login
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal async Task HandleCreateLoginRequest(CreateLoginParams parameters, RequestContext<CreateLoginResult> requestContext)
|
internal async Task HandleCreateLoginRequest(CreateLoginParams parameters, RequestContext<object> requestContext)
|
||||||
{
|
{
|
||||||
ConnectionInfo connInfo;
|
ConnectionInfo connInfo;
|
||||||
ConnectionServiceInstance.TryFindConnection(parameters.OwnerUri, out connInfo);
|
string ownerUri;
|
||||||
// if (connInfo == null)
|
contextIdToConnectionUriMap.TryGetValue(parameters.ContextId, out ownerUri);
|
||||||
// {
|
ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo);
|
||||||
// // raise an error
|
|
||||||
// }
|
if (connInfo == null)
|
||||||
|
{
|
||||||
|
// raise error here
|
||||||
|
}
|
||||||
|
|
||||||
CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true);
|
CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true);
|
||||||
LoginPrototype prototype = new LoginPrototype(dataContainer.Server, parameters.Login);
|
LoginPrototype prototype = new LoginPrototype(dataContainer.Server, parameters.Login);
|
||||||
@@ -139,28 +145,34 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
|
|
||||||
prototype.ApplyGeneralChanges(dataContainer.Server);
|
prototype.ApplyGeneralChanges(dataContainer.Server);
|
||||||
|
|
||||||
await requestContext.SendResult(new CreateLoginResult()
|
// TODO move this to LoginData
|
||||||
|
// TODO support role assignment for Azure
|
||||||
|
LoginPrototype newPrototype = new LoginPrototype(dataContainer.Server, dataContainer.Server.Logins[parameters.Login.Name]);
|
||||||
|
var _ =newPrototype.ServerRoles.ServerRoleNames;
|
||||||
|
|
||||||
|
foreach (string role in parameters.Login.ServerRoles)
|
||||||
{
|
{
|
||||||
Login = parameters.Login,
|
newPrototype.ServerRoles.SetMember(role, true);
|
||||||
Success = true,
|
}
|
||||||
ErrorMessage = string.Empty
|
|
||||||
});
|
newPrototype.ApplyServerRoleChanges(dataContainer.Server);
|
||||||
|
await requestContext.SendResult(new object());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handle request to delete a credential
|
/// Handle request to delete a credential
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal async Task HandleDeleteLoginRequest(DeleteLoginParams parameters, RequestContext<ResultStatus> requestContext)
|
internal async Task HandleDeleteLoginRequest(DeleteLoginParams parameters, RequestContext<object> requestContext)
|
||||||
{
|
{
|
||||||
ConnectionInfo connInfo;
|
ConnectionInfo connInfo;
|
||||||
ConnectionServiceInstance.TryFindConnection(parameters.OwnerUri, out connInfo);
|
ConnectionServiceInstance.TryFindConnection(parameters.ConnectionUri, out connInfo);
|
||||||
// if (connInfo == null)
|
// if (connInfo == null)
|
||||||
// {
|
// {
|
||||||
// // raise an error
|
// // raise an error
|
||||||
// }
|
// }
|
||||||
|
|
||||||
CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true);
|
CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true);
|
||||||
Login login = dataContainer.Server?.Logins[parameters.LoginName];
|
Login login = dataContainer.Server?.Logins[parameters.Name];
|
||||||
|
|
||||||
dataContainer.SqlDialogSubject = login;
|
dataContainer.SqlDialogSubject = login;
|
||||||
DoDropObject(dataContainer);
|
DoDropObject(dataContainer);
|
||||||
@@ -172,6 +184,152 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal async Task HandleUpdateLoginRequest(UpdateLoginParams parameters, RequestContext<object> requestContext)
|
||||||
|
{
|
||||||
|
ConnectionInfo connInfo;
|
||||||
|
string ownerUri;
|
||||||
|
contextIdToConnectionUriMap.TryGetValue(parameters.ContextId, out ownerUri);
|
||||||
|
ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo);
|
||||||
|
if (connInfo == null)
|
||||||
|
{
|
||||||
|
// raise error here
|
||||||
|
}
|
||||||
|
|
||||||
|
CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true);
|
||||||
|
LoginPrototype prototype = new LoginPrototype(dataContainer.Server, dataContainer.Server.Logins[parameters.Login.Name]);
|
||||||
|
|
||||||
|
var login = parameters.Login;
|
||||||
|
prototype.SqlPassword = login.Password;
|
||||||
|
prototype.DefaultLanguage = login.DefaultLanguage;
|
||||||
|
prototype.DefaultDatabase = login.DefaultDatabase;
|
||||||
|
prototype.EnforcePolicy = login.EnforcePasswordPolicy;
|
||||||
|
prototype.EnforceExpiration = login.EnforcePasswordPolicy ? login.EnforcePasswordExpiration : false;
|
||||||
|
prototype.IsLockedOut = login.IsLockedOut;
|
||||||
|
prototype.IsDisabled = !login.IsEnabled;
|
||||||
|
prototype.MustChange = login.EnforcePasswordPolicy ? login.MustChangePassword : false;
|
||||||
|
prototype.WindowsGrantAccess = login.ConnectPermission;
|
||||||
|
|
||||||
|
if (prototype.LoginType == SqlServer.Management.Smo.LoginType.SqlLogin)
|
||||||
|
{
|
||||||
|
// check that there is a password
|
||||||
|
// this check is made if policy enforcement is off
|
||||||
|
// with policy turned on we do not display this message, instead we let server
|
||||||
|
// return the error associated with null password (coming from policy) - see bug 124377
|
||||||
|
if (prototype.SqlPassword.Length == 0 && prototype.EnforcePolicy == false)
|
||||||
|
{
|
||||||
|
// raise error here
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that password and confirm password controls' text matches
|
||||||
|
if (0 != String.Compare(prototype.SqlPassword, prototype.SqlPasswordConfirm, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
// raise error here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = prototype.ServerRoles.ServerRoleNames;
|
||||||
|
foreach (string role in login.ServerRoles)
|
||||||
|
{
|
||||||
|
prototype.ServerRoles.SetMember(role, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
prototype.ApplyGeneralChanges(dataContainer.Server);
|
||||||
|
prototype.ApplyServerRoleChanges(dataContainer.Server);
|
||||||
|
prototype.ApplyDatabaseRoleChanges(dataContainer.Server);
|
||||||
|
await requestContext.SendResult(new object());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task HandleInitializeLoginViewRequest(InitializeLoginViewRequestParams parameters, RequestContext<LoginViewInfo> requestContext)
|
||||||
|
{
|
||||||
|
contextIdToConnectionUriMap.Add(parameters.ContextId, parameters.ConnectionUri);
|
||||||
|
ConnectionInfo connInfo;
|
||||||
|
ConnectionServiceInstance.TryFindConnection(parameters.ConnectionUri, out connInfo);
|
||||||
|
if (connInfo == null)
|
||||||
|
{
|
||||||
|
// raise an error
|
||||||
|
}
|
||||||
|
CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true);
|
||||||
|
LoginViewInfo loginViewInfo = new LoginViewInfo();
|
||||||
|
|
||||||
|
string[] databases = new string[dataContainer.Server.Databases.Count];
|
||||||
|
for (int i = 0; i < dataContainer.Server.Databases.Count; i++)
|
||||||
|
{
|
||||||
|
databases[i] = dataContainer.Server.Databases[i].Name;
|
||||||
|
}
|
||||||
|
string[] languages = new string[dataContainer.Server.Languages.Count];
|
||||||
|
for (int i = 0; i < dataContainer.Server.Languages.Count; i++)
|
||||||
|
{
|
||||||
|
languages[i] = dataContainer.Server.Languages[i].Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginPrototype prototype = parameters.IsNewObject
|
||||||
|
? new LoginPrototype(dataContainer.Server)
|
||||||
|
: new LoginPrototype(dataContainer.Server, dataContainer.Server.Logins[parameters.Name]);
|
||||||
|
|
||||||
|
List<string> loginServerRoles = new List<string>();
|
||||||
|
foreach(string role in prototype.ServerRoles.ServerRoleNames)
|
||||||
|
{
|
||||||
|
if (prototype.ServerRoles.IsMember(role))
|
||||||
|
{
|
||||||
|
loginServerRoles.Add(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginInfo loginInfo = new LoginInfo()
|
||||||
|
{
|
||||||
|
Name = prototype.LoginName,
|
||||||
|
Password = prototype.SqlPassword,
|
||||||
|
OldPassword = prototype.OldPassword,
|
||||||
|
AuthenticationType = LoginTypeToAuthenticationType(prototype.LoginType),
|
||||||
|
EnforcePasswordExpiration = prototype.EnforceExpiration,
|
||||||
|
EnforcePasswordPolicy = prototype.EnforcePolicy,
|
||||||
|
MustChangePassword = prototype.MustChange,
|
||||||
|
DefaultDatabase = prototype.DefaultDatabase,
|
||||||
|
DefaultLanguage = prototype.DefaultDatabase,
|
||||||
|
ServerRoles = loginServerRoles.ToArray(),
|
||||||
|
ConnectPermission = prototype.WindowsGrantAccess,
|
||||||
|
IsEnabled = !prototype.IsDisabled,
|
||||||
|
IsLockedOut = prototype.IsLockedOut,
|
||||||
|
UserMapping = new ServerLoginDatabaseUserMapping[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
await requestContext.SendResult(new LoginViewInfo()
|
||||||
|
{
|
||||||
|
ObjectInfo = loginInfo,
|
||||||
|
SupportWindowsAuthentication = prototype.WindowsAuthSupported,
|
||||||
|
SupportAADAuthentication = prototype.AADAuthSupported,
|
||||||
|
SupportSQLAuthentication = true, // SQL Auth support for login, not necessarily mean SQL Auth support for CONNECT etc.
|
||||||
|
CanEditLockedOutState = true,
|
||||||
|
Databases = databases,
|
||||||
|
Languages = languages,
|
||||||
|
ServerRoles = prototype.ServerRoles.ServerRoleNames,
|
||||||
|
SupportAdvancedPasswordOptions = dataContainer.Server.DatabaseEngineType == DatabaseEngineType.Standalone || dataContainer.Server.DatabaseEngineEdition == DatabaseEngineEdition.SqlDataWarehouse,
|
||||||
|
SupportAdvancedOptions = dataContainer.Server.DatabaseEngineType == DatabaseEngineType.Standalone || dataContainer.Server.DatabaseEngineEdition == DatabaseEngineEdition.SqlManagedInstance
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoginAuthenticationType LoginTypeToAuthenticationType(LoginType loginType)
|
||||||
|
{
|
||||||
|
switch (loginType)
|
||||||
|
{
|
||||||
|
case LoginType.WindowsUser:
|
||||||
|
case LoginType.WindowsGroup:
|
||||||
|
return LoginAuthenticationType.Windows;
|
||||||
|
case LoginType.SqlLogin:
|
||||||
|
return LoginAuthenticationType.Sql;
|
||||||
|
case LoginType.ExternalUser:
|
||||||
|
case LoginType.ExternalGroup:
|
||||||
|
return LoginAuthenticationType.AAD;
|
||||||
|
default:
|
||||||
|
return LoginAuthenticationType.Others;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task HandleDisposeLoginViewRequest(DisposeLoginViewRequestParams parameters, RequestContext<object> requestContext)
|
||||||
|
{
|
||||||
|
contextIdToConnectionUriMap.Remove(parameters.ContextId);
|
||||||
|
await requestContext.SendResult(new object());
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "User Handlers"
|
#region "User Handlers"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
|
|||||||
using Microsoft.SqlTools.ServiceLayer.Security;
|
using Microsoft.SqlTools.ServiceLayer.Security;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Security.Contracts;
|
using Microsoft.SqlTools.ServiceLayer.Security.Contracts;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
// using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security
|
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security
|
||||||
@@ -31,40 +31,46 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security
|
|||||||
{
|
{
|
||||||
// setup
|
// setup
|
||||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
||||||
|
var contextId = System.Guid.NewGuid().ToString();
|
||||||
|
|
||||||
|
var initializeLoginViewRequestParams = new InitializeLoginViewRequestParams
|
||||||
|
{
|
||||||
|
ConnectionUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||||
|
ContextId = contextId,
|
||||||
|
IsNewObject = true
|
||||||
|
};
|
||||||
|
|
||||||
var loginParams = new CreateLoginParams
|
var loginParams = new CreateLoginParams
|
||||||
{
|
{
|
||||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
ContextId = contextId,
|
||||||
Login = SecurityTestUtils.GetTestLoginInfo()
|
Login = SecurityTestUtils.GetTestLoginInfo()
|
||||||
};
|
};
|
||||||
|
|
||||||
var createContext = new Mock<RequestContext<CreateLoginResult>>();
|
var createLoginContext = new Mock<RequestContext<object>>();
|
||||||
createContext.Setup(x => x.SendResult(It.IsAny<CreateLoginResult>()))
|
createLoginContext.Setup(x => x.SendResult(It.IsAny<object>()))
|
||||||
.Returns(Task.FromResult(new object()));
|
.Returns(Task.FromResult(new object()));
|
||||||
|
var initializeLoginViewContext = new Mock<RequestContext<LoginViewInfo>>();
|
||||||
|
initializeLoginViewContext.Setup(x => x.SendResult(It.IsAny<LoginViewInfo>()))
|
||||||
|
.Returns(Task.FromResult(new LoginViewInfo()));
|
||||||
|
|
||||||
// call the create login method
|
// call the create login method
|
||||||
SecurityService service = new SecurityService();
|
SecurityService service = new SecurityService();
|
||||||
await service.HandleCreateLoginRequest(loginParams, createContext.Object);
|
await service.HandleInitializeLoginViewRequest(initializeLoginViewRequestParams, initializeLoginViewContext.Object);
|
||||||
|
await service.HandleCreateLoginRequest(loginParams, createLoginContext.Object);
|
||||||
// verify the result
|
|
||||||
createContext.Verify(x => x.SendResult(It.Is<CreateLoginResult>
|
|
||||||
(p => p.Success && p.Login.LoginName != string.Empty)));
|
|
||||||
|
|
||||||
// cleanup created login
|
// cleanup created login
|
||||||
var deleteParams = new DeleteLoginParams
|
var deleteParams = new DeleteLoginParams
|
||||||
{
|
{
|
||||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
ConnectionUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||||
LoginName = loginParams.Login.LoginName
|
Name = loginParams.Login.Name
|
||||||
};
|
};
|
||||||
|
|
||||||
var deleteContext = new Mock<RequestContext<ResultStatus>>();
|
var deleteContext = new Mock<RequestContext<object>>();
|
||||||
deleteContext.Setup(x => x.SendResult(It.IsAny<ResultStatus>()))
|
deleteContext.Setup(x => x.SendResult(It.IsAny<object>()))
|
||||||
.Returns(Task.FromResult(new object()));
|
.Returns(Task.FromResult(new object()));
|
||||||
|
|
||||||
// call the create login method
|
// call the create login method
|
||||||
await service.HandleDeleteLoginRequest(deleteParams, deleteContext.Object);
|
await service.HandleDeleteLoginRequest(deleteParams, deleteContext.Object);
|
||||||
|
|
||||||
// verify the result
|
|
||||||
deleteContext.Verify(x => x.SendResult(It.Is<ResultStatus>(p => p.Success)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,17 +29,14 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security
|
|||||||
{
|
{
|
||||||
return new LoginInfo()
|
return new LoginInfo()
|
||||||
{
|
{
|
||||||
LoginName = "TestLoginName_" + new Random().NextInt64(10000000,90000000).ToString(),
|
Name = "TestLoginName_" + new Random().NextInt64(10000000,90000000).ToString(),
|
||||||
LoginType= LoginType.Sql,
|
AuthenticationType= LoginAuthenticationType.Sql,
|
||||||
CertificateName = "Test Cert",
|
|
||||||
AsymmetricKeyName = "Asymmetric Test Cert",
|
|
||||||
WindowsGrantAccess = true,
|
WindowsGrantAccess = true,
|
||||||
MustChange = false,
|
MustChangePassword = false,
|
||||||
IsDisabled = false,
|
IsEnabled = false,
|
||||||
IsLockedOut = false,
|
IsLockedOut = false,
|
||||||
EnforcePolicy = false,
|
EnforcePasswordPolicy = false,
|
||||||
EnforceExpiration = false,
|
EnforcePasswordExpiration = false,
|
||||||
WindowsAuthSupported = false,
|
|
||||||
Password = "placeholder",
|
Password = "placeholder",
|
||||||
OldPassword = "placeholder",
|
OldPassword = "placeholder",
|
||||||
DefaultLanguage = "us_english",
|
DefaultLanguage = "us_english",
|
||||||
|
|||||||
@@ -28,29 +28,37 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security
|
|||||||
{
|
{
|
||||||
// setup
|
// setup
|
||||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
||||||
|
var contextId = System.Guid.NewGuid().ToString();
|
||||||
|
|
||||||
|
var initializeLoginViewRequestParams = new InitializeLoginViewRequestParams
|
||||||
|
{
|
||||||
|
ConnectionUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||||
|
ContextId = contextId,
|
||||||
|
IsNewObject = true
|
||||||
|
};
|
||||||
|
|
||||||
var loginParams = new CreateLoginParams
|
var loginParams = new CreateLoginParams
|
||||||
{
|
{
|
||||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
ContextId = contextId,
|
||||||
Login = SecurityTestUtils.GetTestLoginInfo()
|
Login = SecurityTestUtils.GetTestLoginInfo()
|
||||||
};
|
};
|
||||||
|
|
||||||
var createLoginContext = new Mock<RequestContext<CreateLoginResult>>();
|
var createLoginContext = new Mock<RequestContext<object>>();
|
||||||
createLoginContext.Setup(x => x.SendResult(It.IsAny<CreateLoginResult>()))
|
createLoginContext.Setup(x => x.SendResult(It.IsAny<object>()))
|
||||||
.Returns(Task.FromResult(new object()));
|
.Returns(Task.FromResult(new object()));
|
||||||
|
var initializeLoginViewContext = new Mock<RequestContext<LoginViewInfo>>();
|
||||||
|
initializeLoginViewContext.Setup(x => x.SendResult(It.IsAny<LoginViewInfo>()))
|
||||||
|
.Returns(Task.FromResult(new LoginViewInfo()));
|
||||||
|
|
||||||
// call the create login method
|
// call the create login method
|
||||||
SecurityService service = new SecurityService();
|
SecurityService service = new SecurityService();
|
||||||
|
await service.HandleInitializeLoginViewRequest(initializeLoginViewRequestParams, initializeLoginViewContext.Object);
|
||||||
await service.HandleCreateLoginRequest(loginParams, createLoginContext.Object);
|
await service.HandleCreateLoginRequest(loginParams, createLoginContext.Object);
|
||||||
|
|
||||||
// verify the result
|
|
||||||
createLoginContext.Verify(x => x.SendResult(It.Is<CreateLoginResult>
|
|
||||||
(p => p.Success && p.Login.LoginName != string.Empty)));
|
|
||||||
|
|
||||||
|
|
||||||
var userParams = new CreateUserParams
|
var userParams = new CreateUserParams
|
||||||
{
|
{
|
||||||
ContextId = connectionResult.ConnectionInfo.OwnerUri,
|
ContextId = connectionResult.ConnectionInfo.OwnerUri,
|
||||||
User = SecurityTestUtils.GetTestUserInfo(loginParams.Login.LoginName)
|
User = SecurityTestUtils.GetTestUserInfo(loginParams.Login.Name)
|
||||||
};
|
};
|
||||||
|
|
||||||
var createUserContext = new Mock<RequestContext<CreateUserResult>>();
|
var createUserContext = new Mock<RequestContext<CreateUserResult>>();
|
||||||
|
|||||||
Reference in New Issue
Block a user