mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-17 02:51:45 -05:00
Support scripting for Users (#2002)
* WIP 1 * WIP2 * Fix merge break * Support alter existing object
This commit is contained in:
@@ -109,4 +109,27 @@ namespace Microsoft.SqlTools.ServiceLayer.Security.Contracts
|
|||||||
RequestType<DisposeUserViewRequestParams, ResultStatus> Type =
|
RequestType<DisposeUserViewRequestParams, ResultStatus> Type =
|
||||||
RequestType<DisposeUserViewRequestParams, ResultStatus>.Create("objectManagement/disposeUserView");
|
RequestType<DisposeUserViewRequestParams, ResultStatus>.Create("objectManagement/disposeUserView");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Script User params
|
||||||
|
/// </summary>
|
||||||
|
public class ScriptUserParams
|
||||||
|
{
|
||||||
|
public string? ContextId { get; set; }
|
||||||
|
|
||||||
|
public UserInfo? User { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Script User request type
|
||||||
|
/// </summary>
|
||||||
|
public class ScriptUserRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Request definition
|
||||||
|
/// </summary>
|
||||||
|
public static readonly
|
||||||
|
RequestType<ScriptUserParams, string> Type =
|
||||||
|
RequestType<ScriptUserParams, string>.Create("objectManagement/scriptUser");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
this.ServiceHost.SetRequestHandler(InitializeUserViewRequest.Type, this.userServiceHandler.HandleInitializeUserViewRequest, true);
|
this.ServiceHost.SetRequestHandler(InitializeUserViewRequest.Type, this.userServiceHandler.HandleInitializeUserViewRequest, true);
|
||||||
this.ServiceHost.SetRequestHandler(CreateUserRequest.Type, this.userServiceHandler.HandleCreateUserRequest, true);
|
this.ServiceHost.SetRequestHandler(CreateUserRequest.Type, this.userServiceHandler.HandleCreateUserRequest, true);
|
||||||
this.ServiceHost.SetRequestHandler(UpdateUserRequest.Type, this.userServiceHandler.HandleUpdateUserRequest, true);
|
this.ServiceHost.SetRequestHandler(UpdateUserRequest.Type, this.userServiceHandler.HandleUpdateUserRequest, true);
|
||||||
|
this.ServiceHost.SetRequestHandler(ScriptUserRequest.Type, this.userServiceHandler.HandleScriptUserRequest, true);
|
||||||
this.ServiceHost.SetRequestHandler(DisposeUserViewRequest.Type, this.userServiceHandler.HandleDisposeUserViewRequest, true);
|
this.ServiceHost.SetRequestHandler(DisposeUserViewRequest.Type, this.userServiceHandler.HandleDisposeUserViewRequest, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,12 +24,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
{
|
{
|
||||||
private class UserViewState
|
private class UserViewState
|
||||||
{
|
{
|
||||||
|
public bool IsNewObject { get; set; }
|
||||||
|
|
||||||
public string Database { get; set; }
|
public string Database { get; set; }
|
||||||
|
|
||||||
public UserPrototypeData OriginalUserData { get; set; }
|
public UserPrototypeData OriginalUserData { get; set; }
|
||||||
|
|
||||||
public UserViewState(string database, UserPrototypeData originalUserData)
|
public UserViewState(bool isNewObject, string database, UserPrototypeData originalUserData)
|
||||||
{
|
{
|
||||||
|
this.IsNewObject = isNewObject;
|
||||||
this.Database = database;
|
this.Database = database;
|
||||||
this.OriginalUserData = originalUserData;
|
this.OriginalUserData = originalUserData;
|
||||||
}
|
}
|
||||||
@@ -229,7 +232,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
|
|
||||||
this.contextIdToViewState.Add(
|
this.contextIdToViewState.Add(
|
||||||
parameters.ContextId,
|
parameters.ContextId,
|
||||||
new UserViewState(parameters.Database, currentUserPrototype.CurrentState));
|
new UserViewState(parameters.IsNewObject, parameters.Database, currentUserPrototype.CurrentState));
|
||||||
|
|
||||||
await requestContext.SendResult(userViewInfo);
|
await requestContext.SendResult(userViewInfo);
|
||||||
}
|
}
|
||||||
@@ -252,7 +255,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
throw new ArgumentException("Invalid context ID view state");
|
throw new ArgumentException("Invalid context ID view state");
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple<bool, string> result = ConfigureUser(
|
ConfigureUser(
|
||||||
parameters.ContextId,
|
parameters.ContextId,
|
||||||
parameters.User,
|
parameters.User,
|
||||||
ConfigAction.Create,
|
ConfigAction.Create,
|
||||||
@@ -263,8 +266,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
await requestContext.SendResult(new CreateUserResult()
|
await requestContext.SendResult(new CreateUserResult()
|
||||||
{
|
{
|
||||||
User = parameters.User,
|
User = parameters.User,
|
||||||
Success = result.Item1,
|
Success = true,
|
||||||
ErrorMessage = result.Item2
|
ErrorMessage = string.Empty
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +289,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
throw new ArgumentException("Invalid context ID view state");
|
throw new ArgumentException("Invalid context ID view state");
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple<bool, string> result = ConfigureUser(
|
ConfigureUser(
|
||||||
parameters.ContextId,
|
parameters.ContextId,
|
||||||
parameters.User,
|
parameters.User,
|
||||||
ConfigAction.Update,
|
ConfigAction.Update,
|
||||||
@@ -296,11 +299,42 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
|
|
||||||
await requestContext.SendResult(new ResultStatus()
|
await requestContext.SendResult(new ResultStatus()
|
||||||
{
|
{
|
||||||
Success = result.Item1,
|
Success = true,
|
||||||
ErrorMessage = result.Item2
|
ErrorMessage = string.Empty
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle request to update a user
|
||||||
|
/// </summary>
|
||||||
|
internal async Task HandleScriptUserRequest(ScriptUserParams parameters, RequestContext<string> requestContext)
|
||||||
|
{
|
||||||
|
if (parameters.ContextId == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Invalid context ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
UserViewState viewState;
|
||||||
|
this.contextIdToViewState.TryGetValue(parameters.ContextId, out viewState);
|
||||||
|
|
||||||
|
if (viewState == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Invalid context ID view state");
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: check if it's an existing user
|
||||||
|
|
||||||
|
string sqlScript = ConfigureUser(
|
||||||
|
parameters.ContextId,
|
||||||
|
parameters.User,
|
||||||
|
viewState.IsNewObject ? ConfigAction.Create : ConfigAction.Update,
|
||||||
|
RunType.ScriptToWindow,
|
||||||
|
viewState.Database,
|
||||||
|
viewState.OriginalUserData);
|
||||||
|
|
||||||
|
await requestContext.SendResult(sqlScript);
|
||||||
|
}
|
||||||
|
|
||||||
internal async Task HandleDisposeUserViewRequest(DisposeUserViewRequestParams parameters, RequestContext<ResultStatus> requestContext)
|
internal async Task HandleDisposeUserViewRequest(DisposeUserViewRequestParams parameters, RequestContext<ResultStatus> requestContext)
|
||||||
{
|
{
|
||||||
this.ConnectionServiceInstance.Disconnect(new DisconnectParams()
|
this.ConnectionServiceInstance.Disconnect(new DisconnectParams()
|
||||||
@@ -352,7 +386,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
return CDataContainer.CreateDataContainer(connectionInfoWithConnection, xmlDoc);
|
return CDataContainer.CreateDataContainer(connectionInfoWithConnection, xmlDoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Tuple<bool, string> ConfigureUser(
|
internal string ConfigureUser(
|
||||||
string? ownerUri,
|
string? ownerUri,
|
||||||
UserInfo? user,
|
UserInfo? user,
|
||||||
ConfigAction configAction,
|
ConfigAction configAction,
|
||||||
@@ -367,6 +401,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
throw new ArgumentException("Invalid connection URI '{0}'", ownerUri);
|
throw new ArgumentException("Invalid connection URI '{0}'", ownerUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string sqlScript = string.Empty;
|
||||||
CDataContainer dataContainer = CreateUserDataContainer(connInfo, user, configAction, databaseName);
|
CDataContainer dataContainer = CreateUserDataContainer(connInfo, user, configAction, databaseName);
|
||||||
using (var actions = new UserActions(dataContainer, configAction, user, originalData))
|
using (var actions = new UserActions(dataContainer, configAction, user, originalData))
|
||||||
{
|
{
|
||||||
@@ -376,9 +411,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Security
|
|||||||
{
|
{
|
||||||
throw executionHandler.ExecutionFailureException;
|
throw executionHandler.ExecutionFailureException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (runType == RunType.ScriptToWindow)
|
||||||
|
{
|
||||||
|
sqlScript = executionHandler.ScriptTextFromLastRun;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Tuple<bool, string>(true, string.Empty);
|
return sqlScript;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,7 +165,8 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security
|
|||||||
DatabaseUserType userType,
|
DatabaseUserType userType,
|
||||||
string userName = null,
|
string userName = null,
|
||||||
string loginName = null,
|
string loginName = null,
|
||||||
string databaseName = "master")
|
string databaseName = "master",
|
||||||
|
bool scriptUser = false)
|
||||||
{
|
{
|
||||||
string contextId = System.Guid.NewGuid().ToString();
|
string contextId = System.Guid.NewGuid().ToString();
|
||||||
var initializeViewRequestParams = new InitializeUserViewParams
|
var initializeViewRequestParams = new InitializeUserViewParams
|
||||||
@@ -182,6 +183,25 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security
|
|||||||
|
|
||||||
await service.HandleInitializeUserViewRequest(initializeViewRequestParams, initializeUserViewContext.Object);
|
await service.HandleInitializeUserViewRequest(initializeViewRequestParams, initializeUserViewContext.Object);
|
||||||
|
|
||||||
|
if (scriptUser)
|
||||||
|
{
|
||||||
|
var scriptParams = new ScriptUserParams
|
||||||
|
{
|
||||||
|
ContextId = contextId,
|
||||||
|
User = SecurityTestUtils.GetTestUserInfo(userType, userName, loginName)
|
||||||
|
};
|
||||||
|
|
||||||
|
var scriptUserContext = new Mock<RequestContext<string>>();
|
||||||
|
scriptUserContext.Setup(x => x.SendResult(It.IsAny<string>()))
|
||||||
|
.Returns(Task.FromResult(new object()));
|
||||||
|
|
||||||
|
await service.HandleScriptUserRequest(scriptParams, scriptUserContext.Object);
|
||||||
|
|
||||||
|
// verify the result
|
||||||
|
scriptUserContext.Verify(x => x.SendResult(It.Is<string>
|
||||||
|
(p => p.Contains("CREATE USER"))));
|
||||||
|
}
|
||||||
|
|
||||||
var userParams = new CreateUserParams
|
var userParams = new CreateUserParams
|
||||||
{
|
{
|
||||||
ContextId = contextId,
|
ContextId = contextId,
|
||||||
|
|||||||
@@ -112,5 +112,29 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Security
|
|||||||
await SecurityTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, SecurityTestUtils.GetLoginURN(login.Name));
|
await SecurityTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, SecurityTestUtils.GetLoginURN(login.Name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test the basic Create User method handler
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public async Task TestScriptUserWithLogin()
|
||||||
|
{
|
||||||
|
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
||||||
|
{
|
||||||
|
// setup
|
||||||
|
UserServiceHandlerImpl userService = new UserServiceHandlerImpl();
|
||||||
|
LoginServiceHandlerImpl loginService = new LoginServiceHandlerImpl();
|
||||||
|
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
||||||
|
|
||||||
|
var login = await SecurityTestUtils.CreateLogin(loginService, connectionResult);
|
||||||
|
|
||||||
|
var user = await SecurityTestUtils.CreateUser(userService, connectionResult,
|
||||||
|
DatabaseUserType.WithLogin, null, login.Name, scriptUser: true);
|
||||||
|
|
||||||
|
await SecurityTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, SecurityTestUtils.GetUserURN(connectionResult.ConnectionInfo.ConnectionDetails.DatabaseName, user.Name));
|
||||||
|
|
||||||
|
await SecurityTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, SecurityTestUtils.GetLoginURN(login.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user