test(sso): focus registered endpoint compatibility coverage

This commit is contained in:
Taesu
2026-10-13 09:24:58 +09:00
parent dcc481a4ea
commit a527bdfc24
3 changed files with 6 additions and 151 deletions
-33
View File
@@ -1425,39 +1425,6 @@ describe("SSO shared redirectURI", async () => {
expect(provider.redirectURI).not.toContain("shared-test");
});
it("preserves a registered relative redirect URI with a trailing auth base slash", async () => {
const { auth: trailingBaseAuth, signInWithTestUser: signIn } =
await getTestInstance({
baseURL: "http://localhost:3000/api/auth/",
trustedOrigins: ["http://localhost:8080"],
plugins: [
sso({ redirectURI: "/sso/callback?source=a%2Fb" }),
organization(),
],
});
const { headers } = await signIn();
const provider = await trailingBaseAuth.api.registerSSOProvider({
body: {
issuer: server.issuer.url!,
domain: "relative-redirect.com",
providerId: "relative-redirect",
oidcConfig: {
clientId: "relative-redirect",
clientSecret: "relative-redirect-secret",
authorizationEndpoint: `${server.issuer.url}/authorize`,
tokenEndpoint: `${server.issuer.url}/token`,
jwksEndpoint: `${server.issuer.url}/jwks`,
discoveryEndpoint: `${server.issuer.url}/.well-known/openid-configuration`,
},
},
headers,
});
expect(provider.redirectURI).toBe(
"http://localhost:3000/api/auth//sso/callback?source=a%2Fb",
);
});
it("should use shared redirect URI in authorization URL", async () => {
const headers = new Headers();
const res = await authClient.signIn.sso({
+6 -61
View File
@@ -1,71 +1,16 @@
import { APIError } from "better-auth/api";
import { getTestInstance } from "better-auth/test";
import { describe, expect, it, vi } from "vitest";
import { sso } from "../index";
import { describe, expect, it } from "vitest";
import type { SAMLConfig } from "../types";
import {
createSAMLPostForm,
createSP,
deriveSAMLIdentityProviderEntityID,
deriveSAMLServiceProviderPolicy,
getSAMLServiceProviderURL,
} from "./helpers";
const invalidSAMLBindingLocationMessage =
"SAML POST binding location must be an absolute http or https URL";
/** @see https://url.spec.whatwg.org/#percent-encoded-bytes */
it("preserves the configured provider ID for a SAML logout lookup", async () => {
const { auth } = await getTestInstance({
plugins: [sso({ saml: { enableSingleLogout: true } })],
});
const context = await auth.$context;
const lookup = vi.spyOn(context.adapter, "findOne");
await auth.handler(
new Request(
"http://localhost:3000/api/auth/sso/saml2/sp/slo/team%2Fmember?SAMLRequest=payload",
),
);
expect(lookup).toHaveBeenCalledWith(
expect.objectContaining({
model: "ssoProvider",
where: [{ field: "providerId", value: "team%2Fmember" }],
}),
);
});
describe("getSAMLServiceProviderURL", () => {
it("preserves the slash boundary of a registered ACS URL", () => {
expect(
getSAMLServiceProviderURL(
"https://Auth.Example.com:443/api/auth/",
"acs",
"acme:prod",
),
).toBe("https://Auth.Example.com:443/api/auth//sso/saml2/sp/acs/acme:prod");
});
it.each([
"acme:prod",
"okta@corp",
"a+b",
"team%2Fmember",
"okta%3Aacme",
])("preserves registered ACS and SLO URLs for provider %s", (providerId) => {
for (const endpoint of ["acs", "slo"] as const) {
expect(
getSAMLServiceProviderURL(
"https://Auth.Example.com:443/api/auth",
endpoint,
providerId,
),
).toBe(
`https://Auth.Example.com:443/api/auth/sso/saml2/sp/${endpoint}/${providerId}`,
);
}
});
});
function expectInvalidSAMLBindingLocation(action: string) {
try {
createSAMLPostForm(action, "SAMLResponse", "base64value");
@@ -175,11 +120,11 @@ describe("createSP assertion-signing metadata", () => {
expect(provider.getMetadata()).toContain('WantAssertionsSigned="true"');
});
it("preserves registered ACS and SLO slash boundaries in metadata", () => {
it("preserves registered endpoint identities in metadata", () => {
const provider = createSP(
configuration,
"https://service.example.com/api/auth/",
"team%20one",
"https://Auth.Example.com:443/api/auth/",
"acme:prod@team+dev%2Fmember",
{
sloOptions: {
wantLogoutRequestSigned: false,
@@ -190,10 +135,10 @@ describe("createSP assertion-signing metadata", () => {
const metadata = provider.getMetadata();
expect(metadata).toContain(
"https://service.example.com/api/auth//sso/saml2/sp/acs/team%20one",
"https://Auth.Example.com:443/api/auth//sso/saml2/sp/acs/acme:prod@team+dev%2Fmember",
);
expect(metadata).toContain(
"https://service.example.com/api/auth//sso/saml2/sp/slo/team%20one",
"https://Auth.Example.com:443/api/auth//sso/saml2/sp/slo/acme:prod@team+dev%2Fmember",
);
});
@@ -1,5 +1,4 @@
import { describe, expect, it } from "vitest";
import { getSAMLServiceProviderURL } from "../routes/helpers";
import {
getSAMLPostAssertionConsumerServiceUrls,
hasSAMLEncryptedAssertion,
@@ -64,62 +63,6 @@ function validate(xml: string, expectedAudiences = [serviceProviderEntityId]) {
}
describe("validateSAMLResponseBinding", () => {
it("preserves the configured ACS slash boundary", () => {
const expectedRecipients = [
getSAMLServiceProviderURL(
"https://Auth.Example.com:443/api/auth/",
"acs",
"acme:prod",
),
];
const registeredURL =
"https://Auth.Example.com:443/api/auth//sso/saml2/sp/acs/acme:prod";
expect(() =>
validateSAMLResponseBinding(
buildSAMLResponse({
recipient: registeredURL,
destination: registeredURL,
}),
{ expectedAudiences: [serviceProviderEntityId], expectedRecipients },
),
).not.toThrow();
expect(() =>
validateSAMLResponseBinding(
buildSAMLResponse({
recipient:
"https://other.example.com/api/auth//sso/saml2/sp/acs/acme:prod",
}),
{ expectedAudiences: [serviceProviderEntityId], expectedRecipients },
),
).toThrow(/Recipient does not match/);
});
it.each([
"acme:prod",
"okta@corp",
"a+b",
"team%2Fmember",
"okta%3Aacme",
])("accepts the previously registered Recipient and Destination for %s", (providerId) => {
const registeredURL = `https://Auth.Example.com:443/api/auth/sso/saml2/sp/acs/${providerId}`;
const xml = buildSAMLResponse({
recipient: registeredURL,
destination: registeredURL,
});
expect(() =>
validateSAMLResponseBinding(xml, {
expectedAudiences: [serviceProviderEntityId],
expectedRecipients: [
getSAMLServiceProviderURL(
"https://Auth.Example.com:443/api/auth",
"acs",
providerId,
),
],
}),
).not.toThrow();
});
it("accepts an assertion addressed to this Service Provider", () => {
expect(() => validate(buildSAMLResponse())).not.toThrow();
});