@better-auth/sso 1.3.0-beta.7 → 1.3.0-beta.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.d.cts +5 -11
- package/dist/index.d.mts +5 -11
- package/dist/index.d.ts +5 -11
- package/dist/index.mjs +4 -4
- package/package.json +2 -2
- package/src/index.ts +5 -4
- package/src/saml.test.ts +144 -101
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @better-auth/sso@1.3.0-beta.
|
|
2
|
+
> @better-auth/sso@1.3.0-beta.9 build /home/runner/work/better-auth/better-auth/packages/sso
|
|
3
3
|
> unbuild
|
|
4
4
|
|
|
5
5
|
[info] Automatically detected entries: src/index, src/client [esm] [cjs] [dts]
|
package/dist/index.cjs
CHANGED
|
@@ -1015,10 +1015,10 @@ const sso = (options) => {
|
|
|
1015
1015
|
}
|
|
1016
1016
|
let session = await ctx.context.internalAdapter.createSession(user.id, ctx);
|
|
1017
1017
|
await cookies.setSessionCookie(ctx, { session, user });
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1018
|
+
console.log("RelayState: ", RelayState);
|
|
1019
|
+
throw ctx.redirect(
|
|
1020
|
+
RelayState || `${parsedSamlConfig.issuer}/dashboard`
|
|
1021
|
+
);
|
|
1022
1022
|
}
|
|
1023
1023
|
)
|
|
1024
1024
|
},
|
package/dist/index.d.cts
CHANGED
|
@@ -552,19 +552,19 @@ declare const sso: (options?: SSOOptions) => {
|
|
|
552
552
|
session: {
|
|
553
553
|
session: Record<string, any> & {
|
|
554
554
|
id: string;
|
|
555
|
-
token: string;
|
|
556
555
|
userId: string;
|
|
557
556
|
expiresAt: Date;
|
|
558
557
|
createdAt: Date;
|
|
559
558
|
updatedAt: Date;
|
|
559
|
+
token: string;
|
|
560
560
|
ipAddress?: string | null | undefined;
|
|
561
561
|
userAgent?: string | null | undefined;
|
|
562
562
|
};
|
|
563
563
|
user: Record<string, any> & {
|
|
564
564
|
id: string;
|
|
565
|
-
name: string;
|
|
566
|
-
emailVerified: boolean;
|
|
567
565
|
email: string;
|
|
566
|
+
emailVerified: boolean;
|
|
567
|
+
name: string;
|
|
568
568
|
createdAt: Date;
|
|
569
569
|
updatedAt: Date;
|
|
570
570
|
image?: string | null | undefined;
|
|
@@ -973,14 +973,8 @@ declare const sso: (options?: SSOOptions) => {
|
|
|
973
973
|
returnHeaders?: ReturnHeaders | undefined;
|
|
974
974
|
}): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
|
|
975
975
|
headers: Headers;
|
|
976
|
-
response:
|
|
977
|
-
|
|
978
|
-
url: string;
|
|
979
|
-
};
|
|
980
|
-
} : {
|
|
981
|
-
redirect: boolean;
|
|
982
|
-
url: string;
|
|
983
|
-
}>;
|
|
976
|
+
response: never;
|
|
977
|
+
} : never>;
|
|
984
978
|
options: {
|
|
985
979
|
method: "POST";
|
|
986
980
|
body: z.ZodObject<{
|
package/dist/index.d.mts
CHANGED
|
@@ -552,19 +552,19 @@ declare const sso: (options?: SSOOptions) => {
|
|
|
552
552
|
session: {
|
|
553
553
|
session: Record<string, any> & {
|
|
554
554
|
id: string;
|
|
555
|
-
token: string;
|
|
556
555
|
userId: string;
|
|
557
556
|
expiresAt: Date;
|
|
558
557
|
createdAt: Date;
|
|
559
558
|
updatedAt: Date;
|
|
559
|
+
token: string;
|
|
560
560
|
ipAddress?: string | null | undefined;
|
|
561
561
|
userAgent?: string | null | undefined;
|
|
562
562
|
};
|
|
563
563
|
user: Record<string, any> & {
|
|
564
564
|
id: string;
|
|
565
|
-
name: string;
|
|
566
|
-
emailVerified: boolean;
|
|
567
565
|
email: string;
|
|
566
|
+
emailVerified: boolean;
|
|
567
|
+
name: string;
|
|
568
568
|
createdAt: Date;
|
|
569
569
|
updatedAt: Date;
|
|
570
570
|
image?: string | null | undefined;
|
|
@@ -973,14 +973,8 @@ declare const sso: (options?: SSOOptions) => {
|
|
|
973
973
|
returnHeaders?: ReturnHeaders | undefined;
|
|
974
974
|
}): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
|
|
975
975
|
headers: Headers;
|
|
976
|
-
response:
|
|
977
|
-
|
|
978
|
-
url: string;
|
|
979
|
-
};
|
|
980
|
-
} : {
|
|
981
|
-
redirect: boolean;
|
|
982
|
-
url: string;
|
|
983
|
-
}>;
|
|
976
|
+
response: never;
|
|
977
|
+
} : never>;
|
|
984
978
|
options: {
|
|
985
979
|
method: "POST";
|
|
986
980
|
body: z.ZodObject<{
|
package/dist/index.d.ts
CHANGED
|
@@ -552,19 +552,19 @@ declare const sso: (options?: SSOOptions) => {
|
|
|
552
552
|
session: {
|
|
553
553
|
session: Record<string, any> & {
|
|
554
554
|
id: string;
|
|
555
|
-
token: string;
|
|
556
555
|
userId: string;
|
|
557
556
|
expiresAt: Date;
|
|
558
557
|
createdAt: Date;
|
|
559
558
|
updatedAt: Date;
|
|
559
|
+
token: string;
|
|
560
560
|
ipAddress?: string | null | undefined;
|
|
561
561
|
userAgent?: string | null | undefined;
|
|
562
562
|
};
|
|
563
563
|
user: Record<string, any> & {
|
|
564
564
|
id: string;
|
|
565
|
-
name: string;
|
|
566
|
-
emailVerified: boolean;
|
|
567
565
|
email: string;
|
|
566
|
+
emailVerified: boolean;
|
|
567
|
+
name: string;
|
|
568
568
|
createdAt: Date;
|
|
569
569
|
updatedAt: Date;
|
|
570
570
|
image?: string | null | undefined;
|
|
@@ -973,14 +973,8 @@ declare const sso: (options?: SSOOptions) => {
|
|
|
973
973
|
returnHeaders?: ReturnHeaders | undefined;
|
|
974
974
|
}): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
|
|
975
975
|
headers: Headers;
|
|
976
|
-
response:
|
|
977
|
-
|
|
978
|
-
url: string;
|
|
979
|
-
};
|
|
980
|
-
} : {
|
|
981
|
-
redirect: boolean;
|
|
982
|
-
url: string;
|
|
983
|
-
}>;
|
|
976
|
+
response: never;
|
|
977
|
+
} : never>;
|
|
984
978
|
options: {
|
|
985
979
|
method: "POST";
|
|
986
980
|
body: z.ZodObject<{
|
package/dist/index.mjs
CHANGED
|
@@ -999,10 +999,10 @@ const sso = (options) => {
|
|
|
999
999
|
}
|
|
1000
1000
|
let session = await ctx.context.internalAdapter.createSession(user.id, ctx);
|
|
1001
1001
|
await setSessionCookie(ctx, { session, user });
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1002
|
+
console.log("RelayState: ", RelayState);
|
|
1003
|
+
throw ctx.redirect(
|
|
1004
|
+
RelayState || `${parsedSamlConfig.issuer}/dashboard`
|
|
1005
|
+
);
|
|
1006
1006
|
}
|
|
1007
1007
|
)
|
|
1008
1008
|
},
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/sso",
|
|
3
3
|
"author": "Bereket Engida",
|
|
4
|
-
"version": "1.3.0-beta.
|
|
4
|
+
"version": "1.3.0-beta.9",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"oauth2-mock-server": "^7.2.0",
|
|
48
48
|
"samlify": "^2.10.0",
|
|
49
49
|
"zod": "^3.24.1",
|
|
50
|
-
"better-auth": "^1.3.0-beta.
|
|
50
|
+
"better-auth": "^1.3.0-beta.9"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/body-parser": "^1.19.6",
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
validateAuthorizationCode,
|
|
14
14
|
validateToken,
|
|
15
15
|
} from "better-auth/oauth2";
|
|
16
|
+
|
|
16
17
|
import { createAuthEndpoint } from "better-auth/plugins";
|
|
17
18
|
import { z } from "zod";
|
|
18
19
|
import * as saml from "samlify";
|
|
@@ -1328,10 +1329,10 @@ export const sso = (options?: SSOOptions) => {
|
|
|
1328
1329
|
let session: Session =
|
|
1329
1330
|
await ctx.context.internalAdapter.createSession(user.id, ctx);
|
|
1330
1331
|
await setSessionCookie(ctx, { session, user });
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1332
|
+
console.log("RelayState: ", RelayState);
|
|
1333
|
+
throw ctx.redirect(
|
|
1334
|
+
RelayState || `${parsedSamlConfig.issuer}/dashboard`,
|
|
1335
|
+
);
|
|
1335
1336
|
},
|
|
1336
1337
|
),
|
|
1337
1338
|
},
|
package/src/saml.test.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { betterAuth } from "better-auth";
|
|
11
11
|
import { memoryAdapter } from "better-auth/adapters/memory";
|
|
12
12
|
import { createAuthClient } from "better-auth/client";
|
|
13
|
+
import { betterFetch } from "@better-fetch/fetch";
|
|
13
14
|
import { setCookieToHeader } from "better-auth/cookies";
|
|
14
15
|
import { bearer } from "better-auth/plugins";
|
|
15
16
|
import { IdentityProvider, ServiceProvider } from "samlify";
|
|
@@ -17,6 +18,12 @@ import { sso } from ".";
|
|
|
17
18
|
import { ssoClient } from "./client";
|
|
18
19
|
import { createServer } from "http";
|
|
19
20
|
import * as saml from "samlify";
|
|
21
|
+
import type {
|
|
22
|
+
Application as ExpressApp,
|
|
23
|
+
Request as ExpressRequest,
|
|
24
|
+
Response as ExpressResponse,
|
|
25
|
+
} from "express";
|
|
26
|
+
// @ts-ignore
|
|
20
27
|
import express from "express";
|
|
21
28
|
import bodyParser from "body-parser";
|
|
22
29
|
import { randomUUID } from "crypto";
|
|
@@ -346,78 +353,80 @@ const createTemplateCallback =
|
|
|
346
353
|
context: saml.SamlLib.replaceTagsByValue(template, tagValues),
|
|
347
354
|
};
|
|
348
355
|
};
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
this.sp = ServiceProvider({
|
|
392
|
-
metadata: spMetadata,
|
|
393
|
-
});
|
|
394
|
-
this.app.get("/api/sso/saml2/idp/post", async (req, res) => {
|
|
356
|
+
function createMockSAMLIdP(port: number) {
|
|
357
|
+
const app: ExpressApp = express();
|
|
358
|
+
let server: ReturnType<typeof createServer> | undefined;
|
|
359
|
+
app.use(bodyParser.urlencoded({ extended: true }));
|
|
360
|
+
app.use(bodyParser.json());
|
|
361
|
+
|
|
362
|
+
const idp = IdentityProvider({
|
|
363
|
+
metadata: idpMetadata,
|
|
364
|
+
privateKey: idPk,
|
|
365
|
+
isAssertionEncrypted: false,
|
|
366
|
+
privateKeyPass: "jXmKf9By6ruLnUdRo90G",
|
|
367
|
+
loginResponseTemplate: {
|
|
368
|
+
context:
|
|
369
|
+
'<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="{ID}" Version="2.0" IssueInstant="{IssueInstant}" Destination="{Destination}" InResponseTo="{InResponseTo}"><saml:Issuer>{Issuer}</saml:Issuer><samlp:Status><samlp:StatusCode Value="{StatusCode}"/></samlp:Status><saml:Assertion ID="{AssertionID}" Version="2.0" IssueInstant="{IssueInstant}" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"><saml:Issuer>{Issuer}</saml:Issuer><saml:Subject><saml:NameID Format="{NameIDFormat}">{NameID}</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="{SubjectConfirmationDataNotOnOrAfter}" Recipient="{SubjectRecipient}" InResponseTo="{InResponseTo}"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="{ConditionsNotBefore}" NotOnOrAfter="{ConditionsNotOnOrAfter}"><saml:AudienceRestriction><saml:Audience>{Audience}</saml:Audience></saml:AudienceRestriction></saml:Conditions>{AttributeStatement}</saml:Assertion></samlp:Response>',
|
|
370
|
+
attributes: [
|
|
371
|
+
{
|
|
372
|
+
name: "firstName",
|
|
373
|
+
valueTag: "firstName",
|
|
374
|
+
nameFormat: "urn:oasis:names:tc:SAML:2.0:attrname-format:basic",
|
|
375
|
+
valueXsiType: "xs:string",
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
name: "lastName",
|
|
379
|
+
valueTag: "lastName",
|
|
380
|
+
nameFormat: "urn:oasis:names:tc:SAML:2.0:attrname-format:basic",
|
|
381
|
+
valueXsiType: "xs:string",
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
name: "email",
|
|
385
|
+
valueTag: "email",
|
|
386
|
+
nameFormat: "urn:oasis:names:tc:SAML:2.0:attrname-format:basic",
|
|
387
|
+
valueXsiType: "xs:string",
|
|
388
|
+
},
|
|
389
|
+
],
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
const sp = ServiceProvider({
|
|
393
|
+
metadata: spMetadata,
|
|
394
|
+
});
|
|
395
|
+
app.get(
|
|
396
|
+
"/api/sso/saml2/idp/post",
|
|
397
|
+
async (req: ExpressRequest, res: ExpressResponse) => {
|
|
395
398
|
const user = { emailAddress: "test@email.com", famName: "hello world" };
|
|
396
|
-
const { context, entityEndpoint } = await
|
|
397
|
-
|
|
399
|
+
const { context, entityEndpoint } = await idp.createLoginResponse(
|
|
400
|
+
sp,
|
|
398
401
|
{} as any,
|
|
399
402
|
saml.Constants.wording.binding.post,
|
|
400
403
|
user,
|
|
401
|
-
createTemplateCallback(
|
|
404
|
+
createTemplateCallback(idp, sp, user.emailAddress),
|
|
402
405
|
);
|
|
403
406
|
res.status(200).send({ samlResponse: context, entityEndpoint });
|
|
404
|
-
}
|
|
405
|
-
|
|
407
|
+
},
|
|
408
|
+
);
|
|
409
|
+
app.get(
|
|
410
|
+
"/api/sso/saml2/idp/redirect",
|
|
411
|
+
async (req: ExpressRequest, res: ExpressResponse) => {
|
|
406
412
|
const user = { emailAddress: "test@email.com", famName: "hello world" };
|
|
407
|
-
const { context, entityEndpoint } = await
|
|
408
|
-
|
|
413
|
+
const { context, entityEndpoint } = await idp.createLoginResponse(
|
|
414
|
+
sp,
|
|
409
415
|
{} as any,
|
|
410
416
|
saml.Constants.wording.binding.post,
|
|
411
417
|
user,
|
|
412
|
-
createTemplateCallback(
|
|
418
|
+
createTemplateCallback(idp, sp, user.emailAddress),
|
|
413
419
|
);
|
|
414
420
|
res.status(200).send({ samlResponse: context, entityEndpoint });
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
|
|
421
|
+
},
|
|
422
|
+
);
|
|
423
|
+
// @ts-ignore
|
|
424
|
+
app.post(
|
|
425
|
+
"/api/sso/saml2/sp/acs",
|
|
426
|
+
async (req: ExpressRequest, res: ExpressResponse) => {
|
|
418
427
|
try {
|
|
419
|
-
const parseResult = await
|
|
420
|
-
|
|
428
|
+
const parseResult = await sp.parseLoginResponse(
|
|
429
|
+
idp,
|
|
421
430
|
saml.Constants.wording.binding.post,
|
|
422
431
|
req,
|
|
423
432
|
);
|
|
@@ -435,32 +444,58 @@ class MockSAMLIdP {
|
|
|
435
444
|
console.error("Error handling SAML ACS endpoint:", error);
|
|
436
445
|
res.status(500).send({ error: "Failed to process SAML response." });
|
|
437
446
|
}
|
|
438
|
-
}
|
|
439
|
-
|
|
447
|
+
},
|
|
448
|
+
);
|
|
449
|
+
app.post(
|
|
450
|
+
"/api/sso/saml2/callback",
|
|
451
|
+
async (req: ExpressRequest, res: ExpressResponse) => {
|
|
452
|
+
const { SAMLResponse, RelayState } = req.body;
|
|
440
453
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
});
|
|
448
|
-
});
|
|
449
|
-
}
|
|
454
|
+
try {
|
|
455
|
+
const parseResult = await sp.parseLoginResponse(
|
|
456
|
+
idp,
|
|
457
|
+
saml.Constants.wording.binding.post,
|
|
458
|
+
{ body: { SAMLResponse } },
|
|
459
|
+
);
|
|
450
460
|
|
|
451
|
-
|
|
452
|
-
return new Promise<void>((resolve, reject) => {
|
|
453
|
-
this.app.use(bodyParser.urlencoded({ extended: true }));
|
|
454
|
-
this.server?.close((err) => {
|
|
455
|
-
if (err) reject(err);
|
|
456
|
-
else resolve();
|
|
457
|
-
});
|
|
458
|
-
});
|
|
459
|
-
}
|
|
461
|
+
const { attributes, nameID } = parseResult.extract;
|
|
460
462
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
463
|
+
res.redirect(302, RelayState || "http://localhost:3000/dashboard");
|
|
464
|
+
} catch (error) {
|
|
465
|
+
console.error("Error processing SAML callback:", error);
|
|
466
|
+
res.status(500).send({ error: "Failed to process SAML response" });
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
);
|
|
470
|
+
app.get(
|
|
471
|
+
"/api/sso/saml2/idp/metadata",
|
|
472
|
+
(req: ExpressRequest, res: ExpressResponse) => {
|
|
473
|
+
res.type("application/xml");
|
|
474
|
+
res.send(idpMetadata);
|
|
475
|
+
},
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
return {
|
|
479
|
+
start: () => {
|
|
480
|
+
return new Promise<void>((resolve) => {
|
|
481
|
+
server = app.listen(port, () => {
|
|
482
|
+
console.log(`Mock SAML IdP running on port ${port}`);
|
|
483
|
+
resolve();
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
},
|
|
487
|
+
stop: () => {
|
|
488
|
+
return new Promise<void>((resolve, reject) => {
|
|
489
|
+
server?.close((err) => {
|
|
490
|
+
if (err) reject(err);
|
|
491
|
+
else resolve();
|
|
492
|
+
});
|
|
493
|
+
});
|
|
494
|
+
},
|
|
495
|
+
get metadataUrl() {
|
|
496
|
+
return `http://localhost:${port}/idp/metadata`;
|
|
497
|
+
},
|
|
498
|
+
};
|
|
464
499
|
}
|
|
465
500
|
|
|
466
501
|
describe("SAML SSO", async () => {
|
|
@@ -473,7 +508,7 @@ describe("SAML SSO", async () => {
|
|
|
473
508
|
};
|
|
474
509
|
|
|
475
510
|
const memory = memoryAdapter(data);
|
|
476
|
-
const mockIdP =
|
|
511
|
+
const mockIdP = createMockSAMLIdP(8081); // Different port from your main app
|
|
477
512
|
|
|
478
513
|
const ssoOptions = {
|
|
479
514
|
provisionUser: vi
|
|
@@ -580,7 +615,7 @@ describe("SAML SSO", async () => {
|
|
|
580
615
|
encPrivateKeyPass: "g7hGcRmp8PxT5QeP2q9Ehf1bWe9zTALN",
|
|
581
616
|
},
|
|
582
617
|
spMetadata: {
|
|
583
|
-
metadata:
|
|
618
|
+
metadata: spMetadata,
|
|
584
619
|
binding: "post",
|
|
585
620
|
privateKey: spPrivateKey,
|
|
586
621
|
privateKeyPass: "VHOSp5RUiBcrsjrcAuXFwU1NKCkGA8px",
|
|
@@ -672,9 +707,9 @@ describe("SAML SSO", async () => {
|
|
|
672
707
|
issuer: "http://localhost:8081",
|
|
673
708
|
domain: "http://localhost:8081",
|
|
674
709
|
samlConfig: {
|
|
675
|
-
entryPoint:
|
|
710
|
+
entryPoint: "http://localhost:8081/api/sso/saml2/idp/post",
|
|
676
711
|
cert: certificate,
|
|
677
|
-
callbackUrl: "http://localhost:8081/api/sso/saml2/
|
|
712
|
+
callbackUrl: "http://localhost:8081/api/sso/saml2/callback",
|
|
678
713
|
wantAssertionsSigned: false,
|
|
679
714
|
signatureAlgorithm: "sha256",
|
|
680
715
|
digestAlgorithm: "sha256",
|
|
@@ -687,9 +722,8 @@ describe("SAML SSO", async () => {
|
|
|
687
722
|
encPrivateKeyPass: "g7hGcRmp8PxT5QeP2q9Ehf1bWe9zTALN",
|
|
688
723
|
},
|
|
689
724
|
spMetadata: {
|
|
690
|
-
metadata:
|
|
725
|
+
metadata: spMetadata,
|
|
691
726
|
binding: "post",
|
|
692
|
-
// we can do a mapping of property here
|
|
693
727
|
privateKey: spPrivateKey,
|
|
694
728
|
privateKeyPass: "VHOSp5RUiBcrsjrcAuXFwU1NKCkGA8px",
|
|
695
729
|
isAssertionEncrypted: true,
|
|
@@ -709,25 +743,34 @@ describe("SAML SSO", async () => {
|
|
|
709
743
|
callbackURL: "http://localhost:3000/dashboard",
|
|
710
744
|
},
|
|
711
745
|
});
|
|
746
|
+
|
|
712
747
|
expect(signInResponse).toEqual({
|
|
713
748
|
url: expect.stringContaining("http://localhost:8081"),
|
|
714
749
|
redirect: true,
|
|
715
750
|
});
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
RelayState: "http://localhost:3001/dashboard",
|
|
722
|
-
},
|
|
723
|
-
params: {
|
|
724
|
-
providerId: provider.providerId,
|
|
751
|
+
|
|
752
|
+
let samlResponse: any;
|
|
753
|
+
await betterFetch(signInResponse?.url as string, {
|
|
754
|
+
onSuccess: async (context) => {
|
|
755
|
+
samlResponse = await context.data;
|
|
725
756
|
},
|
|
726
757
|
});
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
758
|
+
let redirectLocation = "";
|
|
759
|
+
await betterFetch("http://localhost:8081/api/sso/saml2/callback", {
|
|
760
|
+
method: "POST",
|
|
761
|
+
redirect: "manual",
|
|
762
|
+
headers: {
|
|
763
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
764
|
+
},
|
|
765
|
+
body: new URLSearchParams({
|
|
766
|
+
SAMLResponse: samlResponse.samlResponse,
|
|
767
|
+
RelayState: "http://localhost:3000/dashboard",
|
|
768
|
+
}),
|
|
769
|
+
onError: (context) => {
|
|
770
|
+
expect(context.response.status).toBe(302);
|
|
771
|
+
redirectLocation = context.response.headers.get("location") || "";
|
|
772
|
+
},
|
|
731
773
|
});
|
|
774
|
+
expect(redirectLocation).toBe("http://localhost:3000/dashboard");
|
|
732
775
|
});
|
|
733
776
|
});
|