Enable Azure Active Directory MFA authentication (#3125)

This commit is contained in:
Matt Irvine
2018-11-27 11:13:47 -08:00
committed by GitHub
parent d646b4729b
commit cb72865dcc
33 changed files with 369 additions and 109 deletions

View File

@@ -136,7 +136,7 @@ suite('Firewall rule dialog controller tests', () => {
// Then: it should get security token from account management service and call create firewall rule in resource provider
deferredPromise.promise.then(() => {
mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny()), TypeMoq.Times.once());
mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
mockFirewallRuleDialog.verify(x => x.close(), TypeMoq.Times.once());
mockFirewallRuleDialog.verify(x => x.onServiceComplete(), TypeMoq.Times.once());
@@ -165,7 +165,7 @@ suite('Firewall rule dialog controller tests', () => {
// Then: it should get security token from account management service and an error dialog should have been opened
deferredPromise.promise.then(() => {
mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny()), TypeMoq.Times.once());
mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.never());
done();
@@ -193,7 +193,7 @@ suite('Firewall rule dialog controller tests', () => {
// Then: it should get security token from account management service and an error dialog should have been opened
deferredPromise.promise.then(() => {
mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny()), TypeMoq.Times.once());
mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
done();
@@ -221,7 +221,7 @@ suite('Firewall rule dialog controller tests', () => {
// Then: it should get security token from account management service and an error dialog should have been opened
deferredPromise.promise.then(() => {
mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny()), TypeMoq.Times.once());
mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
done();
@@ -232,7 +232,7 @@ suite('Firewall rule dialog controller tests', () => {
function getMockAccountManagementService(resolveSecurityToken: boolean): TypeMoq.Mock<AccountManagementTestService> {
let accountManagementTestService = new AccountManagementTestService();
let mockAccountManagementService = TypeMoq.Mock.ofInstance(accountManagementTestService);
mockAccountManagementService.setup(x => x.getSecurityToken(TypeMoq.It.isAny()))
mockAccountManagementService.setup(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
.returns(() => resolveSecurityToken ? Promise.resolve({}) : Promise.reject(null).then());
return mockAccountManagementService;
}

View File

@@ -34,6 +34,7 @@ import * as assert from 'assert';
import * as TypeMoq from 'typemoq';
import { IConnectionProfileGroup, ConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import { AccountManagementTestService } from 'sqltest/stubs/accountManagementStubs';
suite('SQL ConnectionManagementService tests', () => {
@@ -46,6 +47,7 @@ suite('SQL ConnectionManagementService tests', () => {
let mssqlConnectionProvider: TypeMoq.Mock<ConnectionProviderStub>;
let workspaceConfigurationServiceMock: TypeMoq.Mock<WorkspaceConfigurationTestService>;
let resourceProviderStubMock: TypeMoq.Mock<ResourceProviderStub>;
let accountManagementService: TypeMoq.Mock<AccountManagementTestService>;
let none: void;
@@ -88,6 +90,7 @@ suite('SQL ConnectionManagementService tests', () => {
mssqlConnectionProvider = TypeMoq.Mock.ofType(ConnectionProviderStub);
let resourceProviderStub = new ResourceProviderStub();
resourceProviderStubMock = TypeMoq.Mock.ofInstance(resourceProviderStub);
accountManagementService = TypeMoq.Mock.ofType(AccountManagementTestService);
let root = new ConnectionProfileGroup(ConnectionProfileGroup.RootGroupName, undefined, ConnectionProfileGroup.RootGroupName, undefined, undefined);
root.connections = [ConnectionProfile.fromIConnectionProfile(capabilitiesService, connectionProfile)];
@@ -162,7 +165,8 @@ suite('SQL ConnectionManagementService tests', () => {
undefined,
resourceProviderStubMock.object,
undefined,
undefined
undefined,
accountManagementService.object
);
return connectionManagementService;
}
@@ -837,4 +841,44 @@ suite('SQL ConnectionManagementService tests', () => {
// Then undefined is returned
assert.equal(foundUri, undefined);
});
test('addSavedPassword fills in Azure access tokens for Azure accounts', async () => {
// Set up a connection profile that uses Azure
let azureConnectionProfile = ConnectionProfile.fromIConnectionProfile(capabilitiesService, connectionProfile);
azureConnectionProfile.authenticationType = 'AzureMFA';
let username = 'testuser@microsoft.com';
azureConnectionProfile.userName = username;
let servername = 'test-database.database.windows.net';
azureConnectionProfile.serverName = servername;
// Set up the account management service to return a token for the given user
accountManagementService.setup(x => x.getAccountsForProvider(TypeMoq.It.isAny())).returns(providerId => Promise.resolve<sqlops.Account[]>([
{
key: {
accountId: username,
providerId: providerId
},
displayInfo: undefined,
isStale: false,
properties: undefined
}
]));
let testToken = 'testToken';
accountManagementService.setup(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
azurePublicCloud: {
token: testToken
}
}));
connectionStore.setup(x => x.addSavedPassword(TypeMoq.It.is(profile => profile.authenticationType === 'AzureMFA'))).returns(profile => Promise.resolve({
profile: profile,
savedCred: false
}));
// If I call addSavedPassword
let profileWithCredentials = await connectionManagementService.addSavedPassword(azureConnectionProfile);
// Then the returned profile has the account token set
assert.equal(profileWithCredentials.userName, username);
assert.equal(profileWithCredentials.options['azureAccountToken'], testToken);
});
});

View File

@@ -50,7 +50,7 @@ export class AccountManagementTestService implements IAccountManagementService {
return undefined;
}
getSecurityToken(account: sqlops.Account): Thenable<{}> {
getSecurityToken(account: sqlops.Account, resource: sqlops.AzureResource): Thenable<{}> {
return undefined;
}
@@ -88,7 +88,7 @@ export class AccountProviderStub implements sqlops.AccountProvider {
return Promise.resolve();
}
getSecurityToken(account: sqlops.Account): Thenable<{}> {
getSecurityToken(account: sqlops.Account, resource: sqlops.AzureResource): Thenable<{}> {
return Promise.resolve({});
}

View File

@@ -15,7 +15,7 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/
import { IRPCProtocol } from 'vs/workbench/services/extensions/node/proxyIdentifier';
import { SqlMainContext } from 'sql/workbench/api/node/sqlExtHost.protocol';
import { MainThreadAccountManagement } from 'sql/workbench/api/node/mainThreadAccountManagement';
import { IAccountManagementService } from 'sql/services/accountManagement/interfaces';
import { IAccountManagementService, AzureResource } from 'sql/services/accountManagement/interfaces';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
const IRPCProtocol = createDecorator<IRPCProtocol>('rpcProtocol');
@@ -366,7 +366,7 @@ suite('ExtHostAccountManagement', () => {
extHost.$getAllAccounts()
.then((accounts) => {
// If: I get security token it will not throw
return extHost.$getSecurityToken(mockAccount1);
return extHost.$getSecurityToken(mockAccount1, AzureResource.ResourceManagement);
}
).then(() => done(), (err) => done(new Error(err)));
});
@@ -417,7 +417,7 @@ suite('ExtHostAccountManagement', () => {
extHost.$getAllAccounts()
.then(accounts => {
return extHost.$getSecurityToken(mockAccount2);
return extHost.$getSecurityToken(mockAccount2, AzureResource.ResourceManagement);
})
.then((noError) => {
done(new Error('Expected getSecurityToken to throw'));
@@ -447,7 +447,7 @@ function getMockAccountManagementService(accounts: sqlops.Account[]): TypeMoq.Mo
mockAccountManagementService.setup(x => x.getAccountsForProvider(TypeMoq.It.isAny()))
.returns(() => Promise.resolve(accounts));
mockAccountManagementService.setup(x => x.getSecurityToken(TypeMoq.It.isValue(accounts[0])))
mockAccountManagementService.setup(x => x.getSecurityToken(TypeMoq.It.isValue(accounts[0]), TypeMoq.It.isAny()))
.returns(() => Promise.resolve({}));
mockAccountManagementService.setup(x => x.updateAccountListEvent)
.returns(() => () => { return undefined; } );