From f66fad07b90e074e1616f14fe8c15158c7f2babc Mon Sep 17 00:00:00 2001 From: wangsijie Date: Thu, 12 Jan 2023 20:50:23 +0800 Subject: [PATCH] fix(core): fix getResourceServerInfo userId (#2919) --- packages/core/src/oidc/init.ts | 5 +- .../src/tests/api/get-access-token.test.ts | 52 +++++++++++++++---- packages/integration-tests/src/utils.ts | 11 ++++ pnpm-lock.yaml | 14 ++++- 4 files changed, 67 insertions(+), 15 deletions(-) diff --git a/packages/core/src/oidc/init.ts b/packages/core/src/oidc/init.ts index 4ed523ac9..ef8c85ba4 100644 --- a/packages/core/src/oidc/init.ts +++ b/packages/core/src/oidc/init.ts @@ -92,9 +92,8 @@ export default function initOidc(queries: Queries): Provider { throw new errors.InvalidTarget(); } - const scopes = ctx.oidc.account - ? await findUserScopesForResourceId(ctx.oidc.account.accountId, resourceServer.id) - : []; + const userId = ctx.oidc.session?.accountId; + const scopes = userId ? await findUserScopesForResourceId(userId, resourceServer.id) : []; const { accessTokenTtl: accessTokenTTL } = resourceServer; diff --git a/packages/integration-tests/src/tests/api/get-access-token.test.ts b/packages/integration-tests/src/tests/api/get-access-token.test.ts index 82f75e4bd..4ad237586 100644 --- a/packages/integration-tests/src/tests/api/get-access-token.test.ts +++ b/packages/integration-tests/src/tests/api/get-access-token.test.ts @@ -1,49 +1,79 @@ import path from 'path'; import { fetchTokenByRefreshToken } from '@logto/js'; -import { managementResource, InteractionEvent } from '@logto/schemas'; +import { + managementResource, + InteractionEvent, + adminConsoleAdminRoleId, + managementResourceScope, +} from '@logto/schemas'; import { assert } from '@silverhand/essentials'; import fetch from 'node-fetch'; import { putInteraction } from '#src/api/index.js'; +import { assignUsersToRole } from '#src/api/role.js'; import MockClient, { defaultConfig } from '#src/client/index.js'; import { logtoUrl } from '#src/constants.js'; import { processSession } from '#src/helpers/client.js'; import { createUserByAdmin } from '#src/helpers/index.js'; import { enableAllPasswordSignInMethods } from '#src/helpers/sign-in-experience.js'; -import { generateUsername, generatePassword } from '#src/utils.js'; +import { generateUsername, generatePassword, getAccessTokenPayload } from '#src/utils.js'; describe('get access token', () => { const username = generateUsername(); const password = generatePassword(); + const guestUsername = generateUsername(); beforeAll(async () => { - await createUserByAdmin(username, password); + await createUserByAdmin(guestUsername, password); + const user = await createUserByAdmin(username, password); + await assignUsersToRole([user.id], adminConsoleAdminRoleId); await enableAllPasswordSignInMethods(); }); - it('sign-in and getAccessToken', async () => { - const client = new MockClient({ resources: [managementResource.indicator] }); - + it('sign-in and getAccessToken with admin user', async () => { + const client = new MockClient({ + resources: [managementResource.indicator], + scopes: [managementResourceScope.name], + }); await client.initSession(); - await client.successSend(putInteraction, { event: InteractionEvent.SignIn, identifier: { username, password }, }); - const { redirectTo } = await client.submitInteraction(); - await processSession(client, redirectTo); - const accessToken = await client.getAccessToken(managementResource.indicator); - expect(accessToken).not.toBeNull(); + expect(getAccessTokenPayload(accessToken)).toHaveProperty( + 'scope', + managementResourceScope.name + ); // Request for invalid resource should throw void expect(client.getAccessToken('api.foo.com')).rejects.toThrow(); }); + it('sign-in and getAccessToken with guest user', async () => { + const client = new MockClient({ + resources: [managementResource.indicator], + scopes: [managementResourceScope.name], + }); + await client.initSession(); + await client.successSend(putInteraction, { + event: InteractionEvent.SignIn, + identifier: { username: guestUsername, password }, + }); + const { redirectTo } = await client.submitInteraction(); + await processSession(client, redirectTo); + const accessToken = await client.getAccessToken(managementResource.indicator); + + expect(getAccessTokenPayload(accessToken)).not.toHaveProperty( + 'scope', + managementResourceScope.name + ); + }); + it('sign-in and get multiple Access Token by the same Refresh Token within refreshTokenReuseInterval', async () => { const client = new MockClient({ resources: [managementResource.indicator] }); diff --git a/packages/integration-tests/src/utils.ts b/packages/integration-tests/src/utils.ts index 6baa55119..c642d7ae0 100644 --- a/packages/integration-tests/src/utils.ts +++ b/packages/integration-tests/src/utils.ts @@ -1,3 +1,5 @@ +import { assert } from '@silverhand/essentials'; + export const generateName = () => crypto.randomUUID(); export const generateUserId = () => crypto.randomUUID(); export const generateUsername = () => `usr_${crypto.randomUUID().replaceAll('-', '_')}`; @@ -19,3 +21,12 @@ export const waitFor = async (ms: number) => new Promise((resolve) => { setTimeout(resolve, ms); }); + +export const getAccessTokenPayload = (accessToken: string): Record => { + const payloadPart = accessToken.split('.')[1]; + assert(typeof payloadPart === 'string', new Error('Invalid access token')); + const payload = Buffer.from(payloadPart, 'base64').toString(); + + // eslint-disable-next-line no-restricted-syntax + return JSON.parse(payload) as Record; +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 92dbbd73b..a20a0078c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2330,6 +2330,18 @@ packages: lodash.once: 4.1.1 dev: true + /@logto/client/1.0.0-beta.15: + resolution: {integrity: sha512-+CrgyUcBcTILpfMPtwIEwBD60XgXUCdu7MpnvNZjd0sNaUpAoyFbUiRKzvbFeF7w9Nc4zO/kgAwbk36kqTXsvw==} + dependencies: + '@logto/core-kit': 1.0.0-beta.20 + '@logto/js': 1.0.0-beta.14 + '@silverhand/essentials': 1.3.0 + camelcase-keys: 7.0.2 + jose: 4.11.1 + lodash.get: 4.4.2 + lodash.once: 4.1.1 + dev: true + /@logto/core-kit/1.0.0-beta.20: resolution: {integrity: sha512-seYvL/aGYRfO4d0FYfKIW/Cu9PnFMRpRM5/oRXwXbcbv+LY1a3TcAX0itrVXeBygIrxiAmWd9DL7CGIWzb48Qg==} engines: {node: ^16.0.0} @@ -2362,7 +2374,7 @@ packages: /@logto/node/1.0.0-beta.14: resolution: {integrity: sha512-+0S6lBBcG3pOmjEMRQnD+6X0MJ3V3E/4In59ckl/uVr/UgIufvOKWJwWCfsVKyguaO3QweJn19x7YkF8FyO31g==} dependencies: - '@logto/client': 1.0.0-beta.14 + '@logto/client': 1.0.0-beta.15 '@silverhand/essentials': 1.3.0 js-base64: 3.7.3 node-fetch: 2.6.7