// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // using System; using System.Threading.Tasks; using Microsoft.SqlTools.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Hosting; using Microsoft.SqlTools.ServiceLayer.Management; using Microsoft.SqlTools.ServiceLayer.Security.Contracts; namespace Microsoft.SqlTools.ServiceLayer.Security { /// /// Main class for Security Service functionality /// public sealed class SecurityService : IDisposable { private bool disposed; private ConnectionService? connectionService; private UserServiceHandlerImpl userServiceHandler; private LoginServiceHandlerImpl loginServiceHandler; private static readonly Lazy instance = new Lazy(() => new SecurityService()); /// /// Construct a new SecurityService instance with default parameters /// public SecurityService() { userServiceHandler = new UserServiceHandlerImpl(); loginServiceHandler = new LoginServiceHandlerImpl(); } /// /// Gets the singleton instance object /// public static SecurityService Instance { get { return instance.Value; } } /// /// Internal for testing purposes only /// internal ConnectionService ConnectionServiceInstance { get { connectionService ??= ConnectionService.Instance; return connectionService; } set { connectionService = value; } } /// /// Service host object for sending/receiving requests/events. /// Internal for testing purposes. /// internal IProtocolEndpoint? ServiceHost { get; set; } /// /// Initializes the Security Service instance /// public void InitializeService(ServiceHost serviceHost) { this.ServiceHost = serviceHost; // Credential request handlers this.ServiceHost.SetRequestHandler(CreateCredentialRequest.Type, HandleCreateCredentialRequest, true); this.ServiceHost.SetRequestHandler(UpdateCredentialRequest.Type, HandleUpdateCredentialRequest, true); this.ServiceHost.SetRequestHandler(GetCredentialsRequest.Type, HandleGetCredentialsRequest, true); // Login request handlers this.ServiceHost.SetRequestHandler(CreateLoginRequest.Type, this.loginServiceHandler.HandleCreateLoginRequest, true); this.ServiceHost.SetRequestHandler(UpdateLoginRequest.Type, this.loginServiceHandler.HandleUpdateLoginRequest, true); this.ServiceHost.SetRequestHandler(InitializeLoginViewRequest.Type, this.loginServiceHandler.HandleInitializeLoginViewRequest, true); this.ServiceHost.SetRequestHandler(DisposeLoginViewRequest.Type, this.loginServiceHandler.HandleDisposeLoginViewRequest, true); // User request handlers this.ServiceHost.SetRequestHandler(InitializeUserViewRequest.Type, this.userServiceHandler.HandleInitializeUserViewRequest, true); this.ServiceHost.SetRequestHandler(CreateUserRequest.Type, this.userServiceHandler.HandleCreateUserRequest, 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); } #region "Credential Handlers" /// /// Handle request to create a credential /// internal async Task HandleCreateCredentialRequest(CreateCredentialParams parameters, RequestContext requestContext) { var result = await ConfigureCredential(parameters.OwnerUri, parameters.Credential, ConfigAction.Create, RunType.RunNow); await requestContext.SendResult(new CredentialResult() { Credential = parameters.Credential, Success = result.Item1, ErrorMessage = result.Item2 }); } /// /// Handle request to update a credential /// internal async Task HandleUpdateCredentialRequest(UpdateCredentialParams parameters, RequestContext requestContext) { var result = await ConfigureCredential(parameters.OwnerUri, parameters.Credential, ConfigAction.Update, RunType.RunNow); await requestContext.SendResult(new CredentialResult() { Credential = parameters.Credential, Success = result.Item1, ErrorMessage = result.Item2 }); } /// /// Handle request to get all credentials /// internal async Task HandleGetCredentialsRequest(GetCredentialsParams parameters, RequestContext requestContext) { var result = new GetCredentialsResult(); try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection(parameters.OwnerUri, out connInfo); CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); var credentials = dataContainer.Server?.Credentials; int credentialsCount = credentials != null ? credentials.Count : 0; CredentialInfo[] credentialsInfos = new CredentialInfo[credentialsCount]; if (credentials != null) { for (int i = 0; i < credentialsCount; ++i) { credentialsInfos[i] = new CredentialInfo(); credentialsInfos[i].Name = credentials[i].Name; credentialsInfos[i].Identity = credentials[i].Identity; credentialsInfos[i].Id = credentials[i].ID; credentialsInfos[i].DateLastModified = credentials[i].DateLastModified; credentialsInfos[i].CreateDate = credentials[i].CreateDate; credentialsInfos[i].ProviderName = credentials[i].ProviderName; } } result.Credentials = credentialsInfos; result.Success = true; } catch (Exception ex) { result.Success = false; result.ErrorMessage = ex.ToString(); } await requestContext.SendResult(result); } /// /// Disposes the service /// public void Dispose() { if (!disposed) { disposed = true; } } internal Task> ConfigureCredential( string ownerUri, CredentialInfo credential, ConfigAction configAction, RunType runType) { return Task>.Run(() => { try { ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo); CDataContainer dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true); using (CredentialActions actions = new CredentialActions(dataContainer, credential, configAction)) { var executionHandler = new ExecutonHandler(actions); executionHandler.RunNow(runType, this); } return new Tuple(true, string.Empty); } catch (Exception ex) { return new Tuple(false, ex.ToString()); } }); } #endregion // "Credential Handlers" } }