Merge remote-tracking branch 'origin/v2/main' into 1579-wave-1
# Conflicts: # clients/cli/package-lock.json # clients/cli/package.json # clients/web/src/App.tsx # clients/web/src/lib/environmentFactory.test.ts # clients/web/src/lib/environmentFactory.ts # clients/web/src/lib/remoteOAuthStorage.test.ts # clients/web/src/lib/remoteOAuthStorage.ts # clients/web/src/test/core/auth/connection-state.test.ts # clients/web/src/test/core/auth/providers.test.ts # clients/web/src/test/core/auth/storage-browser.test.ts # clients/web/src/test/core/auth/storage-remote.test.ts # clients/web/src/test/core/mcp/oauthManager.test.ts # clients/web/src/test/integration/auth/node/storage.test.ts # clients/web/src/test/integration/storage/adapters.test.ts # clients/web/src/utils/clearServerOAuthState.test.ts # clients/web/src/utils/clearServerOAuthState.ts # core/auth/connection-state.ts # core/auth/oauth-storage.ts # core/auth/providers.ts # core/auth/storage.ts # core/auth/store.ts # core/storage/adapters/remote-storage.ts
This commit is contained in:
commit
32a3610737
2 changed files with 5046 additions and 3271 deletions
|
|
@ -3064,8 +3064,8 @@ export class InspectorClient extends InspectorClientEventTarget {
|
|||
/**
|
||||
* Clears OAuth tokens and client information
|
||||
*/
|
||||
clearOAuthTokens(): void {
|
||||
this.oauthManager?.clearOAuthTokens();
|
||||
async clearOAuthTokens(): Promise<void> {
|
||||
await this.oauthManager?.clearOAuthTokens();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -139,7 +139,8 @@ export class OAuthManager {
|
|||
|
||||
provider.setEventTarget(this.params.getEventTarget());
|
||||
|
||||
const storedScope = this.oauthConfig.storage.getScope(serverUrl);
|
||||
await provider.prepareForAuth();
|
||||
const storedScope = provider.scope;
|
||||
if (storedScope === undefined && this.oauthConfig.scope) {
|
||||
await provider.saveScope(this.oauthConfig.scope);
|
||||
}
|
||||
|
|
@ -162,7 +163,7 @@ export class OAuthManager {
|
|||
return this.oauthConfig.enterpriseManaged === true;
|
||||
}
|
||||
|
||||
private getEmaFlowConfig(): EmaFlowConfig {
|
||||
private async getEmaFlowConfig(): Promise<EmaFlowConfig> {
|
||||
if (!this.oauthConfig.storage || !this.oauthConfig.redirectUrlProvider) {
|
||||
throw new Error(
|
||||
"OAuth environment components (storage, redirectUrlProvider) are required.",
|
||||
|
|
@ -177,16 +178,17 @@ export class OAuthManager {
|
|||
: "not_configured",
|
||||
);
|
||||
}
|
||||
const storedScope = await this.oauthConfig.storage.getScope(
|
||||
this.getServerUrl(),
|
||||
);
|
||||
return {
|
||||
serverUrl: this.getServerUrl(),
|
||||
idp,
|
||||
resourceClientId: this.oauthConfig.clientId,
|
||||
resourceClientSecret: this.oauthConfig.clientSecret,
|
||||
scope:
|
||||
computeScopeUnion(
|
||||
this.oauthConfig.scope,
|
||||
this.oauthConfig.storage.getScope(this.getServerUrl()),
|
||||
) || this.oauthConfig.scope,
|
||||
computeScopeUnion(this.oauthConfig.scope, storedScope) ||
|
||||
this.oauthConfig.scope,
|
||||
redirectUrl: this.oauthConfig.redirectUrlProvider.getRedirectUrl(),
|
||||
storage: this.oauthConfig.storage,
|
||||
fetchFn: this.params.effectiveAuthFetch,
|
||||
|
|
@ -196,14 +198,14 @@ export class OAuthManager {
|
|||
/** Attempt silent EMA (cached IdP session + legs 2–3). */
|
||||
async trySilentEnterpriseManagedAuth(): Promise<boolean> {
|
||||
if (!this.isEnterpriseManaged()) return false;
|
||||
const result = await trySilentEmaAuth(this.getEmaFlowConfig());
|
||||
const result = await trySilentEmaAuth(await this.getEmaFlowConfig());
|
||||
if (result.status === "success") return true;
|
||||
if (result.status === "mint_failed") throw result.error;
|
||||
return false;
|
||||
}
|
||||
|
||||
private async authenticateEnterpriseManaged(): Promise<URL | undefined> {
|
||||
const config = this.getEmaFlowConfig();
|
||||
const config = await this.getEmaFlowConfig();
|
||||
const silent = await trySilentEmaAuth(config);
|
||||
if (silent.status === "success") {
|
||||
return undefined;
|
||||
|
|
@ -283,11 +285,12 @@ export class OAuthManager {
|
|||
): Promise<void> {
|
||||
try {
|
||||
if (this.isEnterpriseManaged()) {
|
||||
const emaConfig = await this.getEmaFlowConfig();
|
||||
const scopeForMint =
|
||||
this.pendingAuthorizationScope ?? this.getEmaFlowConfig().scope;
|
||||
this.pendingAuthorizationScope ?? emaConfig.scope;
|
||||
const config = scopeForMint
|
||||
? { ...this.getEmaFlowConfig(), scope: scopeForMint }
|
||||
: this.getEmaFlowConfig();
|
||||
? { ...emaConfig, scope: scopeForMint }
|
||||
: emaConfig;
|
||||
const tokens = await completeEmaIdpAuthorizationAndMint(
|
||||
config,
|
||||
authorizationCode,
|
||||
|
|
@ -387,13 +390,13 @@ export class OAuthManager {
|
|||
}
|
||||
}
|
||||
|
||||
clearOAuthTokens(): void {
|
||||
async clearOAuthTokens(): Promise<void> {
|
||||
if (!this.oauthConfig?.storage) {
|
||||
return;
|
||||
}
|
||||
|
||||
const serverUrl = this.getServerUrl();
|
||||
this.oauthConfig.storage.clear(serverUrl);
|
||||
await this.oauthConfig.storage.clear(serverUrl);
|
||||
|
||||
this.oauthFlowState = null;
|
||||
this.pendingAuthorizationScope = undefined;
|
||||
|
|
@ -446,7 +449,7 @@ export class OAuthManager {
|
|||
*/
|
||||
async refreshEnterpriseManagedTokens(): Promise<boolean> {
|
||||
if (!this.isEnterpriseManaged()) return false;
|
||||
const tokens = await refreshEmaResourceTokens(this.getEmaFlowConfig());
|
||||
const tokens = await refreshEmaResourceTokens(await this.getEmaFlowConfig());
|
||||
return tokens !== undefined;
|
||||
}
|
||||
|
||||
|
|
@ -492,7 +495,7 @@ export class OAuthManager {
|
|||
}
|
||||
|
||||
const effectiveScope = resolveEffectiveGrantedScope(
|
||||
storage.getScope(serverUrl),
|
||||
await storage.getScope(serverUrl),
|
||||
tokens.scope,
|
||||
);
|
||||
return !isStrictScopeSuperset(scopeForAuth, effectiveScope);
|
||||
|
|
@ -568,7 +571,7 @@ export class OAuthManager {
|
|||
}
|
||||
|
||||
const previousScope = computeScopeUnion(
|
||||
storage?.getScope(serverUrl),
|
||||
storage ? await storage.getScope(serverUrl) : undefined,
|
||||
grantedTokenScope,
|
||||
);
|
||||
const requiredFromChallenge =
|
||||
|
|
@ -605,8 +608,10 @@ export class OAuthManager {
|
|||
return this.oauthConfig.scope?.trim() || undefined;
|
||||
}
|
||||
|
||||
private emaFlowConfigForChallenge(challenge: AuthChallenge): EmaFlowConfig {
|
||||
const base = this.getEmaFlowConfig();
|
||||
private async emaFlowConfigForChallenge(
|
||||
challenge: AuthChallenge,
|
||||
): Promise<EmaFlowConfig> {
|
||||
const base = await this.getEmaFlowConfig();
|
||||
const enriched = challenge.authorizationScopes;
|
||||
if (enriched && enriched.length > 0) {
|
||||
return { ...base, scope: enriched.join(" ") };
|
||||
|
|
@ -626,7 +631,7 @@ export class OAuthManager {
|
|||
return { kind: "step_up_confirm", challenge: enriched };
|
||||
}
|
||||
|
||||
const config = this.emaFlowConfigForChallenge(enriched);
|
||||
const config = await this.emaFlowConfigForChallenge(enriched);
|
||||
|
||||
if (enriched.reason === "insufficient_scope") {
|
||||
const silent = await trySilentEmaAuth(config);
|
||||
|
|
@ -861,7 +866,10 @@ export class OAuthManager {
|
|||
> {
|
||||
const provider = await this.createOAuthProvider();
|
||||
if (this.isEnterpriseManaged()) {
|
||||
return new EmaTransportOAuthProvider(provider, this.getEmaFlowConfig());
|
||||
return new EmaTransportOAuthProvider(
|
||||
provider,
|
||||
await this.getEmaFlowConfig(),
|
||||
);
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue