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:
parent
22d0a17389
commit
cd0d3577ee
4 changed files with 2 additions and 88 deletions
|
@ -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();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}`;
|
|
||||||
};
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue