CMS - SQL Login (#5989)

* initial SQL Login with save password working

* fix switching auth types

* remove metadata from package file

* allow editing connections for unsaved password connections

* review comments

* change thenables to async/awaits

* review comments

* changed thenables to promises

* remove authTypeChanged bool

* removed unused import

* review comments

* removed try catches

* cr comments

* review comments
This commit is contained in:
Aditya Bist
2019-07-01 11:40:11 -07:00
committed by GitHub
parent 6b5193908c
commit 678b2737bd
12 changed files with 317 additions and 211 deletions

View File

@@ -87,6 +87,10 @@
"defaultValue": null, "defaultValue": null,
"objectType": null, "objectType": null,
"categoryValues": [ "categoryValues": [
{
"displayName": "%cms.connectionOptions.authType.categoryValues.sqlLogin%",
"name": "SqlLogin"
},
{ {
"displayName": "%cms.connectionOptions.authType.categoryValues.integrated%", "displayName": "%cms.connectionOptions.authType.categoryValues.integrated%",
"name": "Integrated" "name": "Integrated"

View File

@@ -12,7 +12,6 @@
"cms.resource.addServerGroup.title": "New Server Group...", "cms.resource.addServerGroup.title": "New Server Group...",
"cms.resource.registerCmsServer.title": "Add Central Management Server", "cms.resource.registerCmsServer.title": "Add Central Management Server",
"cms.resource.deleteCmsServer.title": "Delete", "cms.resource.deleteCmsServer.title": "Delete",
"cms.configuration.title": "MSSQL configuration", "cms.configuration.title": "MSSQL configuration",
"cms.query.displayBitAsNumber": "Should BIT columns be displayed as numbers (1 or 0)? If false, BIT columns will be displayed as 'true' or 'false'", "cms.query.displayBitAsNumber": "Should BIT columns be displayed as numbers (1 or 0)? If false, BIT columns will be displayed as 'true' or 'false'",
"cms.format.alignColumnDefinitionsInColumns": "Should column definitions be aligned?", "cms.format.alignColumnDefinitionsInColumns": "Should column definitions be aligned?",

View File

@@ -18,40 +18,37 @@ const localize = nls.loadMessageBundle();
export function registerCmsServerCommand(appContext: AppContext, tree: CmsResourceTreeProvider): void { export function registerCmsServerCommand(appContext: AppContext, tree: CmsResourceTreeProvider): void {
// Create a CMS Server // Create a CMS Server
appContext.apiWrapper.registerCommand('cms.resource.registerCmsServer', async (node?: TreeNode) => { appContext.apiWrapper.registerCommand('cms.resource.registerCmsServer', async (node?: TreeNode, connectionProfile?: azdata.IConnectionProfile) => {
if (node && !(node instanceof CmsResourceEmptyTreeNode)) { if (node && !(node instanceof CmsResourceEmptyTreeNode)) {
return; return;
} }
await appContext.cmsUtils.connection.then(async (connection) => { let connection = await appContext.cmsUtils.makeConnection(connectionProfile);
if (connection && connection.options) { if (connection && connection.options) {
let registeredCmsServerName = connection.options.registeredServerName ? let registeredCmsServerName = connection.options.registeredServerName ?
connection.options.registeredServerName : connection.options.server; connection.options.registeredServerName : connection.options.server;
// check if a CMS with the same name is registered or not // check if a CMS with the same name is registered or not
let cachedServers = appContext.cmsUtils.registeredCmsServers; let cachedServers = appContext.cmsUtils.registeredCmsServers;
let serverExists: boolean = false; let serverExists: boolean = false;
if (cachedServers) { if (cachedServers) {
serverExists = cachedServers.some((server) => { serverExists = cachedServers.some((server) => {
return server.name === registeredCmsServerName; return server.name === registeredCmsServerName;
}); });
}
if (!serverExists) {
// remove any group ID if user selects a connection from
// recent connection list
connection.options.groupId = null;
let registeredCmsServerDescription = connection.options.registeredServerDescription;
// remove server description from connection uri
connection.options.registeredCmsServerDescription = null;
let ownerUri = await azdata.connection.getUriForConnection(connection.connectionId);
appContext.cmsUtils.cacheRegisteredCmsServer(registeredCmsServerName, registeredCmsServerDescription, ownerUri, connection);
tree.notifyNodeChanged(undefined);
} else {
// error out for same server name
let errorText = localize('cms.errors.sameCmsServerName', 'Central Management Server Group already has a Registered Server with the name {0}', registeredCmsServerName);
appContext.apiWrapper.showErrorMessage(errorText);
return;
}
} }
}); if (!serverExists) {
// remove any group ID if user selects a connection from
// recent connection list
connection.options.groupId = null;
let registeredCmsServerDescription = connection.options.registeredServerDescription;
let ownerUri = await azdata.connection.getUriForConnection(connection.connectionId);
appContext.cmsUtils.cacheRegisteredCmsServer(registeredCmsServerName, registeredCmsServerDescription, ownerUri, connection);
tree.notifyNodeChanged(undefined);
} else {
// error out for same server name
let errorText = localize('cms.errors.sameCmsServerName', 'Central Management Server Group already has a Registered Server with the name {0}', registeredCmsServerName);
appContext.apiWrapper.showErrorMessage(errorText);
throw new Error(errorText);
}
}
}); });
} }
@@ -61,7 +58,7 @@ export function deleteCmsServerCommand(appContext: AppContext, tree: CmsResource
if (!(node instanceof CmsResourceTreeNode)) { if (!(node instanceof CmsResourceTreeNode)) {
return; return;
} }
await appContext.cmsUtils.deleteCmsServer(node.name); await appContext.cmsUtils.deleteCmsServer(node.name, node.connection);
tree.isSystemInitialized = false; tree.isSystemInitialized = false;
tree.notifyNodeChanged(undefined); tree.notifyNodeChanged(undefined);
}); });
@@ -76,16 +73,8 @@ export function addRegisteredServerCommand(appContext: AppContext, tree: CmsReso
let relativePath = node instanceof CmsResourceTreeNode ? '' : node.relativePath; let relativePath = node instanceof CmsResourceTreeNode ? '' : node.relativePath;
let serverName = node instanceof CmsResourceTreeNode ? node.connection.options.registeredServerName === '' let serverName = node instanceof CmsResourceTreeNode ? node.connection.options.registeredServerName === ''
? node.connection.options.server : node.connection.options.registeredServerName : null; ? node.connection.options.server : node.connection.options.registeredServerName : null;
await appContext.cmsUtils.addRegisteredServer(relativePath, node.ownerUri, serverName).then((result) => { await appContext.cmsUtils.addRegisteredServer(relativePath, node.ownerUri, serverName);
if (result) { tree.notifyNodeChanged(node);
tree.notifyNodeChanged(node);
}
}, (error) => {
// error out
let errorText = localize('cms.errors.addRegisterServerFail', 'Could not add the Registered Server {0}', error);
appContext.apiWrapper.showErrorMessage(errorText);
return;
});
}); });
} }
@@ -95,18 +84,14 @@ export function deleteRegisteredServerCommand(appContext: AppContext, tree: CmsR
if (!(node instanceof RegisteredServerTreeNode)) { if (!(node instanceof RegisteredServerTreeNode)) {
return; return;
} }
appContext.apiWrapper.showWarningMessage( let result = await appContext.apiWrapper.showWarningMessage(
`${localize('cms.confirmDeleteServer', 'Are you sure you want to delete')} ${node.name}?`, `${localize('cms.confirmDeleteServer', 'Are you sure you want to delete')} ${node.name}?`,
localize('cms.yes', 'Yes'), localize('cms.yes', 'Yes'),
localize('cms.no', 'No')).then((result) => { localize('cms.no', 'No'));
if (result && result === localize('cms.yes', 'Yes')) { if (result && result === localize('cms.yes', 'Yes')) {
appContext.cmsUtils.removeRegisteredServer(node.name, node.relativePath, node.ownerUri).then((result) => { await appContext.cmsUtils.removeRegisteredServer(node.name, node.relativePath, node.ownerUri);
if (result) { tree.notifyNodeChanged(node.parent);
tree.notifyNodeChanged(node.parent); }
}
});
}
});
}); });
} }
@@ -151,22 +136,19 @@ export function addServerGroupCommand(appContext: AppContext, tree: CmsResourceT
dialog.content = [mainTab]; dialog.content = [mainTab];
azdata.window.openDialog(dialog); azdata.window.openDialog(dialog);
let groupExists = false; let groupExists = false;
dialog.okButton.onClick(() => { dialog.okButton.onClick(async () => {
let path = node instanceof ServerGroupTreeNode ? node.relativePath : ''; let path = node instanceof ServerGroupTreeNode ? node.relativePath : '';
if (node.serverGroupNodes.some(node => node.name === serverGroupName)) { if (node.serverGroupNodes.some(node => node.name === serverGroupName)) {
groupExists = true; groupExists = true;
} }
if (!groupExists) { if (!groupExists) {
appContext.cmsUtils.addServerGroup(serverGroupName, serverDescription, path, node.ownerUri).then((result) => { await appContext.cmsUtils.addServerGroup(serverGroupName, serverDescription, path, node.ownerUri);
if (result) { tree.notifyNodeChanged(node);
tree.notifyNodeChanged(node);
}
});
} else { } else {
// error out for same server group // error out for same server group
let errorText = localize('cms.errors.sameServerGroupName', '{0} already has a Server Group with the name {1}', node.name, serverGroupName); const errorText = localize('cms.errors.sameServerGroupName', '{0} already has a Server Group with the name {1}', node.name, serverGroupName);
appContext.apiWrapper.showErrorMessage(errorText); appContext.apiWrapper.showErrorMessage(errorText);
return; throw new Error(errorText);
} }
}); });
}); });
@@ -178,18 +160,14 @@ export function deleteServerGroupCommand(appContext: AppContext, tree: CmsResour
if (!(node instanceof ServerGroupTreeNode)) { if (!(node instanceof ServerGroupTreeNode)) {
return; return;
} }
appContext.apiWrapper.showWarningMessage( let result = await appContext.apiWrapper.showWarningMessage(
`${localize('cms.confirmDeleteGroup', 'Are you sure you want to delete')} ${node.name}?`, `${localize('cms.confirmDeleteGroup', 'Are you sure you want to delete')} ${node.name}?`,
localize('cms.yes', 'Yes'), localize('cms.yes', 'Yes'),
localize('cms.no', 'No')).then((result) => { localize('cms.no', 'No'));
if (result && result === localize('cms.yes', 'Yes')) { if (result && result === localize('cms.yes', 'Yes')) {
appContext.cmsUtils.removeServerGroup(node.name, node.relativePath, node.ownerUri).then((result) => { await appContext.cmsUtils.removeServerGroup(node.name, node.relativePath, node.ownerUri);
if (result) { tree.notifyNodeChanged(node.parent);
tree.notifyNodeChanged(node.parent); }
}
});
}
});
}); });
} }

View File

@@ -6,7 +6,7 @@
'use strict'; 'use strict';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { TreeItemCollapsibleState } from 'vscode'; import { TreeItemCollapsibleState, TreeItem } from 'vscode';
import { AppContext } from '../../appContext'; import { AppContext } from '../../appContext';
import { TreeNode } from '../treeNode'; import { TreeNode } from '../treeNode';
import { CmsResourceTreeNodeBase } from './baseTreeNodes'; import { CmsResourceTreeNodeBase } from './baseTreeNodes';
@@ -38,48 +38,52 @@ export class CmsResourceTreeNode extends CmsResourceTreeNodeBase {
try { try {
let nodes: CmsResourceTreeNodeBase[] = []; let nodes: CmsResourceTreeNodeBase[] = [];
if (!this.ownerUri) { if (!this.ownerUri) {
this._ownerUri = await this.appContext.cmsUtils.getUriForConnection(this.connection); // Set back password to get ownerUri
if (this.connection.options.authenticationType === 'SqlLogin' && this.connection.options.savePassword === true) {
this.connection.options.password = await this.appContext.cmsUtils.getPassword(this.connection.options.user);
}
} }
return this.appContext.cmsUtils.createCmsServer(this.connection, this.name, this.description).then((result) => { return this.appContext.cmsUtils.createCmsServer(this.connection, this.name, this.description).then((result) => {
if (result) { // cache new connection is different from old one
if (result.registeredServersList) { if (this.appContext.cmsUtils.didConnectionChange(this._connection, result.connection)) {
result.registeredServersList.forEach((registeredServer) => { this._connection = result.connection;
nodes.push(new RegisteredServerTreeNode( this._ownerUri = result.ownerUri;
registeredServer.name, this.appContext.cmsUtils.cacheRegisteredCmsServer(this.name, this.description, this.ownerUri, this.connection);
registeredServer.description, }
registeredServer.serverName, if (result.listRegisteredServersResult.registeredServersList) {
registeredServer.relativePath, result.listRegisteredServersResult.registeredServersList.forEach((registeredServer) => {
this.ownerUri, nodes.push(new RegisteredServerTreeNode(
this.appContext, registeredServer.name,
this.treeChangeHandler, this)); registeredServer.description,
}); registeredServer.serverName,
} registeredServer.relativePath,
if (result.registeredServerGroups) { this.ownerUri,
if (result.registeredServerGroups) { this.appContext,
this._serverGroupNodes = []; this.treeChangeHandler, this));
result.registeredServerGroups.forEach((serverGroup) => { });
let serverGroupNode = new ServerGroupTreeNode( }
serverGroup.name, if (result.listRegisteredServersResult.registeredServerGroups) {
serverGroup.description, this._serverGroupNodes = [];
serverGroup.relativePath, result.listRegisteredServersResult.registeredServerGroups.forEach((serverGroup) => {
this.ownerUri, let serverGroupNode = new ServerGroupTreeNode(
this.appContext, serverGroup.name,
this.treeChangeHandler, this); serverGroup.description,
nodes.push(serverGroupNode); serverGroup.relativePath,
this._serverGroupNodes.push(serverGroupNode); this.ownerUri,
}); this.appContext,
} this.treeChangeHandler, this);
} nodes.push(serverGroupNode);
if (nodes.length > 0) { this._serverGroupNodes.push(serverGroupNode);
return nodes.sort((node1, node2) => node1.name > node2.name ? 1 : -1); });
} else { }
return [CmsResourceMessageTreeNode.create(CmsResourceTreeNode.noResourcesLabel, undefined)]; if (nodes.length > 0) {
} return nodes.sort((node1, node2) => node1.name > node2.name ? 1 : -1);
} else {
return [CmsResourceMessageTreeNode.create(CmsResourceTreeNode.noResourcesLabel, undefined)];
} }
}, (error) => { }, (error) => {
let errorText = localize('cms.errors.expandCmsFail', 'The Central Management Server {0} could not be found or is offline', this.name); this.treeChangeHandler.notifyNodeChanged(undefined);
this.appContext.apiWrapper.showErrorMessage(error ? error : errorText); throw error;
return [];
}); });
} catch { } catch {
return []; return [];

View File

@@ -14,6 +14,7 @@ import { CmsResourceEmptyTreeNode } from './cmsResourceEmptyTreeNode';
import { ICmsResourceTreeChangeHandler } from './treeChangeHandler'; import { ICmsResourceTreeChangeHandler } from './treeChangeHandler';
import { CmsResourceMessageTreeNode } from '../messageTreeNode'; import { CmsResourceMessageTreeNode } from '../messageTreeNode';
import { CmsResourceTreeNode } from './cmsResourceTreeNode'; import { CmsResourceTreeNode } from './cmsResourceTreeNode';
import { ICmsResourceNodeInfo } from './baseTreeNodes';
export class CmsResourceTreeProvider implements TreeDataProvider<TreeNode>, ICmsResourceTreeChangeHandler { export class CmsResourceTreeProvider implements TreeDataProvider<TreeNode>, ICmsResourceTreeChangeHandler {
@@ -27,7 +28,8 @@ export class CmsResourceTreeProvider implements TreeDataProvider<TreeNode>, ICms
public async getChildren(element?: TreeNode): Promise<TreeNode[]> { public async getChildren(element?: TreeNode): Promise<TreeNode[]> {
if (element) { if (element) {
return element.getChildren(true); let children = await element.getChildren(true);
return children;
} }
if (!this.isSystemInitialized) { if (!this.isSystemInitialized) {
@@ -42,11 +44,11 @@ export class CmsResourceTreeProvider implements TreeDataProvider<TreeNode>, ICms
servers.push(new CmsResourceTreeNode( servers.push(new CmsResourceTreeNode(
server.name, server.name,
server.description, server.description,
undefined, server.ownerUri,
server.connection, server.connection,
this._appContext, this, null)); this._appContext, this, null));
this.appContext.cmsUtils.cacheRegisteredCmsServer(server.name, server.description, this.appContext.cmsUtils.cacheRegisteredCmsServer(server.name, server.description,
undefined, server.connection); server.ownerUri, server.connection);
}); });
return servers; return servers;
} }
@@ -62,13 +64,6 @@ export class CmsResourceTreeProvider implements TreeDataProvider<TreeNode>, ICms
let registeredCmsServers = this.appContext.cmsUtils.registeredCmsServers; let registeredCmsServers = this.appContext.cmsUtils.registeredCmsServers;
if (registeredCmsServers && registeredCmsServers.length > 0) { if (registeredCmsServers && registeredCmsServers.length > 0) {
this.isSystemInitialized = true; this.isSystemInitialized = true;
// save the CMS Servers for future use
let toSaveCmsServers = JSON.parse(JSON.stringify(registeredCmsServers));
toSaveCmsServers.forEach(server => {
server.ownerUri = undefined,
server.connection.options.password = '';
});
await this._appContext.cmsUtils.setConfiguration(toSaveCmsServers);
return registeredCmsServers.map((server) => { return registeredCmsServers.map((server) => {
return new CmsResourceTreeNode( return new CmsResourceTreeNode(
server.name, server.name,

View File

@@ -14,6 +14,14 @@ import { ICmsResourceNodeInfo } from './cmsResource/tree/baseTreeNodes';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
const cmsProvider: string = 'MSSQL-CMS'; const cmsProvider: string = 'MSSQL-CMS';
const mssqlProvider: string = 'MSSQL'; const mssqlProvider: string = 'MSSQL';
const CredentialNamespace = 'cmsCredentials';
const sqlLoginAuthType: string = 'SqlLogin';
export interface CreateCmsResult {
listRegisteredServersResult: mssql.ListRegisteredServersResult;
connection: azdata.connection.Connection;
ownerUri: string;
}
/** /**
* Wrapper class to act as a facade over VSCode and Data APIs and allow us to test / mock callbacks into * Wrapper class to act as a facade over VSCode and Data APIs and allow us to test / mock callbacks into
@@ -24,8 +32,21 @@ const mssqlProvider: string = 'MSSQL';
*/ */
export class CmsUtils { export class CmsUtils {
private _credentialProvider: azdata.CredentialProvider;
private _cmsService: mssql.CmsService; private _cmsService: mssql.CmsService;
private _registeredCmsServers: ICmsResourceNodeInfo[]; private _registeredCmsServers: ICmsResourceNodeInfo[] = [];
public async savePassword(username: string, password: string): Promise<boolean> {
let provider = await this.credentialProvider();
let result = await provider.saveCredential(username, password);
return result;
}
public async getPassword(username: string): Promise<string> {
let provider = await this.credentialProvider();
let credential = await provider.readCredential(username);
return credential ? credential.password : undefined;
}
public showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> { public showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
return vscode.window.showErrorMessage(message, ...items); return vscode.window.showErrorMessage(message, ...items);
@@ -53,9 +74,10 @@ export class CmsUtils {
let ownerUri = await azdata.connection.getUriForConnection(connection.connectionId); let ownerUri = await azdata.connection.getUriForConnection(connection.connectionId);
if (!ownerUri) { if (!ownerUri) {
// Make a connection if it's not already connected // Make a connection if it's not already connected
await azdata.connection.connect(Utils.toConnectionProfile(connection), false, false).then(async (result) => { let result = await azdata.connection.connect(Utils.toConnectionProfile(connection), false, false);
if (result) {
ownerUri = await azdata.connection.getUriForConnection(result.connectionId); ownerUri = await azdata.connection.getUriForConnection(result.connectionId);
}); }
} }
return ownerUri; return ownerUri;
} }
@@ -70,59 +92,79 @@ export class CmsUtils {
} }
public async getRegisteredServers(ownerUri: string, relativePath: string): Promise<mssql.ListRegisteredServersResult> { public async getRegisteredServers(ownerUri: string, relativePath: string): Promise<mssql.ListRegisteredServersResult> {
return this.getCmsService().then((service) => { const cmsService = await this.getCmsService();
return service.getRegisteredServers(ownerUri, relativePath).then((result) => { const result = await cmsService.getRegisteredServers(ownerUri, relativePath);
if (result && result.registeredServersList && result.registeredServersList) { if (result && result.registeredServersList && result.registeredServersList) {
return result; return result;
} }
});
});
} }
public async createCmsServer(connection: azdata.connection.Connection, public async createCmsServer(connection: azdata.connection.Connection,
name: string, description: string): Promise<mssql.ListRegisteredServersResult> { name: string, description: string): Promise<CreateCmsResult> {
let provider = await this.getCmsService(); let provider = await this.getCmsService();
connection.providerName = connection.providerName === cmsProvider ? mssqlProvider : connection.providerName; connection.providerName = connection.providerName === cmsProvider ? mssqlProvider : connection.providerName;
let ownerUri = await azdata.connection.getUriForConnection(connection.connectionId); let ownerUri = await azdata.connection.getUriForConnection(connection.connectionId);
if (!ownerUri) { if (!ownerUri) {
// Make a connection if it's not already connected // Make a connection if it's not already connected
await azdata.connection.connect(Utils.toConnectionProfile(connection), false, false).then(async (result) => { let initialConnectionProfile = this.getConnectionProfile(connection);
ownerUri = await azdata.connection.getUriForConnection(result.connectionId); let result = await azdata.connection.connect(initialConnectionProfile, false, false);
}); ownerUri = await azdata.connection.getUriForConnection(result.connectionId);
} // If the ownerUri is still undefined, then open a connection dialog with the connection
return provider.createCmsServer(name, description, connection, ownerUri).then((result) => { if (!ownerUri) {
if (result) { let result = await this.makeConnection(initialConnectionProfile);
return Promise.resolve(result); if (result) {
} else { ownerUri = await azdata.connection.getUriForConnection(result.connectionId);
return Promise.reject(null); connection = result;
}
} }
}); }
let result = await provider.createCmsServer(name, description, connection, ownerUri);
const createCmsResult: CreateCmsResult = {
listRegisteredServersResult: result,
connection: connection,
ownerUri: ownerUri
};
return createCmsResult;
} }
public async deleteCmsServer(cmsServer: any): Promise<void> { public async deleteCmsServer(cmsServerName: string, connection: azdata.connection.Connection): Promise<void> {
let config = this.getConfiguration(); let config = this.getConfiguration();
if (config && config.servers) { if (config && config.servers) {
let newServers = config.servers.filter((cachedServer) => { let newServers = config.servers.filter((cachedServer) => {
return cachedServer.name !== cmsServer; return cachedServer.name !== cmsServerName;
}); });
await this.setConfiguration(newServers); await this.setConfiguration(newServers);
this._registeredCmsServers = this._registeredCmsServers.filter((cachedServer) => { this._registeredCmsServers = this._registeredCmsServers.filter((cachedServer) => {
return cachedServer.name !== cmsServer; return cachedServer.name !== cmsServerName;
}); });
} }
if (connection.options.authenticationType === sqlLoginAuthType && connection.options.savePassword) {
this._credentialProvider.deleteCredential(connection.options.user);
}
} }
public cacheRegisteredCmsServer(name: string, description: string, ownerUri: string, connection: azdata.connection.Connection): void { public async cacheRegisteredCmsServer(name: string, description: string, ownerUri: string, connection: azdata.connection.Connection): Promise<void> {
if (!this._registeredCmsServers) {
this._registeredCmsServers = [];
}
let cmsServerNode: ICmsResourceNodeInfo = { let cmsServerNode: ICmsResourceNodeInfo = {
name: name, name: name,
description: description, description: description,
connection: connection, connection: connection,
ownerUri: ownerUri ownerUri: ownerUri
}; };
// update a server if a server with same name exists
this._registeredCmsServers = this._registeredCmsServers.filter((server) => {
return server.name !== name;
});
this._registeredCmsServers.push(cmsServerNode); this._registeredCmsServers.push(cmsServerNode);
// save the CMS Servers for future use
let toSaveCmsServers: ICmsResourceNodeInfo[] = this._registeredCmsServers.map(server => Object.assign({}, server));
toSaveCmsServers.forEach(server => {
server.ownerUri = undefined;
// don't save password in config
server.connection.options.password = '';
});
await this.setConfiguration(toSaveCmsServers);
} }
public async addRegisteredServer(relativePath: string, ownerUri: string, public async addRegisteredServer(relativePath: string, ownerUri: string,
@@ -143,47 +185,41 @@ export class CmsUtils {
providerName: undefined, providerName: undefined,
saveProfile: undefined, saveProfile: undefined,
id: undefined, id: undefined,
options: {} options: {
}; authTypeChanged: true
return this.openConnectionDialog([cmsProvider], initialProfile, { saveConnection: false }).then(async (connection) => {
if (connection && connection.options) {
if (connection.options.server === parentServerName) {
// error out for same server registration
let errorText = localize('cms.errors.sameServerUnderCms', 'You cannot add a shared registered server with the same name as the Configuration Server');
this.showErrorMessage(errorText);
return false;
} else {
let registeredServerName = connection.options.registeredServerName === '' ? connection.options.server : connection.options.registeredServerName;
let result = await provider.addRegisteredServer(ownerUri, relativePath, registeredServerName, connection.options.registeredServerDescription, connection);
if (result) {
return Promise.resolve(result);
} else {
return Promise.reject(registeredServerName);
}
}
} }
}); };
let connection = await this.openConnectionDialog([cmsProvider], initialProfile, { saveConnection: false });
if (connection && connection.options) {
if (connection.options.server === parentServerName) {
// error out for same server registration
let errorText = localize('cms.errors.sameServerUnderCms', 'You cannot add a shared registered server with the same name as the Configuration Server');
this.showErrorMessage(errorText);
throw new Error(errorText);
} else {
let registeredServerName = connection.options.registeredServerName === '' ? connection.options.server : connection.options.registeredServerName;
let result = await provider.addRegisteredServer(ownerUri, relativePath, registeredServerName, connection.options.registeredServerDescription, connection);
return result;
}
}
} }
public async removeRegisteredServer(registeredServerName: string, relativePath: string, ownerUri: string): Promise<boolean> { public async removeRegisteredServer(registeredServerName: string, relativePath: string, ownerUri: string): Promise<boolean> {
let provider = await this.getCmsService(); let provider = await this.getCmsService();
return provider.removeRegisteredServer(ownerUri, relativePath, registeredServerName).then((result) => { let result = await provider.removeRegisteredServer(ownerUri, relativePath, registeredServerName);
return result; return result;
});
} }
public async addServerGroup(groupName: string, groupDescription: string, relativePath: string, ownerUri: string): Promise<boolean> { public async addServerGroup(groupName: string, groupDescription: string, relativePath: string, ownerUri: string): Promise<boolean> {
let provider = await this.getCmsService(); let provider = await this.getCmsService();
return provider.addServerGroup(ownerUri, relativePath, groupName, groupDescription).then((result) => { let result = await provider.addServerGroup(ownerUri, relativePath, groupName, groupDescription);
return result; return result;
});
} }
public async removeServerGroup(groupName: string, relativePath: string, ownerUri: string): Promise<boolean> { public async removeServerGroup(groupName: string, relativePath: string, ownerUri: string): Promise<boolean> {
let provider = await this.getCmsService(); let provider = await this.getCmsService();
return provider.removeServerGroup(ownerUri, relativePath, groupName).then((result) => { let result = await provider.removeServerGroup(ownerUri, relativePath, groupName);
return result; return result;
});
} }
// Getters // Getters
@@ -191,15 +227,68 @@ export class CmsUtils {
return this._registeredCmsServers; return this._registeredCmsServers;
} }
public get connection(): Thenable<azdata.connection.Connection> { public async credentialProvider(): Promise<azdata.CredentialProvider> {
return this.openConnectionDialog([cmsProvider], undefined, { saveConnection: false }).then((connection) => { if (!this._credentialProvider) {
if (connection) { this._credentialProvider = await azdata.credentials.getProvider(CredentialNamespace);
// remove group ID from connection if a user chose connection }
// from the recent connections list return this._credentialProvider;
connection.options['groupId'] = null;
connection.providerName = mssqlProvider;
return connection;
}
});
} }
public async makeConnection(initialConnectionProfile?: azdata.IConnectionProfile): Promise<azdata.connection.Connection> {
if (!initialConnectionProfile) {
initialConnectionProfile = {
connectionName: undefined,
serverName: undefined,
databaseName: undefined,
userName: undefined,
password: undefined,
authenticationType: undefined,
savePassword: undefined,
groupFullName: undefined,
groupId: undefined,
providerName: undefined,
saveProfile: undefined,
id: undefined,
options: {}
};
}
let connection = await this.openConnectionDialog([cmsProvider], initialConnectionProfile, { saveConnection: false });
if (connection) {
// remove group ID from connection if a user chose connection
// from the recent connections list
connection.options['groupId'] = null;
connection.providerName = mssqlProvider;
if (connection.options.savePassword) {
await this.savePassword(connection.options.user, connection.options.password);
}
return connection;
}
}
// Static Functions
public getConnectionProfile(connection: azdata.connection.Connection): azdata.IConnectionProfile {
let connectionProfile: azdata.IConnectionProfile = {
connectionName: connection.options.connectionName,
serverName: connection.options.server,
databaseName: undefined,
userName: connection.options.user,
password: connection.options.password,
authenticationType: connection.options.authenticationType,
savePassword: connection.options.savePassword,
groupFullName: undefined,
groupId: undefined,
providerName: connection.providerName,
saveProfile: false,
id: connection.connectionId,
options: connection.options
};
return connectionProfile;
}
public didConnectionChange(connectionA: azdata.connection.Connection, connectionB: azdata.connection.Connection): boolean {
return (connectionA !== connectionB) || ((connectionA.connectionId === connectionB.connectionId) &&
(connectionA.options.savePassword !== connectionA.options.savePassword));
}
} }

View File

@@ -53,6 +53,9 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
this.options[appNameKey] = Constants.applicationName; this.options[appNameKey] = Constants.applicationName;
} }
} }
if (model.options.registeredServerDescription) {
this.registeredServerDescription = model.options.registeredServerDescription;
}
} }
} else { } else {
//Default for a new connection //Default for a new connection
@@ -109,12 +112,12 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
this.options['azureTenantId'] = value; this.options['azureTenantId'] = value;
} }
public get registeredCmsServerDescription(): string { public get registeredServerDescription(): string {
return this.options['registeredCmsServerDescription']; return this.options['registeredServerDescription'];
} }
public set registeredCmsServerDescription(value: string) { public set registeredServerDescription(value: string) {
this.options['registeredCmsServerDescription'] = value; this.options['registeredServerDescription'] = value;
} }
public get groupFullName(): string { public get groupFullName(): string {

View File

@@ -75,6 +75,9 @@ export class MainThreadConnectionManagement implements MainThreadConnectionManag
} }
let connectionProfile = await this._connectionDialogService.openDialogAndWait(this._connectionManagementService, let connectionProfile = await this._connectionDialogService.openDialogAndWait(this._connectionManagementService,
{ connectionType: connectionType, providers: providers }, initialConnectionProfile, undefined); { connectionType: connectionType, providers: providers }, initialConnectionProfile, undefined);
if (connectionProfile) {
connectionProfile.options.savePassword = connectionProfile.savePassword;
}
const connection = connectionProfile ? { const connection = connectionProfile ? {
connectionId: connectionProfile.id, connectionId: connectionProfile.id,
options: connectionProfile.options, options: connectionProfile.options,

View File

@@ -36,8 +36,8 @@ export class CmsConnectionController extends ConnectionController {
}, providerName); }, providerName);
} }
public showUiComponent(container: HTMLElement): void { public showUiComponent(container: HTMLElement, authTypeChanged: boolean = false): void {
this._databaseCache = new Map<string, string[]>(); this._databaseCache = new Map<string, string[]>();
this._connectionWidget.createConnectionWidget(container); this._connectionWidget.createConnectionWidget(container, authTypeChanged);
} }
} }

View File

@@ -35,7 +35,7 @@ export class CmsConnectionWidget extends ConnectionWidget {
private _serverDescriptionInputBox: InputBox; private _serverDescriptionInputBox: InputBox;
protected _authTypeMap: { [providerName: string]: AuthenticationType[] } = { protected _authTypeMap: { [providerName: string]: AuthenticationType[] } = {
[Constants.cmsProviderName]: [AuthenticationType.Integrated] [Constants.cmsProviderName]: [AuthenticationType.SqlLogin, AuthenticationType.Integrated]
}; };
constructor(options: azdata.ConnectionOption[], constructor(options: azdata.ConnectionOption[],
@@ -53,8 +53,14 @@ export class CmsConnectionWidget extends ConnectionWidget {
super(options, callbacks, providerName, _themeService, _contextViewService, _connectionManagementService, _capabilitiesService, super(options, callbacks, providerName, _themeService, _contextViewService, _connectionManagementService, _capabilitiesService,
_clipboardService, _configurationService, _accountManagementService); _clipboardService, _configurationService, _accountManagementService);
let authTypeOption = this._optionsMaps[ConnectionOptionSpecialType.authType]; let authTypeOption = this._optionsMaps[ConnectionOptionSpecialType.authType];
authTypeOption.defaultValue = this.getAuthTypeDisplayName(AuthenticationType.Integrated); if (authTypeOption) {
this._authTypeSelectBox = new SelectBox(authTypeOption.categoryValues.map(c => c.displayName), authTypeOption.defaultValue, this._contextViewService, undefined, { ariaLabel: authTypeOption.displayName }); if (OS === OperatingSystem.Windows) {
authTypeOption.defaultValue = this.getAuthTypeDisplayName(AuthenticationType.Integrated);
} else {
authTypeOption.defaultValue = this.getAuthTypeDisplayName(AuthenticationType.SqlLogin);
}
this._authTypeSelectBox = new SelectBox(authTypeOption.categoryValues.map(c => c.displayName), authTypeOption.defaultValue, this._contextViewService, undefined, { ariaLabel: authTypeOption.displayName });
}
} }
protected registerListeners(): void { protected registerListeners(): void {
@@ -64,12 +70,12 @@ export class CmsConnectionWidget extends ConnectionWidget {
} }
} }
protected fillInConnectionForm(): void { protected fillInConnectionForm(authTypeChanged: boolean = false): void {
// Server Name // Server Name
this.addServerNameOption(); this.addServerNameOption();
// Authentication type // Authentication type
this.addAuthenticationTypeOption(); this.addAuthenticationTypeOption(authTypeChanged);
// Login Options // Login Options
this.addLoginOptions(); this.addLoginOptions();
@@ -84,16 +90,28 @@ export class CmsConnectionWidget extends ConnectionWidget {
this.addAdvancedOptions(); this.addAdvancedOptions();
} }
protected addAuthenticationTypeOption(): void { protected addAuthenticationTypeOption(authTypeChanged: boolean = false): void {
super.addAuthenticationTypeOption(); super.addAuthenticationTypeOption(authTypeChanged);
let authTypeOption = this._optionsMaps[ConnectionOptionSpecialType.authType]; let authTypeOption = this._optionsMaps[ConnectionOptionSpecialType.authType];
let newAuthTypes = authTypeOption.categoryValues; let newAuthTypes = authTypeOption.categoryValues;
// CMS only supports Integrated Auth // True when opening a CMS dialog to add a registered server
newAuthTypes = authTypeOption.categoryValues.filter((option) => option.name === AuthenticationType.Integrated); if (authTypeChanged) {
this._authTypeSelectBox.setOptions(newAuthTypes.map(c => c.displayName), 0); // Registered Servers only support Integrated Auth
authTypeOption.defaultValue = AuthenticationType.Integrated; newAuthTypes = authTypeOption.categoryValues.filter((option) => option.name === AuthenticationType.Integrated);
this._authTypeSelectBox.setOptions(authTypeOption.categoryValues.map(c => c.displayName), 1); this._authTypeSelectBox.setOptions(newAuthTypes.map(c => c.displayName));
authTypeOption.defaultValue = AuthenticationType.Integrated;
} else {
// CMS supports all auth types
newAuthTypes = authTypeOption.categoryValues;
this._authTypeSelectBox.setOptions(newAuthTypes.map(c => c.displayName));
if (OS === OperatingSystem.Windows) {
authTypeOption.defaultValue = this.getAuthTypeDisplayName(AuthenticationType.Integrated);
} else {
authTypeOption.defaultValue = this.getAuthTypeDisplayName(AuthenticationType.SqlLogin);
}
}
this._authTypeSelectBox.selectWithOptionName(authTypeOption.defaultValue);
} }
private addServerDescriptionOption(): void { private addServerDescriptionOption(): void {
@@ -107,10 +125,10 @@ export class CmsConnectionWidget extends ConnectionWidget {
} }
} }
public createConnectionWidget(container: HTMLElement): void { public createConnectionWidget(container: HTMLElement, authTypeChanged: boolean = false): void {
this._container = DOM.append(container, DOM.$('div.connection-table')); this._container = DOM.append(container, DOM.$('div.connection-table'));
this._tableContainer = DOM.append(this._container, DOM.$('table.connection-table-content')); this._tableContainer = DOM.append(this._container, DOM.$('table.connection-table-content'));
this.fillInConnectionForm(); this.fillInConnectionForm(authTypeChanged);
this.registerListeners(); this.registerListeners();
if (this._authTypeSelectBox) { if (this._authTypeSelectBox) {
this.onAuthTypeSelected(this._authTypeSelectBox.value); this.onAuthTypeSelected(this._authTypeSelectBox.value);
@@ -147,4 +165,12 @@ export class CmsConnectionWidget extends ConnectionWidget {
} }
return validInputs; return validInputs;
} }
public fillInConnectionInputs(connectionInfo: IConnectionProfile) {
super.fillInConnectionInputs(connectionInfo);
if (connectionInfo) {
let description = connectionInfo.options.registeredServerDescription ? connectionInfo.options.registeredServerDescription : '';
this._serverDescriptionInputBox.value = description;
}
}
} }

View File

@@ -318,7 +318,12 @@ export class ConnectionDialogService implements IConnectionDialogService {
this._model.providerName = this._currentProviderType; this._model.providerName = this._currentProviderType;
this._model = new ConnectionProfile(this._capabilitiesService, this._model); this._model = new ConnectionProfile(this._capabilitiesService, this._model);
this.uiController.showUiComponent(input.container); if (this._inputModel && this._inputModel.options) {
this.uiController.showUiComponent(input.container,
this._inputModel.options.authTypeChanged);
} else {
this.uiController.showUiComponent(input.container);
}
} }

View File

@@ -123,13 +123,13 @@ export class ConnectionWidget {
this._providerName = providerName; this._providerName = providerName;
} }
public createConnectionWidget(container: HTMLElement): void { public createConnectionWidget(container: HTMLElement, authTypeChanged: boolean = false): void {
this._serverGroupOptions = [this.DefaultServerGroup]; this._serverGroupOptions = [this.DefaultServerGroup];
this._serverGroupSelectBox = new SelectBox(this._serverGroupOptions.map(g => g.name), this.DefaultServerGroup.name, this._contextViewService, undefined, { ariaLabel: this._serverGroupDisplayString }); this._serverGroupSelectBox = new SelectBox(this._serverGroupOptions.map(g => g.name), this.DefaultServerGroup.name, this._contextViewService, undefined, { ariaLabel: this._serverGroupDisplayString });
this._previousGroupOption = this._serverGroupSelectBox.value; this._previousGroupOption = this._serverGroupSelectBox.value;
this._container = DOM.append(container, DOM.$('div.connection-table')); this._container = DOM.append(container, DOM.$('div.connection-table'));
this._tableContainer = DOM.append(this._container, DOM.$('table.connection-table-content')); this._tableContainer = DOM.append(this._container, DOM.$('table.connection-table-content'));
this.fillInConnectionForm(); this.fillInConnectionForm(authTypeChanged);
this.registerListeners(); this.registerListeners();
if (this._authTypeSelectBox) { if (this._authTypeSelectBox) {
this.onAuthTypeSelected(this._authTypeSelectBox.value); this.onAuthTypeSelected(this._authTypeSelectBox.value);
@@ -155,12 +155,12 @@ export class ConnectionWidget {
} }
} }
protected fillInConnectionForm(): void { protected fillInConnectionForm(authTypeChanged: boolean = false): void {
// Server Name // Server Name
this.addServerNameOption(); this.addServerNameOption();
// Authentication type // Authentication type
this.addAuthenticationTypeOption(); this.addAuthenticationTypeOption(authTypeChanged);
// Login Options // Login Options
this.addLoginOptions(); this.addLoginOptions();
@@ -178,7 +178,7 @@ export class ConnectionWidget {
this.addAdvancedOptions(); this.addAdvancedOptions();
} }
protected addAuthenticationTypeOption(): void { protected addAuthenticationTypeOption(authTypeChanged: boolean = false): void {
if (this._optionsMaps[ConnectionOptionSpecialType.authType]) { if (this._optionsMaps[ConnectionOptionSpecialType.authType]) {
let authType = DialogHelper.appendRow(this._tableContainer, this._optionsMaps[ConnectionOptionSpecialType.authType].displayName, 'connection-label', 'connection-input'); let authType = DialogHelper.appendRow(this._tableContainer, this._optionsMaps[ConnectionOptionSpecialType.authType].displayName, 'connection-label', 'connection-input');
DialogHelper.appendInputSelectBox(authType, this._authTypeSelectBox); DialogHelper.appendInputSelectBox(authType, this._authTypeSelectBox);