0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

refactor(core): fix resource parameter

This commit is contained in:
Gao Sun 2023-11-10 14:59:48 +08:00
parent d3e7cff0bd
commit fcda26ac2f
No known key found for this signature in database
GPG key ID: 13EBE123E4773688
6 changed files with 39 additions and 21 deletions

View file

@ -0,0 +1,27 @@
import { GrantType } from '@logto/schemas';
import type Provider from 'oidc-provider';
import instance from 'oidc-provider/lib/helpers/weak_cache.js';
import { type EnvSet } from '#src/env-set/index.js';
import type Queries from '#src/tenants/Queries.js';
import * as refreshToken from './refresh-token.js';
export const registerGrants = (oidc: Provider, envSet: EnvSet, queries: Queries) => {
const {
features: { resourceIndicators },
} = instance(oidc).configuration();
// If resource indicators are enabled, append `resource` to the parameters and allow it to
// be duplicated
const parameterConfig: [parameters: string[], duplicates: string[]] = resourceIndicators.enabled
? [[...refreshToken.parameters, 'resource'], ['resource']]
: [[...refreshToken.parameters], []];
// Override the default `refresh_token` grant
oidc.registerGrantType(
GrantType.RefreshToken,
refreshToken.buildHandler(envSet, queries.organizations),
...parameterConfig
);
};

View file

@ -20,7 +20,7 @@
*/
import { UserScope, buildOrganizationUrn } from '@logto/core-kit';
import { type Optional, cond, isKeyInObject } from '@silverhand/essentials';
import { type Optional, isKeyInObject, cond } from '@silverhand/essentials';
import type Provider from 'oidc-provider';
import { errors } from 'oidc-provider';
import difference from 'oidc-provider/lib/helpers/_/difference.js';
@ -53,7 +53,7 @@ const gty = 'refresh_token';
/**
* The valid parameters for the `organization_token` grant type. Note the `resource` parameter is
* handled by oidc-provider so we don't need to include it here.
* not included here since it should be handled per configuration when registering the grant type.
*/
export const parameters = Object.freeze(['refresh_token', 'organization_id', 'scope'] as const);
@ -130,7 +130,9 @@ export const buildHandler: (
}
/* === RFC 0001 === */
if (params.organization_id) {
// The params object may have the key with `undefined` value, so we have to use `Boolean` to check.
const organizationId = cond(Boolean(params.organization_id) && String(params.organization_id));
if (organizationId) {
// Validate if the refresh token has the required scope from RFC 0001.
if (!refreshToken.scopes.has(UserScope.Organizations)) {
throw new InsufficientScope('refresh token missing required scope', UserScope.Organizations);
@ -218,7 +220,6 @@ export const buildHandler: (
/* === RFC 0001 === */
// Check membership
const organizationId = cond(Boolean(params.organization_id) && String(params.organization_id));
if (
organizationId &&
!(await queries.relations.users.exists(organizationId, account.accountId))

View file

@ -7,6 +7,6 @@ describe('oidc provider init', () => {
it('init should not throw', async () => {
const { queries, libraries } = new MockTenant();
expect(() => initOidc('mock_id', mockEnvSet, queries, libraries)).not.toThrow();
expect(() => initOidc(mockEnvSet, queries, libraries)).not.toThrow();
});
});

View file

@ -8,7 +8,6 @@ import {
customClientMetadataDefault,
CustomClientMetadataKey,
demoAppApplicationId,
GrantType,
inSeconds,
logtoCookieKey,
type LogtoUiCookie,
@ -31,7 +30,7 @@ import type Libraries from '#src/tenants/Libraries.js';
import type Queries from '#src/tenants/Queries.js';
import defaults from './defaults.js';
import * as refreshToken from './grants/refresh-token.js';
import { registerGrants } from './grants/index.js';
import { findResource, findResourceScopes, getSharedResourceServerData } from './resource.js';
import { getUserClaimData, getUserClaims } from './scope.js';
import { OIDCExtraParametersKey, InteractionMode } from './type.js';
@ -39,12 +38,7 @@ import { OIDCExtraParametersKey, InteractionMode } from './type.js';
// Temporarily removed 'EdDSA' since it's not supported by browser yet
const supportedSigningAlgs = Object.freeze(['RS256', 'PS256', 'ES256', 'ES384', 'ES512'] as const);
export default function initOidc(
tenantId: string,
envSet: EnvSet,
queries: Queries,
libraries: Libraries
): Provider {
export default function initOidc(envSet: EnvSet, queries: Queries, libraries: Libraries): Provider {
const {
resources: { findDefaultResource },
users: { findUserById },
@ -287,11 +281,7 @@ export default function initOidc(
});
addOidcEventListeners(oidc, queries);
// Override the default `refresh_token` grant
oidc.registerGrantType(GrantType.RefreshToken, refreshToken.buildHandler(envSet, organizations), [
...refreshToken.parameters,
]);
registerGrants(oidc, envSet, queries);
// Provide audit log context for event listeners
oidc.use(koaAuditLog(queries));

View file

@ -83,7 +83,7 @@ export default class Tenant implements TenantContext {
app.use(koaSecurityHeaders(mountedApps, id));
// Mount OIDC
const provider = initOidc(id, envSet, queries, libraries);
const provider = initOidc(envSet, queries, libraries);
app.use(mount('/oidc', provider.app));
const tenantContext: TenantContext = {

View file

@ -101,8 +101,8 @@ const App = () => {
config={{
endpoint: window.location.origin,
appId: demoAppApplicationId,
prompt: Prompt.Consent,
// Use enum values once JS SDK is updated
prompt: Prompt.Login,
// TODO: Use enum values once JS SDK is updated
scopes: ['urn:logto:scope:organizations', 'urn:logto:scope:organization_roles'],
resources: ['urn:logto:resource:organizations'],
}}