mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 21:03:05 -07:00
fix: preserve path components in OAuth issuer URLs (#12448)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Gregory Shikhman <cornmander@cornmander.com>
This commit is contained in:
@@ -44,9 +44,10 @@ import type {
|
||||
import { MCPOAuthProvider } from './oauth-provider.js';
|
||||
import type { OAuthToken } from './token-storage/types.js';
|
||||
import { MCPOAuthTokenStorage } from './oauth-token-storage.js';
|
||||
import type {
|
||||
OAuthAuthorizationServerMetadata,
|
||||
OAuthProtectedResourceMetadata,
|
||||
import {
|
||||
OAuthUtils,
|
||||
type OAuthAuthorizationServerMetadata,
|
||||
type OAuthProtectedResourceMetadata,
|
||||
} from './oauth-utils.js';
|
||||
import { coreEvents } from '../utils/events.js';
|
||||
|
||||
@@ -1369,4 +1370,98 @@ describe('MCPOAuthProvider', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('issuer discovery conformance', () => {
|
||||
const registrationMetadata: OAuthAuthorizationServerMetadata = {
|
||||
issuer: 'http://localhost:8888/realms/my-realm',
|
||||
authorization_endpoint:
|
||||
'http://localhost:8888/realms/my-realm/protocol/openid-connect/auth',
|
||||
token_endpoint:
|
||||
'http://localhost:8888/realms/my-realm/protocol/openid-connect/token',
|
||||
registration_endpoint:
|
||||
'http://localhost:8888/realms/my-realm/clients-registrations/openid-connect',
|
||||
};
|
||||
|
||||
it('falls back to path-based issuer when origin discovery fails', async () => {
|
||||
const authProvider = new MCPOAuthProvider();
|
||||
const providerWithAccess = authProvider as unknown as {
|
||||
discoverAuthServerMetadataForRegistration: (
|
||||
authorizationUrl: string,
|
||||
) => Promise<{
|
||||
issuerUrl: string;
|
||||
metadata: OAuthAuthorizationServerMetadata;
|
||||
}>;
|
||||
};
|
||||
|
||||
vi.spyOn(
|
||||
OAuthUtils,
|
||||
'discoverAuthorizationServerMetadata',
|
||||
).mockImplementation(async (issuer) => {
|
||||
if (issuer === 'http://localhost:8888/realms/my-realm') {
|
||||
return registrationMetadata;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
const result =
|
||||
await providerWithAccess.discoverAuthServerMetadataForRegistration(
|
||||
'http://localhost:8888/realms/my-realm/protocol/openid-connect/auth',
|
||||
);
|
||||
|
||||
expect(
|
||||
vi.mocked(OAuthUtils.discoverAuthorizationServerMetadata).mock.calls,
|
||||
).toEqual([
|
||||
['http://localhost:8888'],
|
||||
['http://localhost:8888/realms/my-realm'],
|
||||
]);
|
||||
expect(result.issuerUrl).toBe('http://localhost:8888/realms/my-realm');
|
||||
expect(result.metadata).toBe(registrationMetadata);
|
||||
});
|
||||
|
||||
it('trims versioned segments from authorization endpoints', async () => {
|
||||
const authProvider = new MCPOAuthProvider();
|
||||
const providerWithAccess = authProvider as unknown as {
|
||||
discoverAuthServerMetadataForRegistration: (
|
||||
authorizationUrl: string,
|
||||
) => Promise<{
|
||||
issuerUrl: string;
|
||||
metadata: OAuthAuthorizationServerMetadata;
|
||||
}>;
|
||||
};
|
||||
|
||||
const oktaMetadata: OAuthAuthorizationServerMetadata = {
|
||||
issuer: 'https://auth.okta.local/oauth2/default',
|
||||
authorization_endpoint:
|
||||
'https://auth.okta.local/oauth2/default/v1/authorize',
|
||||
token_endpoint: 'https://auth.okta.local/oauth2/default/v1/token',
|
||||
registration_endpoint:
|
||||
'https://auth.okta.local/oauth2/default/v1/register',
|
||||
};
|
||||
|
||||
const attempts: string[] = [];
|
||||
vi.spyOn(
|
||||
OAuthUtils,
|
||||
'discoverAuthorizationServerMetadata',
|
||||
).mockImplementation(async (issuer) => {
|
||||
attempts.push(issuer);
|
||||
if (issuer === 'https://auth.okta.local/oauth2/default') {
|
||||
return oktaMetadata;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
const result =
|
||||
await providerWithAccess.discoverAuthServerMetadataForRegistration(
|
||||
'https://auth.okta.local/oauth2/default/v1/authorize',
|
||||
);
|
||||
|
||||
expect(attempts).toEqual([
|
||||
'https://auth.okta.local',
|
||||
'https://auth.okta.local/oauth2/default/v1',
|
||||
'https://auth.okta.local/oauth2/default',
|
||||
]);
|
||||
expect(result.issuerUrl).toBe('https://auth.okta.local/oauth2/default');
|
||||
expect(result.metadata).toBe(oktaMetadata);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user