Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/authentication/browser/authentication.contribution.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Disposable } from '../../../../base/common/lifecycle.js';
7
import { localize } from '../../../../nls.js';
8
import { registerAction2 } from '../../../../platform/actions/common/actions.js';
9
import { CommandsRegistry } from '../../../../platform/commands/common/commands.js';
10
import { IExtensionManifest } from '../../../../platform/extensions/common/extensions.js';
11
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
12
import { Registry } from '../../../../platform/registry/common/platform.js';
13
import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js';
14
import { SignOutOfAccountAction } from './actions/signOutOfAccountAction.js';
15
import { IBrowserWorkbenchEnvironmentService } from '../../../services/environment/browser/environmentService.js';
16
import { Extensions, IExtensionFeatureTableRenderer, IExtensionFeaturesRegistry, IRenderedData, IRowData, ITableData } from '../../../services/extensionManagement/common/extensionFeatures.js';
17
import { ManageTrustedExtensionsForAccountAction } from './actions/manageTrustedExtensionsForAccountAction.js';
18
import { ManageAccountPreferencesForExtensionAction } from './actions/manageAccountPreferencesForExtensionAction.js';
19
import { IAuthenticationUsageService } from '../../../services/authentication/browser/authenticationUsageService.js';
20
import { ManageAccountPreferencesForMcpServerAction } from './actions/manageAccountPreferencesForMcpServerAction.js';
21
import { ManageTrustedMcpServersForAccountAction } from './actions/manageTrustedMcpServersForAccountAction.js';
22
import { RemoveDynamicAuthenticationProvidersAction } from './actions/manageDynamicAuthenticationProvidersAction.js';
23
import { IAuthenticationQueryService } from '../../../services/authentication/common/authenticationQuery.js';
24
import { IMcpRegistry } from '../../mcp/common/mcpRegistryTypes.js';
25
import { autorun } from '../../../../base/common/observable.js';
26
import { IAuthenticationService } from '../../../services/authentication/common/authentication.js';
27
import { Event } from '../../../../base/common/event.js';
28
29
const codeExchangeProxyCommand = CommandsRegistry.registerCommand('workbench.getCodeExchangeProxyEndpoints', function (accessor, _) {
30
const environmentService = accessor.get(IBrowserWorkbenchEnvironmentService);
31
return environmentService.options?.codeExchangeProxyEndpoints;
32
});
33
34
class AuthenticationDataRenderer extends Disposable implements IExtensionFeatureTableRenderer {
35
36
readonly type = 'table';
37
38
shouldRender(manifest: IExtensionManifest): boolean {
39
return !!manifest.contributes?.authentication;
40
}
41
42
render(manifest: IExtensionManifest): IRenderedData<ITableData> {
43
const authentication = manifest.contributes?.authentication || [];
44
if (!authentication.length) {
45
return { data: { headers: [], rows: [] }, dispose: () => { } };
46
}
47
48
const headers = [
49
localize('authenticationlabel', "Label"),
50
localize('authenticationid', "ID"),
51
localize('authenticationMcpAuthorizationServers', "MCP Authorization Servers")
52
];
53
54
const rows: IRowData[][] = authentication
55
.sort((a, b) => a.label.localeCompare(b.label))
56
.map(auth => {
57
return [
58
auth.label,
59
auth.id,
60
(auth.authorizationServerGlobs ?? []).join(',\n')
61
];
62
});
63
64
return {
65
data: {
66
headers,
67
rows
68
},
69
dispose: () => { }
70
};
71
}
72
}
73
74
const extensionFeature = Registry.as<IExtensionFeaturesRegistry>(Extensions.ExtensionFeaturesRegistry).registerExtensionFeature({
75
id: 'authentication',
76
label: localize('authentication', "Authentication"),
77
access: {
78
canToggle: false
79
},
80
renderer: new SyncDescriptor(AuthenticationDataRenderer),
81
});
82
83
class AuthenticationContribution extends Disposable implements IWorkbenchContribution {
84
static ID = 'workbench.contrib.authentication';
85
86
constructor() {
87
super();
88
this._register(codeExchangeProxyCommand);
89
this._register(extensionFeature);
90
91
this._registerActions();
92
}
93
94
private _registerActions(): void {
95
this._register(registerAction2(SignOutOfAccountAction));
96
this._register(registerAction2(ManageTrustedExtensionsForAccountAction));
97
this._register(registerAction2(ManageAccountPreferencesForExtensionAction));
98
this._register(registerAction2(ManageTrustedMcpServersForAccountAction));
99
this._register(registerAction2(ManageAccountPreferencesForMcpServerAction));
100
this._register(registerAction2(RemoveDynamicAuthenticationProvidersAction));
101
}
102
}
103
104
class AuthenticationUsageContribution implements IWorkbenchContribution {
105
static ID = 'workbench.contrib.authenticationUsage';
106
107
constructor(
108
@IAuthenticationUsageService private readonly _authenticationUsageService: IAuthenticationUsageService,
109
) {
110
this._initializeExtensionUsageCache();
111
}
112
113
private async _initializeExtensionUsageCache() {
114
await this._authenticationUsageService.initializeExtensionUsageCache();
115
}
116
}
117
118
// class AuthenticationExtensionsContribution extends Disposable implements IWorkbenchContribution {
119
// static ID = 'workbench.contrib.authenticationExtensions';
120
121
// constructor(
122
// @IExtensionService private readonly _extensionService: IExtensionService,
123
// @IAuthenticationQueryService private readonly _authenticationQueryService: IAuthenticationQueryService,
124
// @IAuthenticationService private readonly _authenticationService: IAuthenticationService
125
// ) {
126
// super();
127
// void this.run();
128
// this._register(this._extensionService.onDidChangeExtensions(this._onDidChangeExtensions, this));
129
// this._register(
130
// Event.any(
131
// this._authenticationService.onDidChangeDeclaredProviders,
132
// this._authenticationService.onDidRegisterAuthenticationProvider
133
// )(() => this._cleanupRemovedExtensions())
134
// );
135
// }
136
137
// async run(): Promise<void> {
138
// await this._extensionService.whenInstalledExtensionsRegistered();
139
// this._cleanupRemovedExtensions();
140
// }
141
142
// private _onDidChangeExtensions(delta: { readonly added: readonly IExtensionDescription[]; readonly removed: readonly IExtensionDescription[] }): void {
143
// if (delta.removed.length > 0) {
144
// this._cleanupRemovedExtensions(delta.removed);
145
// }
146
// }
147
148
// private _cleanupRemovedExtensions(removedExtensions?: readonly IExtensionDescription[]): void {
149
// const extensionIdsToRemove = removedExtensions
150
// ? new Set(removedExtensions.map(e => e.identifier.value))
151
// : new Set(this._extensionService.extensions.map(e => e.identifier.value));
152
153
// // If we are cleaning up specific removed extensions, we only remove those.
154
// const isTargetedCleanup = !!removedExtensions;
155
156
// const providerIds = this._authenticationQueryService.getProviderIds();
157
// for (const providerId of providerIds) {
158
// this._authenticationQueryService.provider(providerId).forEachAccount(account => {
159
// account.extensions().forEach(extension => {
160
// const shouldRemove = isTargetedCleanup
161
// ? extensionIdsToRemove.has(extension.extensionId)
162
// : !extensionIdsToRemove.has(extension.extensionId);
163
164
// if (shouldRemove) {
165
// extension.removeUsage();
166
// extension.setAccessAllowed(false);
167
// }
168
// });
169
// });
170
// }
171
// }
172
// }
173
174
class AuthenticationMcpContribution extends Disposable implements IWorkbenchContribution {
175
static ID = 'workbench.contrib.authenticationMcp';
176
177
constructor(
178
@IMcpRegistry private readonly _mcpRegistry: IMcpRegistry,
179
@IAuthenticationQueryService private readonly _authenticationQueryService: IAuthenticationQueryService,
180
@IAuthenticationService private readonly _authenticationService: IAuthenticationService
181
) {
182
super();
183
this._cleanupRemovedMcpServers();
184
185
// Listen for MCP collections changes using autorun with observables
186
this._register(autorun(reader => {
187
// Read the collections observable to register dependency
188
this._mcpRegistry.collections.read(reader);
189
// Schedule cleanup for next tick to avoid running during observable updates
190
queueMicrotask(() => this._cleanupRemovedMcpServers());
191
}));
192
this._register(
193
Event.any(
194
this._authenticationService.onDidChangeDeclaredProviders,
195
this._authenticationService.onDidRegisterAuthenticationProvider
196
)(() => this._cleanupRemovedMcpServers())
197
);
198
}
199
200
private _cleanupRemovedMcpServers(): void {
201
const currentServerIds = new Set(this._mcpRegistry.collections.get().flatMap(c => c.serverDefinitions.get()).map(s => s.id));
202
const providerIds = this._authenticationQueryService.getProviderIds();
203
for (const providerId of providerIds) {
204
this._authenticationQueryService.provider(providerId).forEachAccount(account => {
205
account.mcpServers().forEach(server => {
206
if (!currentServerIds.has(server.mcpServerId)) {
207
server.removeUsage();
208
server.setAccessAllowed(false);
209
}
210
});
211
});
212
}
213
}
214
}
215
216
registerWorkbenchContribution2(AuthenticationContribution.ID, AuthenticationContribution, WorkbenchPhase.AfterRestored);
217
registerWorkbenchContribution2(AuthenticationUsageContribution.ID, AuthenticationUsageContribution, WorkbenchPhase.Eventually);
218
// registerWorkbenchContribution2(AuthenticationExtensionsContribution.ID, AuthenticationExtensionsContribution, WorkbenchPhase.Eventually);
219
registerWorkbenchContribution2(AuthenticationMcpContribution.ID, AuthenticationMcpContribution, WorkbenchPhase.Eventually);
220
221