forked from authts/oidc-client-ts
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCryptoUtils.test.ts
More file actions
136 lines (118 loc) · 6.09 KB
/
Copy pathCryptoUtils.test.ts
File metadata and controls
136 lines (118 loc) · 6.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import { describe, expect, it, vi } from "vitest";
import { CryptoUtils } from "./CryptoUtils";
import { jwtVerify, decodeProtectedHeader, importJWK, type JWK } from "jose";
const pattern = /^[0-9a-f]{8}[0-9a-f]{4}4[0-9a-f]{3}[89ab][0-9a-f]{3}[0-9a-f]{12}$/;
describe("CryptoUtils", () => {
describe("generateUUIDv4", () => {
it("should return a valid RFC4122 v4 guid (sans dashes)", () => {
// act
const rnd = CryptoUtils.generateUUIDv4();
// assert
expect(rnd).toMatch(pattern);
});
});
describe("customCalculateJwkThumbprint", () => {
it("should return a valid rfc7638 jwk thumbprint for EC", async () => {
const jwk = {
"kty": "EC",
"x": "zSau12OpG01OkWtiU8yG1ppv06v1uDrG66cNeqMWk_8",
"y": "Mjr6rkLy4chKd7f8m0ctUFEA2DtZuk_F09FU3h98xyo",
"crv": "P-256",
} as JsonWebKey;
const jwkThumbprint = await CryptoUtils.customCalculateJwkThumbprint(jwk);
expect(jwkThumbprint).toEqual("fvRy8PxXeUhrCgW4r0hAFroUAqSnmyiCncJmlCamt9g");
});
it("should return a valid rfc7638 jwk thumbprint for RSA", async () => {
const jwk = {
"kty": "RSA",
"e": "AQAB",
"n": "qPfgaTEWEP3S9w0tgsicURfo-nLW09_0KfOPinhYZ4ouzU-3xC4pSlEp8Ut9FgL0AgqNslNaK34Kq-NZjO9DAQ==",
} as JsonWebKey;
const jwkThumbprint = await CryptoUtils.customCalculateJwkThumbprint(jwk);
expect(jwkThumbprint).toEqual("PY09-sc60ozeKeWZNizkBrT_081gcm9YHwIRyZ__3_0");
});
it("should return a valid rfc7638 jwk thumbprint for OKP", async () => {
const jwk = {
"kty": "OKP",
"x": "zSau12OpG01OkWtiU8yG1ppv06v1uDrG66cNeqMWk_8",
"crv": "P-256",
} as JsonWebKey;
const jwkThumbprint = await CryptoUtils.customCalculateJwkThumbprint(jwk);
expect(jwkThumbprint).toEqual("2UtIWugaDqeNZtm87tNRSAnJ6XiFqhRLf_BRFNFs9T8");
});
it("should return a valid rfc7638 jwk thumbprint for oct", async () => {
const jwk = {
"kty": "OKP",
"crv": "P-256",
} as JsonWebKey;
const jwkThumbprint = await CryptoUtils.customCalculateJwkThumbprint(jwk);
expect(jwkThumbprint).toEqual("b0HfX8_AYRZlfiRj51oOHHL9BrTz0Q4z6AqSk-2nyJM");
});
it("should throw an error for an unknown jwk type", async () => {
const jwk = {
"kty": "unknown",
} as JsonWebKey;
await expect(CryptoUtils.customCalculateJwkThumbprint(jwk)).rejects.toThrow("Unknown jwk type");
});
});
describe("generateDPoPProof", () => {
it("should generate a valid proof without an access token", async () => {
// arrange
const url = "https://localhost:5005/identity";
const httpMethod = "GET";
const keyPair = await CryptoUtils.generateDPoPKeys();
// act
const dpopProof = await CryptoUtils.generateDPoPProof({ url, httpMethod, keyPair });
const protectedHeader = decodeProtectedHeader(dpopProof);
const publicKey = await importJWK(<JWK>protectedHeader.jwk);
const verifiedResult = await jwtVerify(dpopProof, publicKey);
// assert
expect(verifiedResult.payload).toHaveProperty("htu");
expect(verifiedResult.payload).toHaveProperty("htm");
});
it("should generate a valid proof with an access token", async () => {
// arrange
const url = "https://localhost:5005/identity";
const httpMethod = "GET";
const accessToken = "access_token";
const keyPair = await CryptoUtils.generateDPoPKeys();
// act
const dpopProof = await CryptoUtils.generateDPoPProof({ url, accessToken, httpMethod, keyPair });
const protectedHeader = decodeProtectedHeader(dpopProof);
const publicKey = await importJWK(<JWK>protectedHeader.jwk);
const verifiedResult = await jwtVerify(dpopProof, publicKey);
// assert
expect(verifiedResult.payload).toHaveProperty("htu");
expect(verifiedResult.payload).toHaveProperty("htm");
expect(verifiedResult.payload).toHaveProperty("ath");
});
it("should throw an exception if there is an error generating the signed JWT", async () => {
const keyPair = await CryptoUtils.generateDPoPKeys();
const exportKeyMock = vi.spyOn(crypto.subtle, "exportKey").mockResolvedValue({} as JsonWebKey);
const generateSignedJwtMock = vi.spyOn(crypto.subtle, "sign").mockRejectedValue(new Error("Generate signed JWT error"));
await expect(CryptoUtils.generateDPoPProof({
url: "http://example.com", keyPair: keyPair })).rejects.toThrow("Generate signed JWT error");
exportKeyMock.mockRestore();
generateSignedJwtMock.mockRestore();
});
it("should generate a valid proof with a nonce", async () => {
// arrange
const url = "https://localhost:5005/identity";
const httpMethod = "GET";
const accessToken = "access_token";
const keyPair = await CryptoUtils.generateDPoPKeys();
const nonce = "some-nonce";
// act
const dpopProof = await CryptoUtils.generateDPoPProof({ url, accessToken, httpMethod, keyPair, nonce });
const protectedHeader = decodeProtectedHeader(dpopProof);
const publicKey = await importJWK(<JWK>protectedHeader.jwk);
const verifiedResult = await jwtVerify(dpopProof, publicKey);
// assert
expect(verifiedResult.payload).toHaveProperty("htu");
expect(verifiedResult.payload).toHaveProperty("htm");
expect(verifiedResult.payload).toHaveProperty("ath");
expect(verifiedResult.payload).toHaveProperty("nonce");
expect(verifiedResult.payload.nonce).toEqual(nonce);
});
});
});