mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
feat(core): third-party applications are not allowed for token exchange (#6100)
* feat(core,schemas): token exchange grant * feat(core): third-party applications are not allowed for token exchange
This commit is contained in:
parent
81c014173c
commit
2ce6ba3447
3 changed files with 45 additions and 2 deletions
|
@ -14,6 +14,7 @@ const { jest } = import.meta;
|
|||
const noop = async () => {};
|
||||
const findSubjectToken = jest.fn();
|
||||
const updateSubjectTokenById = jest.fn();
|
||||
const findApplicationById = jest.fn().mockResolvedValue(mockApplication);
|
||||
|
||||
const mockTenant = new MockTenant(undefined, {
|
||||
subjectTokens: {
|
||||
|
@ -21,7 +22,7 @@ const mockTenant = new MockTenant(undefined, {
|
|||
updateSubjectTokenById,
|
||||
},
|
||||
applications: {
|
||||
findApplicationById: jest.fn().mockResolvedValue(mockApplication),
|
||||
findApplicationById,
|
||||
},
|
||||
});
|
||||
const mockHandler = (tenant = mockTenant) => {
|
||||
|
@ -78,11 +79,21 @@ afterAll(() => {
|
|||
});
|
||||
|
||||
describe('token exchange', () => {
|
||||
afterEach(() => {
|
||||
findApplicationById.mockClear();
|
||||
});
|
||||
|
||||
it('should throw when client is not available', async () => {
|
||||
const ctx = createOidcContext({ ...validOidcContext, client: undefined });
|
||||
await expect(mockHandler()(ctx, noop)).rejects.toThrow(errors.InvalidClient);
|
||||
});
|
||||
|
||||
it('should throw when client is third-party application', async () => {
|
||||
findApplicationById.mockResolvedValueOnce({ ...mockApplication, isThirdParty: true });
|
||||
const ctx = createOidcContext(validOidcContext);
|
||||
await expect(mockHandler()(ctx, noop)).rejects.toThrow(errors.InvalidClient);
|
||||
});
|
||||
|
||||
it('should throw when subject token type is incorrect', async () => {
|
||||
const ctx = createOidcContext({
|
||||
...validOidcContext,
|
||||
|
|
|
@ -16,6 +16,8 @@ import { type EnvSet } from '#src/env-set/index.js';
|
|||
import type Queries from '#src/tenants/Queries.js';
|
||||
import assertThat from '#src/utils/assert-that.js';
|
||||
|
||||
import { isThirdPartyApplication } from '../resource.js';
|
||||
|
||||
const { InvalidClient, InvalidGrant } = errors;
|
||||
|
||||
/**
|
||||
|
@ -51,6 +53,11 @@ export const buildHandler: (
|
|||
|
||||
assertThat(params, new InvalidGrant('parameters must be available'));
|
||||
assertThat(client, new InvalidClient('client must be available'));
|
||||
// We don't allow third-party applications to perform token exchange
|
||||
assertThat(
|
||||
!(await isThirdPartyApplication(queries, client.clientId)),
|
||||
new InvalidClient('third-party applications are not allowed for this grant type')
|
||||
);
|
||||
assertThat(
|
||||
params.subject_token_type === 'urn:ietf:params:oauth:token-type:access_token',
|
||||
new InvalidGrant('unsupported subject token type')
|
||||
|
|
|
@ -6,7 +6,7 @@ import { oidcApi } from '#src/api/api.js';
|
|||
import { createApplication, deleteApplication } from '#src/api/application.js';
|
||||
import { createSubjectToken } from '#src/api/subject-token.js';
|
||||
import { createUserByAdmin } from '#src/helpers/index.js';
|
||||
import { devFeatureTest } from '#src/utils.js';
|
||||
import { devFeatureTest, generateName } from '#src/utils.js';
|
||||
|
||||
const { describe, it } = devFeatureTest;
|
||||
|
||||
|
@ -109,5 +109,30 @@ describe('Token Exchange', () => {
|
|||
})
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
it('should fail with a third-party application', async () => {
|
||||
const { subjectToken } = await createSubjectToken(userId);
|
||||
const thirdPartyApplication = await createApplication(
|
||||
generateName(),
|
||||
ApplicationType.Traditional,
|
||||
{
|
||||
isThirdParty: true,
|
||||
}
|
||||
);
|
||||
|
||||
await expect(
|
||||
oidcApi.post('token', {
|
||||
headers: formUrlEncodedHeaders,
|
||||
body: new URLSearchParams({
|
||||
client_id: thirdPartyApplication.id,
|
||||
grant_type: GrantType.TokenExchange,
|
||||
subject_token: subjectToken,
|
||||
subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',
|
||||
}),
|
||||
})
|
||||
).rejects.toThrow();
|
||||
|
||||
await deleteApplication(thirdPartyApplication.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue