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

refactor: remove SAML app certificate/metadata download APIs (#6856)

This commit is contained in:
Darcy Ye 2024-12-04 23:27:34 -08:00 committed by GitHub
parent 22d0a17389
commit cd0d3577ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 2 additions and 88 deletions

View file

@ -16,7 +16,6 @@ import { buildOidcClientMetadata } from '#src/oidc/utils.js';
import { generateInternalSecret } from '#src/routes/applications/application-secret.js'; import { generateInternalSecret } from '#src/routes/applications/application-secret.js';
import type { ManagementApiRouter, RouterInitArgs } from '#src/routes/types.js'; import type { ManagementApiRouter, RouterInitArgs } from '#src/routes/types.js';
import assertThat from '#src/utils/assert-that.js'; import assertThat from '#src/utils/assert-that.js';
import { createContentDisposition } from '#src/utils/content-disposition.js';
import { import {
calculateCertificateFingerprints, calculateCertificateFingerprints,
@ -35,7 +34,6 @@ export default function samlApplicationRoutes<T extends ManagementApiRouter>(
findSamlApplicationSecretsByApplicationId, findSamlApplicationSecretsByApplicationId,
findSamlApplicationSecretByApplicationIdAndId, findSamlApplicationSecretByApplicationIdAndId,
updateSamlApplicationSecretStatusByApplicationIdAndSecretId, updateSamlApplicationSecretStatusByApplicationIdAndSecretId,
findActiveSamlApplicationSecretByApplicationId,
}, },
} = queries; } = queries;
const { const {
@ -43,7 +41,6 @@ export default function samlApplicationRoutes<T extends ManagementApiRouter>(
createSamlApplicationSecret, createSamlApplicationSecret,
findSamlApplicationById, findSamlApplicationById,
updateSamlApplicationById, updateSamlApplicationById,
getSamlIdPMetadataByApplicationId,
}, },
} = libraries; } = libraries;
@ -270,70 +267,4 @@ export default function samlApplicationRoutes<T extends ManagementApiRouter>(
return next(); return next();
} }
); );
router.get(
'/saml-applications/:id/certificate',
koaGuard({
params: z.object({ id: z.string() }),
status: [200, 400, 404],
response: samlApplicationSecretResponseGuard.pick({
certificate: true,
fingerprints: true,
}),
}),
async (ctx, next) => {
const { id } = ctx.guard.params;
const { certificate } = await findActiveSamlApplicationSecretByApplicationId(id);
const fingerprints = calculateCertificateFingerprints(certificate);
ctx.status = 200;
ctx.body = { certificate, fingerprints };
return next();
}
);
router.get(
'/saml-applications/:id/certificate.pem',
koaGuard({
params: z.object({ id: z.string() }),
status: [200, 400, 404],
response: z.string(),
}),
async (ctx, next) => {
const { id } = ctx.guard.params;
const { certificate } = await findActiveSamlApplicationSecretByApplicationId(id);
ctx.status = 200;
ctx.body = certificate;
ctx.type = 'application/x-pem-file';
ctx.set('Content-Disposition', createContentDisposition(`certificate.pem`));
return next();
}
);
router.get(
'/saml-applications/:id/metadata.xml',
koaGuard({
params: z.object({ id: z.string() }),
status: [200, 404],
response: z.string(),
}),
async (ctx, next) => {
const { id } = ctx.guard.params;
const { metadata } = await getSamlIdPMetadataByApplicationId(id);
ctx.status = 200;
ctx.body = metadata;
ctx.type = 'text/xml;charset=utf-8';
ctx.set('Content-Disposition', createContentDisposition(`metadata.xml`));
return next();
}
);
} }

View file

@ -1,10 +0,0 @@
/**
* Generate Content-Disposition header value for file download
* @param filename The name of the file to be downloaded
* @returns Content-Disposition header value
*/
export const createContentDisposition = (filename: string) => {
// RFC 6266 requires the filename to be quoted and UTF-8 encoded
const encodedFilename = encodeURIComponent(filename);
return `attachment; filename="${encodedFilename}"; filename*=UTF-8''${encodedFilename}`;
};

View file

@ -44,9 +44,6 @@ export const updateSamlApplicationSecret = async (id: string, secretId: string,
.patch(`saml-applications/${id}/secrets/${secretId}`, { json: { active } }) .patch(`saml-applications/${id}/secrets/${secretId}`, { json: { active } })
.json<SamlApplicationSecretResponse>(); .json<SamlApplicationSecretResponse>();
export const getSamlApplicationCertificate = async (id: string) =>
authedAdminApi.get(`saml-applications/${id}/certificate`).json<{ certificate: string }>();
// Anonymous endpoints // Anonymous endpoints
export const getSamlApplicationMetadata = async (id: string) => export const getSamlApplicationMetadata = async (id: string) =>
api api

View file

@ -11,7 +11,6 @@ import {
updateSamlApplicationSecret, updateSamlApplicationSecret,
getSamlApplicationSecrets, getSamlApplicationSecrets,
getSamlApplicationMetadata, getSamlApplicationMetadata,
getSamlApplicationCertificate,
} from '#src/api/saml-application.js'; } from '#src/api/saml-application.js';
import { expectRejects } from '#src/helpers/index.js'; import { expectRejects } from '#src/helpers/index.js';
import { devFeatureTest } from '#src/utils.js'; import { devFeatureTest } from '#src/utils.js';
@ -141,13 +140,12 @@ describe('SAML application secrets/certificate/metadata', () => {
await deleteSamlApplication(id); await deleteSamlApplication(id);
}); });
it('should be able to get certificate/metadata after creating a SAML app', async () => { it('should be able to get metadata after creating a SAML app', async () => {
const { id } = await createSamlApplication({ const { id } = await createSamlApplication({
name: 'test', name: 'test',
description: 'test', description: 'test',
}); });
await expect(getSamlApplicationCertificate(id)).resolves.not.toThrow();
await expect(getSamlApplicationMetadata(id)).resolves.not.toThrow(); await expect(getSamlApplicationMetadata(id)).resolves.not.toThrow();
await deleteSamlApplication(id); await deleteSamlApplication(id);
@ -163,15 +161,13 @@ describe('SAML application secrets/certificate/metadata', () => {
const updatedSecret = await updateSamlApplicationSecret(id, createdSecret.id, true); const updatedSecret = await updateSamlApplicationSecret(id, createdSecret.id, true);
expect(updatedSecret.active).toBe(true); expect(updatedSecret.active).toBe(true);
expect(typeof updatedSecret.certificate).toBe('string');
const secrets = await getSamlApplicationSecrets(id); const secrets = await getSamlApplicationSecrets(id);
expect(secrets.length).toBe(2); expect(secrets.length).toBe(2);
expect(secrets.every(({ createdAt, expiresAt }) => createdAt < expiresAt)).toBe(true); expect(secrets.every(({ createdAt, expiresAt }) => createdAt < expiresAt)).toBe(true);
expect(secrets.filter(({ active }) => active).length).toBe(1); expect(secrets.filter(({ active }) => active).length).toBe(1);
const { certificate } = await getSamlApplicationCertificate(id);
expect(typeof certificate).toBe('string');
await deleteSamlApplication(id); await deleteSamlApplication(id);
}); });