Path: blob/main/src/vs/workbench/services/authentication/browser/authenticationQueryService.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { Emitter } from '../../../../base/common/event.js';6import { Disposable } from '../../../../base/common/lifecycle.js';7import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';8import { ILogService } from '../../../../platform/log/common/log.js';9import { AuthenticationSessionAccount, IAuthenticationService, IAuthenticationExtensionsService, INTERNAL_AUTH_PROVIDER_PREFIX } from '../common/authentication.js';10import {11IAuthenticationQueryService,12IProviderQuery,13IAccountQuery,14IAccountExtensionQuery,15IAccountMcpServerQuery,16IAccountExtensionsQuery,17IAccountMcpServersQuery,18IAccountEntitiesQuery,19IProviderExtensionQuery,20IProviderMcpServerQuery,21IExtensionQuery,22IMcpServerQuery,23IActiveEntities,24IAuthenticationUsageStats,25IBaseQuery26} from '../common/authenticationQuery.js';27import { IAuthenticationUsageService } from './authenticationUsageService.js';28import { IAuthenticationMcpUsageService } from './authenticationMcpUsageService.js';29import { IAuthenticationAccessService } from './authenticationAccessService.js';30import { IAuthenticationMcpAccessService } from './authenticationMcpAccessService.js';31import { IAuthenticationMcpService } from './authenticationMcpService.js';32import { ExtensionIdentifier } from '../../../../platform/extensions/common/extensions.js';3334/**35* Base implementation for query interfaces36*/37abstract class BaseQuery implements IBaseQuery {38constructor(39public readonly providerId: string,40protected readonly queryService: AuthenticationQueryService41) { }42}4344/**45* Implementation of account-extension query operations46*/47class AccountExtensionQuery extends BaseQuery implements IAccountExtensionQuery {48constructor(49providerId: string,50public readonly accountName: string,51public readonly extensionId: string,52queryService: AuthenticationQueryService53) {54super(providerId, queryService);55}5657isAccessAllowed(): boolean | undefined {58return this.queryService.authenticationAccessService.isAccessAllowed(this.providerId, this.accountName, this.extensionId);59}6061setAccessAllowed(allowed: boolean, extensionName?: string): void {62this.queryService.authenticationAccessService.updateAllowedExtensions(63this.providerId,64this.accountName,65[{ id: this.extensionId, name: extensionName || this.extensionId, allowed }]66);67}6869addUsage(scopes: readonly string[], extensionName: string): void {70this.queryService.authenticationUsageService.addAccountUsage(71this.providerId,72this.accountName,73scopes,74this.extensionId,75extensionName76);77}7879getUsage(): {80readonly extensionId: string;81readonly extensionName: string;82readonly scopes: readonly string[];83readonly lastUsed: number;84}[] {85const allUsages = this.queryService.authenticationUsageService.readAccountUsages(this.providerId, this.accountName);86return allUsages87.filter(usage => usage.extensionId === ExtensionIdentifier.toKey(this.extensionId))88.map(usage => ({89extensionId: usage.extensionId,90extensionName: usage.extensionName,91scopes: usage.scopes || [],92lastUsed: usage.lastUsed93}));94}9596removeUsage(): void {97// Get current usages, filter out this extension, and store the rest98const allUsages = this.queryService.authenticationUsageService.readAccountUsages(this.providerId, this.accountName);99const filteredUsages = allUsages.filter(usage => usage.extensionId !== this.extensionId);100101// Clear all usages and re-add the filtered ones102this.queryService.authenticationUsageService.removeAccountUsage(this.providerId, this.accountName);103for (const usage of filteredUsages) {104this.queryService.authenticationUsageService.addAccountUsage(105this.providerId,106this.accountName,107usage.scopes || [],108usage.extensionId,109usage.extensionName110);111}112}113114setAsPreferred(): void {115this.queryService.authenticationExtensionsService.updateAccountPreference(116this.extensionId,117this.providerId,118{ label: this.accountName, id: this.accountName }119);120}121122isPreferred(): boolean {123const preferredAccount = this.queryService.authenticationExtensionsService.getAccountPreference(this.extensionId, this.providerId);124return preferredAccount === this.accountName;125}126127isTrusted(): boolean {128const allowedExtensions = this.queryService.authenticationAccessService.readAllowedExtensions(this.providerId, this.accountName);129const extension = allowedExtensions.find(ext => ext.id === this.extensionId);130return extension?.trusted === true;131}132}133134/**135* Implementation of account-MCP server query operations136*/137class AccountMcpServerQuery extends BaseQuery implements IAccountMcpServerQuery {138constructor(139providerId: string,140public readonly accountName: string,141public readonly mcpServerId: string,142queryService: AuthenticationQueryService143) {144super(providerId, queryService);145}146147isAccessAllowed(): boolean | undefined {148return this.queryService.authenticationMcpAccessService.isAccessAllowed(this.providerId, this.accountName, this.mcpServerId);149}150151setAccessAllowed(allowed: boolean, mcpServerName?: string): void {152this.queryService.authenticationMcpAccessService.updateAllowedMcpServers(153this.providerId,154this.accountName,155[{ id: this.mcpServerId, name: mcpServerName || this.mcpServerId, allowed }]156);157}158159addUsage(scopes: readonly string[], mcpServerName: string): void {160this.queryService.authenticationMcpUsageService.addAccountUsage(161this.providerId,162this.accountName,163scopes,164this.mcpServerId,165mcpServerName166);167}168169getUsage(): {170readonly mcpServerId: string;171readonly mcpServerName: string;172readonly scopes: readonly string[];173readonly lastUsed: number;174}[] {175const allUsages = this.queryService.authenticationMcpUsageService.readAccountUsages(this.providerId, this.accountName);176return allUsages177.filter(usage => usage.mcpServerId === this.mcpServerId)178.map(usage => ({179mcpServerId: usage.mcpServerId,180mcpServerName: usage.mcpServerName,181scopes: usage.scopes || [],182lastUsed: usage.lastUsed183}));184}185186removeUsage(): void {187// Get current usages, filter out this MCP server, and store the rest188const allUsages = this.queryService.authenticationMcpUsageService.readAccountUsages(this.providerId, this.accountName);189const filteredUsages = allUsages.filter(usage => usage.mcpServerId !== this.mcpServerId);190191// Clear all usages and re-add the filtered ones192this.queryService.authenticationMcpUsageService.removeAccountUsage(this.providerId, this.accountName);193for (const usage of filteredUsages) {194this.queryService.authenticationMcpUsageService.addAccountUsage(195this.providerId,196this.accountName,197usage.scopes || [],198usage.mcpServerId,199usage.mcpServerName200);201}202}203204setAsPreferred(): void {205this.queryService.authenticationMcpService.updateAccountPreference(206this.mcpServerId,207this.providerId,208{ label: this.accountName, id: this.accountName }209);210}211212isPreferred(): boolean {213const preferredAccount = this.queryService.authenticationMcpService.getAccountPreference(this.mcpServerId, this.providerId);214return preferredAccount === this.accountName;215}216217isTrusted(): boolean {218const allowedMcpServers = this.queryService.authenticationMcpAccessService.readAllowedMcpServers(this.providerId, this.accountName);219const mcpServer = allowedMcpServers.find(server => server.id === this.mcpServerId);220return mcpServer?.trusted === true;221}222}223224/**225* Implementation of account-extensions query operations226*/227class AccountExtensionsQuery extends BaseQuery implements IAccountExtensionsQuery {228constructor(229providerId: string,230public readonly accountName: string,231queryService: AuthenticationQueryService232) {233super(providerId, queryService);234}235236getAllowedExtensions(): { id: string; name: string; allowed?: boolean; lastUsed?: number; trusted?: boolean }[] {237const allowedExtensions = this.queryService.authenticationAccessService.readAllowedExtensions(this.providerId, this.accountName);238const usages = this.queryService.authenticationUsageService.readAccountUsages(this.providerId, this.accountName);239240return allowedExtensions241.filter(ext => ext.allowed !== false)242.map(ext => {243// Find the most recent usage for this extension244const extensionUsages = usages.filter(usage => usage.extensionId === ext.id);245const lastUsed = extensionUsages.length > 0 ? Math.max(...extensionUsages.map(u => u.lastUsed)) : undefined;246247// Check if trusted through the extension query248const extensionQuery = new AccountExtensionQuery(this.providerId, this.accountName, ext.id, this.queryService);249const trusted = extensionQuery.isTrusted();250251return {252id: ext.id,253name: ext.name,254allowed: ext.allowed,255lastUsed,256trusted257};258});259}260261allowAccess(extensionIds: string[]): void {262const extensionsToAllow = extensionIds.map(id => ({ id, name: id, allowed: true }));263this.queryService.authenticationAccessService.updateAllowedExtensions(this.providerId, this.accountName, extensionsToAllow);264}265266removeAccess(extensionIds: string[]): void {267const extensionsToRemove = extensionIds.map(id => ({ id, name: id, allowed: false }));268this.queryService.authenticationAccessService.updateAllowedExtensions(this.providerId, this.accountName, extensionsToRemove);269}270271forEach(callback: (extensionQuery: IAccountExtensionQuery) => void): void {272const usages = this.queryService.authenticationUsageService.readAccountUsages(this.providerId, this.accountName);273const allowedExtensions = this.queryService.authenticationAccessService.readAllowedExtensions(this.providerId, this.accountName);274275// Combine extensions from both usage and access data276const extensionIds = new Set<string>();277usages.forEach(usage => extensionIds.add(usage.extensionId));278allowedExtensions.forEach(ext => extensionIds.add(ext.id));279280for (const extensionId of extensionIds) {281const extensionQuery = new AccountExtensionQuery(this.providerId, this.accountName, extensionId, this.queryService);282callback(extensionQuery);283}284}285}286287/**288* Implementation of account-MCP servers query operations289*/290class AccountMcpServersQuery extends BaseQuery implements IAccountMcpServersQuery {291constructor(292providerId: string,293public readonly accountName: string,294queryService: AuthenticationQueryService295) {296super(providerId, queryService);297}298299getAllowedMcpServers(): { id: string; name: string; allowed?: boolean; lastUsed?: number; trusted?: boolean }[] {300return this.queryService.authenticationMcpAccessService.readAllowedMcpServers(this.providerId, this.accountName)301.filter(server => server.allowed !== false);302}303304allowAccess(mcpServerIds: string[]): void {305const mcpServersToAllow = mcpServerIds.map(id => ({ id, name: id, allowed: true }));306this.queryService.authenticationMcpAccessService.updateAllowedMcpServers(this.providerId, this.accountName, mcpServersToAllow);307}308309removeAccess(mcpServerIds: string[]): void {310const mcpServersToRemove = mcpServerIds.map(id => ({ id, name: id, allowed: false }));311this.queryService.authenticationMcpAccessService.updateAllowedMcpServers(this.providerId, this.accountName, mcpServersToRemove);312}313314forEach(callback: (mcpServerQuery: IAccountMcpServerQuery) => void): void {315const usages = this.queryService.authenticationMcpUsageService.readAccountUsages(this.providerId, this.accountName);316const allowedMcpServers = this.queryService.authenticationMcpAccessService.readAllowedMcpServers(this.providerId, this.accountName);317318// Combine MCP servers from both usage and access data319const mcpServerIds = new Set<string>();320usages.forEach(usage => mcpServerIds.add(usage.mcpServerId));321allowedMcpServers.forEach(server => mcpServerIds.add(server.id));322323for (const mcpServerId of mcpServerIds) {324const mcpServerQuery = new AccountMcpServerQuery(this.providerId, this.accountName, mcpServerId, this.queryService);325callback(mcpServerQuery);326}327}328}329330/**331* Implementation of account-entities query operations for type-agnostic operations332*/333class AccountEntitiesQuery extends BaseQuery implements IAccountEntitiesQuery {334constructor(335providerId: string,336public readonly accountName: string,337queryService: AuthenticationQueryService338) {339super(providerId, queryService);340}341342hasAnyUsage(): boolean {343// Check extension usage344const extensionUsages = this.queryService.authenticationUsageService.readAccountUsages(this.providerId, this.accountName);345if (extensionUsages.length > 0) {346return true;347}348349// Check MCP server usage350const mcpUsages = this.queryService.authenticationMcpUsageService.readAccountUsages(this.providerId, this.accountName);351if (mcpUsages.length > 0) {352return true;353}354355// Check extension access356const allowedExtensions = this.queryService.authenticationAccessService.readAllowedExtensions(this.providerId, this.accountName);357if (allowedExtensions.some(ext => ext.allowed !== false)) {358return true;359}360361// Check MCP server access362const allowedMcpServers = this.queryService.authenticationMcpAccessService.readAllowedMcpServers(this.providerId, this.accountName);363if (allowedMcpServers.some(server => server.allowed !== false)) {364return true;365}366367return false;368}369370getEntityCount(): { extensions: number; mcpServers: number; total: number } {371// Use the same logic as getAllEntities to count all entities with usage or access372const extensionUsages = this.queryService.authenticationUsageService.readAccountUsages(this.providerId, this.accountName);373const allowedExtensions = this.queryService.authenticationAccessService.readAllowedExtensions(this.providerId, this.accountName).filter(ext => ext.allowed);374const extensionIds = new Set<string>();375extensionUsages.forEach(usage => extensionIds.add(usage.extensionId));376allowedExtensions.forEach(ext => extensionIds.add(ext.id));377378const mcpUsages = this.queryService.authenticationMcpUsageService.readAccountUsages(this.providerId, this.accountName);379const allowedMcpServers = this.queryService.authenticationMcpAccessService.readAllowedMcpServers(this.providerId, this.accountName).filter(server => server.allowed);380const mcpServerIds = new Set<string>();381mcpUsages.forEach(usage => mcpServerIds.add(usage.mcpServerId));382allowedMcpServers.forEach(server => mcpServerIds.add(server.id));383384const extensionCount = extensionIds.size;385const mcpServerCount = mcpServerIds.size;386387return {388extensions: extensionCount,389mcpServers: mcpServerCount,390total: extensionCount + mcpServerCount391};392}393394removeAllAccess(): void {395// Remove all extension access396const extensionsQuery = new AccountExtensionsQuery(this.providerId, this.accountName, this.queryService);397const extensions = extensionsQuery.getAllowedExtensions();398const extensionIds = extensions.map(ext => ext.id);399if (extensionIds.length > 0) {400extensionsQuery.removeAccess(extensionIds);401}402403// Remove all MCP server access404const mcpServersQuery = new AccountMcpServersQuery(this.providerId, this.accountName, this.queryService);405const mcpServers = mcpServersQuery.getAllowedMcpServers();406const mcpServerIds = mcpServers.map(server => server.id);407if (mcpServerIds.length > 0) {408mcpServersQuery.removeAccess(mcpServerIds);409}410}411412forEach(callback: (entityId: string, entityType: 'extension' | 'mcpServer') => void): void {413// Iterate over extensions414const extensionsQuery = new AccountExtensionsQuery(this.providerId, this.accountName, this.queryService);415extensionsQuery.forEach(extensionQuery => {416callback(extensionQuery.extensionId, 'extension');417});418419// Iterate over MCP servers420const mcpServersQuery = new AccountMcpServersQuery(this.providerId, this.accountName, this.queryService);421mcpServersQuery.forEach(mcpServerQuery => {422callback(mcpServerQuery.mcpServerId, 'mcpServer');423});424}425}426427/**428* Implementation of account query operations429*/430class AccountQuery extends BaseQuery implements IAccountQuery {431constructor(432providerId: string,433public readonly accountName: string,434queryService: AuthenticationQueryService435) {436super(providerId, queryService);437}438439extension(extensionId: string): IAccountExtensionQuery {440return new AccountExtensionQuery(this.providerId, this.accountName, extensionId, this.queryService);441}442443mcpServer(mcpServerId: string): IAccountMcpServerQuery {444return new AccountMcpServerQuery(this.providerId, this.accountName, mcpServerId, this.queryService);445}446447extensions(): IAccountExtensionsQuery {448return new AccountExtensionsQuery(this.providerId, this.accountName, this.queryService);449}450451mcpServers(): IAccountMcpServersQuery {452return new AccountMcpServersQuery(this.providerId, this.accountName, this.queryService);453}454455entities(): IAccountEntitiesQuery {456return new AccountEntitiesQuery(this.providerId, this.accountName, this.queryService);457}458459remove(): void {460// Remove all extension access and usage data461this.queryService.authenticationAccessService.removeAllowedExtensions(this.providerId, this.accountName);462this.queryService.authenticationUsageService.removeAccountUsage(this.providerId, this.accountName);463464// Remove all MCP server access and usage data465this.queryService.authenticationMcpAccessService.removeAllowedMcpServers(this.providerId, this.accountName);466this.queryService.authenticationMcpUsageService.removeAccountUsage(this.providerId, this.accountName);467}468}469470/**471* Implementation of provider-extension query operations472*/473class ProviderExtensionQuery extends BaseQuery implements IProviderExtensionQuery {474constructor(475providerId: string,476public readonly extensionId: string,477queryService: AuthenticationQueryService478) {479super(providerId, queryService);480}481482getPreferredAccount(): string | undefined {483return this.queryService.authenticationExtensionsService.getAccountPreference(this.extensionId, this.providerId);484}485486setPreferredAccount(account: AuthenticationSessionAccount): void {487this.queryService.authenticationExtensionsService.updateAccountPreference(this.extensionId, this.providerId, account);488}489490removeAccountPreference(): void {491this.queryService.authenticationExtensionsService.removeAccountPreference(this.extensionId, this.providerId);492}493}494495/**496* Implementation of provider-MCP server query operations497*/498class ProviderMcpServerQuery extends BaseQuery implements IProviderMcpServerQuery {499constructor(500providerId: string,501public readonly mcpServerId: string,502queryService: AuthenticationQueryService503) {504super(providerId, queryService);505}506507async getLastUsedAccount(): Promise<string | undefined> {508try {509const accounts = await this.queryService.authenticationService.getAccounts(this.providerId);510let lastUsedAccount: string | undefined;511let lastUsedTime = 0;512513for (const account of accounts) {514const usages = this.queryService.authenticationMcpUsageService.readAccountUsages(this.providerId, account.label);515const mcpServerUsages = usages.filter(usage => usage.mcpServerId === this.mcpServerId);516517for (const usage of mcpServerUsages) {518if (usage.lastUsed > lastUsedTime) {519lastUsedTime = usage.lastUsed;520lastUsedAccount = account.label;521}522}523}524525return lastUsedAccount;526} catch {527return undefined;528}529}530531getPreferredAccount(): string | undefined {532return this.queryService.authenticationMcpService.getAccountPreference(this.mcpServerId, this.providerId);533}534535setPreferredAccount(account: AuthenticationSessionAccount): void {536this.queryService.authenticationMcpService.updateAccountPreference(this.mcpServerId, this.providerId, account);537}538539removeAccountPreference(): void {540this.queryService.authenticationMcpService.removeAccountPreference(this.mcpServerId, this.providerId);541}542543async getUsedAccounts(): Promise<string[]> {544try {545const accounts = await this.queryService.authenticationService.getAccounts(this.providerId);546const usedAccounts: string[] = [];547548for (const account of accounts) {549const usages = this.queryService.authenticationMcpUsageService.readAccountUsages(this.providerId, account.label);550if (usages.some(usage => usage.mcpServerId === this.mcpServerId)) {551usedAccounts.push(account.label);552}553}554555return usedAccounts;556} catch {557return [];558}559}560}561562/**563* Implementation of provider query operations564*/565class ProviderQuery extends BaseQuery implements IProviderQuery {566constructor(567providerId: string,568queryService: AuthenticationQueryService569) {570super(providerId, queryService);571}572573account(accountName: string): IAccountQuery {574return new AccountQuery(this.providerId, accountName, this.queryService);575}576577extension(extensionId: string): IProviderExtensionQuery {578return new ProviderExtensionQuery(this.providerId, extensionId, this.queryService);579}580581mcpServer(mcpServerId: string): IProviderMcpServerQuery {582return new ProviderMcpServerQuery(this.providerId, mcpServerId, this.queryService);583}584585async getActiveEntities(): Promise<IActiveEntities> {586const extensions: string[] = [];587const mcpServers: string[] = [];588589try {590const accounts = await this.queryService.authenticationService.getAccounts(this.providerId);591592for (const account of accounts) {593// Get extension usages594const extensionUsages = this.queryService.authenticationUsageService.readAccountUsages(this.providerId, account.label);595for (const usage of extensionUsages) {596if (!extensions.includes(usage.extensionId)) {597extensions.push(usage.extensionId);598}599}600601// Get MCP server usages602const mcpUsages = this.queryService.authenticationMcpUsageService.readAccountUsages(this.providerId, account.label);603for (const usage of mcpUsages) {604if (!mcpServers.includes(usage.mcpServerId)) {605mcpServers.push(usage.mcpServerId);606}607}608}609} catch {610// Return empty arrays if there's an error611}612613return { extensions, mcpServers };614}615616async getAccountNames(): Promise<string[]> {617try {618const accounts = await this.queryService.authenticationService.getAccounts(this.providerId);619return accounts.map(account => account.label);620} catch {621return [];622}623}624625async getUsageStats(): Promise<IAuthenticationUsageStats> {626const recentActivity: { accountName: string; lastUsed: number; usageCount: number }[] = [];627let totalSessions = 0;628let totalAccounts = 0;629630try {631const accounts = await this.queryService.authenticationService.getAccounts(this.providerId);632totalAccounts = accounts.length;633634for (const account of accounts) {635const extensionUsages = this.queryService.authenticationUsageService.readAccountUsages(this.providerId, account.label);636const mcpUsages = this.queryService.authenticationMcpUsageService.readAccountUsages(this.providerId, account.label);637638const allUsages = [...extensionUsages, ...mcpUsages];639const usageCount = allUsages.length;640const lastUsed = Math.max(...allUsages.map(u => u.lastUsed), 0);641642if (usageCount > 0) {643recentActivity.push({ accountName: account.label, lastUsed, usageCount });644}645}646647// Sort by most recent activity648recentActivity.sort((a, b) => b.lastUsed - a.lastUsed);649650// Count total sessions (approximate)651totalSessions = recentActivity.reduce((sum, activity) => sum + activity.usageCount, 0);652} catch {653// Return default stats if there's an error654}655656return { totalSessions, totalAccounts, recentActivity };657}658659async forEachAccount(callback: (accountQuery: IAccountQuery) => void): Promise<void> {660try {661const accounts = await this.queryService.authenticationService.getAccounts(this.providerId);662for (const account of accounts) {663const accountQuery = new AccountQuery(this.providerId, account.label, this.queryService);664callback(accountQuery);665}666} catch {667// Silently handle errors in enumeration668}669}670}671672/**673* Implementation of extension query operations (cross-provider)674*/675class ExtensionQuery implements IExtensionQuery {676constructor(677public readonly extensionId: string,678private readonly queryService: AuthenticationQueryService679) { }680681async getProvidersWithAccess(includeInternal?: boolean): Promise<string[]> {682const providersWithAccess: string[] = [];683const providerIds = this.queryService.authenticationService.getProviderIds();684685for (const providerId of providerIds) {686// Skip internal providers unless explicitly requested687if (!includeInternal && providerId.startsWith(INTERNAL_AUTH_PROVIDER_PREFIX)) {688continue;689}690691try {692const accounts = await this.queryService.authenticationService.getAccounts(providerId);693const hasAccess = accounts.some(account => {694const accessAllowed = this.queryService.authenticationAccessService.isAccessAllowed(providerId, account.label, this.extensionId);695return accessAllowed === true;696});697698if (hasAccess) {699providersWithAccess.push(providerId);700}701} catch {702// Skip providers that error703}704}705706return providersWithAccess;707}708709getAllAccountPreferences(includeInternal?: boolean): Map<string, string> {710const preferences = new Map<string, string>();711const providerIds = this.queryService.authenticationService.getProviderIds();712713for (const providerId of providerIds) {714// Skip internal providers unless explicitly requested715if (!includeInternal && providerId.startsWith(INTERNAL_AUTH_PROVIDER_PREFIX)) {716continue;717}718719const preferredAccount = this.queryService.authenticationExtensionsService.getAccountPreference(this.extensionId, providerId);720if (preferredAccount) {721preferences.set(providerId, preferredAccount);722}723}724725return preferences;726}727728provider(providerId: string): IProviderExtensionQuery {729return new ProviderExtensionQuery(providerId, this.extensionId, this.queryService);730}731}732733/**734* Implementation of MCP server query operations (cross-provider)735*/736class McpServerQuery implements IMcpServerQuery {737constructor(738public readonly mcpServerId: string,739private readonly queryService: AuthenticationQueryService740) { }741742async getProvidersWithAccess(includeInternal?: boolean): Promise<string[]> {743const providersWithAccess: string[] = [];744const providerIds = this.queryService.authenticationService.getProviderIds();745746for (const providerId of providerIds) {747// Skip internal providers unless explicitly requested748if (!includeInternal && providerId.startsWith(INTERNAL_AUTH_PROVIDER_PREFIX)) {749continue;750}751752try {753const accounts = await this.queryService.authenticationService.getAccounts(providerId);754const hasAccess = accounts.some(account => {755const accessAllowed = this.queryService.authenticationMcpAccessService.isAccessAllowed(providerId, account.label, this.mcpServerId);756return accessAllowed === true;757});758759if (hasAccess) {760providersWithAccess.push(providerId);761}762} catch {763// Skip providers that error764}765}766767return providersWithAccess;768}769770getAllAccountPreferences(includeInternal?: boolean): Map<string, string> {771const preferences = new Map<string, string>();772const providerIds = this.queryService.authenticationService.getProviderIds();773774for (const providerId of providerIds) {775// Skip internal providers unless explicitly requested776if (!includeInternal && providerId.startsWith(INTERNAL_AUTH_PROVIDER_PREFIX)) {777continue;778}779780const preferredAccount = this.queryService.authenticationMcpService.getAccountPreference(this.mcpServerId, providerId);781if (preferredAccount) {782preferences.set(providerId, preferredAccount);783}784}785786return preferences;787}788789provider(providerId: string): IProviderMcpServerQuery {790return new ProviderMcpServerQuery(providerId, this.mcpServerId, this.queryService);791}792}793794/**795* Main implementation of the authentication query service796*/797export class AuthenticationQueryService extends Disposable implements IAuthenticationQueryService {798declare readonly _serviceBrand: undefined;799800private readonly _onDidChangePreferences = this._register(new Emitter<{801readonly providerId: string;802readonly entityType: 'extension' | 'mcpServer';803readonly entityIds: string[];804}>());805readonly onDidChangePreferences = this._onDidChangePreferences.event;806807private readonly _onDidChangeAccess = this._register(new Emitter<{808readonly providerId: string;809readonly accountName: string;810}>());811readonly onDidChangeAccess = this._onDidChangeAccess.event;812813constructor(814@IAuthenticationService public readonly authenticationService: IAuthenticationService,815@IAuthenticationUsageService public readonly authenticationUsageService: IAuthenticationUsageService,816@IAuthenticationMcpUsageService public readonly authenticationMcpUsageService: IAuthenticationMcpUsageService,817@IAuthenticationAccessService public readonly authenticationAccessService: IAuthenticationAccessService,818@IAuthenticationMcpAccessService public readonly authenticationMcpAccessService: IAuthenticationMcpAccessService,819@IAuthenticationExtensionsService public readonly authenticationExtensionsService: IAuthenticationExtensionsService,820@IAuthenticationMcpService public readonly authenticationMcpService: IAuthenticationMcpService,821@ILogService public readonly logService: ILogService822) {823super();824825// Forward events from underlying services826this._register(this.authenticationExtensionsService.onDidChangeAccountPreference(e => {827this._onDidChangePreferences.fire({828providerId: e.providerId,829entityType: 'extension',830entityIds: e.extensionIds831});832}));833834this._register(this.authenticationMcpService.onDidChangeAccountPreference(e => {835this._onDidChangePreferences.fire({836providerId: e.providerId,837entityType: 'mcpServer',838entityIds: e.mcpServerIds839});840}));841842this._register(this.authenticationAccessService.onDidChangeExtensionSessionAccess(e => {843this._onDidChangeAccess.fire({844providerId: e.providerId,845accountName: e.accountName846});847}));848849this._register(this.authenticationMcpAccessService.onDidChangeMcpSessionAccess(e => {850this._onDidChangeAccess.fire({851providerId: e.providerId,852accountName: e.accountName853});854}));855}856857provider(providerId: string): IProviderQuery {858return new ProviderQuery(providerId, this);859}860861extension(extensionId: string): IExtensionQuery {862return new ExtensionQuery(extensionId, this);863}864865mcpServer(mcpServerId: string): IMcpServerQuery {866return new McpServerQuery(mcpServerId, this);867}868869getProviderIds(includeInternal?: boolean): string[] {870return this.authenticationService.getProviderIds().filter(providerId => {871// Filter out internal providers unless explicitly included872return includeInternal || !providerId.startsWith(INTERNAL_AUTH_PROVIDER_PREFIX);873});874}875876async clearAllData(confirmation: 'CLEAR_ALL_AUTH_DATA', includeInternal: boolean = true): Promise<void> {877if (confirmation !== 'CLEAR_ALL_AUTH_DATA') {878throw new Error('Must provide confirmation string to clear all authentication data');879}880881const providerIds = this.getProviderIds(includeInternal);882883for (const providerId of providerIds) {884try {885const accounts = await this.authenticationService.getAccounts(providerId);886887for (const account of accounts) {888// Clear extension data889this.authenticationAccessService.removeAllowedExtensions(providerId, account.label);890this.authenticationUsageService.removeAccountUsage(providerId, account.label);891892// Clear MCP server data893this.authenticationMcpAccessService.removeAllowedMcpServers(providerId, account.label);894this.authenticationMcpUsageService.removeAccountUsage(providerId, account.label);895}896} catch (error) {897this.logService.error(`Error clearing data for provider ${providerId}:`, error);898}899}900901this.logService.info('All authentication data cleared');902}903}904905registerSingleton(IAuthenticationQueryService, AuthenticationQueryService, InstantiationType.Delayed);906907908