keycloakify 11.5.0 → 11.5.1

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/bin/682.index.js CHANGED
@@ -311,7 +311,15 @@ const zParsedRealmJson = (() => {
311
311
  })
312
312
  .optional(),
313
313
  protocol: lib.z.string().optional(),
314
- protocolMappers: lib.z.array(lib.z.unknown()).optional()
314
+ protocolMappers: lib.z.array(lib.z.object({
315
+ id: lib.z.string(),
316
+ name: lib.z.string(),
317
+ protocol: lib.z.string(),
318
+ protocolMapper: lib.z.string(),
319
+ consentRequired: lib.z.boolean(),
320
+ config: lib.z.record(lib.z.string()).optional()
321
+ }))
322
+ .optional()
315
323
  }))
316
324
  });
317
325
  assert/* assert */.h;
@@ -705,7 +713,7 @@ function addOrEditClient(params) {
705
713
  return { clientId: testClient.clientId };
706
714
  }
707
715
  function editAccountConsoleAndSecurityAdminConsole(params) {
708
- var _a, _b, _c;
716
+ var _a, _b, _c, _d, _e;
709
717
  const { parsedRealmJson } = params;
710
718
  for (const clientId of ["account-console", "security-admin-console"]) {
711
719
  const client = parsedRealmJson.clients.find(client => client.clientId === clientId);
@@ -721,6 +729,56 @@ function editAccountConsoleAndSecurityAdminConsole(params) {
721
729
  }
722
730
  ((_c = client.attributes) !== null && _c !== void 0 ? _c : (client.attributes = {}))["post.logout.redirect.uris"] = "+";
723
731
  client.webOrigins = ["*"];
732
+ admin_specific: {
733
+ if (clientId !== "security-admin-console") {
734
+ break admin_specific;
735
+ }
736
+ const protocolMapper_preexisting = (_d = client.protocolMappers) === null || _d === void 0 ? void 0 : _d.find(protocolMapper => {
737
+ if (protocolMapper.protocolMapper !== "oidc-hardcoded-claim-mapper") {
738
+ return false;
739
+ }
740
+ if (protocolMapper.protocol !== "openid-connect") {
741
+ return false;
742
+ }
743
+ if (protocolMapper.config === undefined) {
744
+ return false;
745
+ }
746
+ if (protocolMapper.config["claim.name"] !== "allowed-origins") {
747
+ return false;
748
+ }
749
+ return true;
750
+ });
751
+ let protocolMapper;
752
+ const config = {
753
+ "introspection.token.claim": "true",
754
+ "claim.value": '["*"]',
755
+ "userinfo.token.claim": "true",
756
+ "id.token.claim": "false",
757
+ "lightweight.claim": "false",
758
+ "access.token.claim": "true",
759
+ "claim.name": "allowed-origins",
760
+ "jsonType.label": "JSON",
761
+ "access.tokenResponse.claim": "false"
762
+ };
763
+ if (protocolMapper_preexisting !== undefined) {
764
+ protocolMapper = protocolMapper_preexisting;
765
+ }
766
+ else {
767
+ protocolMapper = {
768
+ id: "8fd0d584-7052-4d04-a615-d18a71050873",
769
+ name: "allowed-origins",
770
+ protocol: "openid-connect",
771
+ protocolMapper: "oidc-hardcoded-claim-mapper",
772
+ consentRequired: false,
773
+ config
774
+ };
775
+ ((_e = client.protocolMappers) !== null && _e !== void 0 ? _e : (client.protocolMappers = [])).push(protocolMapper);
776
+ }
777
+ (0,assert/* assert */.h)(protocolMapper.config !== undefined);
778
+ if (config !== protocolMapper.config) {
779
+ Object.assign(protocolMapper.config, config);
780
+ }
781
+ }
724
782
  }
725
783
  }
726
784
  //# sourceMappingURL=prepareRealmConfig.js.map
@@ -735,12 +793,29 @@ function editAccountConsoleAndSecurityAdminConsole(params) {
735
793
  (0,assert/* assert */.h)();
736
794
  async function dumpContainerConfig(params) {
737
795
  const { realmName, keycloakMajorVersionNumber, buildContext } = params;
738
- {
739
- // https://github.com/keycloak/keycloak/issues/33800
740
- const doesUseLockedH2Database = keycloakMajorVersionNumber >= 25;
741
- if (doesUseLockedH2Database) {
742
- external_child_process_default().execSync(`docker exec ${constants/* CONTAINER_NAME */.sv} sh -c "cp -rp /opt/keycloak/data/h2 /tmp"`);
796
+ // https://github.com/keycloak/keycloak/issues/33800
797
+ const doesUseLockedH2Database = keycloakMajorVersionNumber >= 25;
798
+ if (doesUseLockedH2Database) {
799
+ const dCompleted = new Deferred.Deferred();
800
+ const cmd = `docker exec ${constants/* CONTAINER_NAME */.sv} sh -c "cp -rp /opt/keycloak/data/h2 /tmp"`;
801
+ external_child_process_default().exec(cmd, error => {
802
+ if (error !== null) {
803
+ dCompleted.reject(error);
804
+ return;
805
+ }
806
+ dCompleted.resolve();
807
+ });
808
+ try {
809
+ await dCompleted.pr;
743
810
  }
811
+ catch (error) {
812
+ (0,assert/* assert */.h)((0,assert.is)(error));
813
+ console.log(source_default().red(`Docker command failed: ${cmd}`));
814
+ console.log(source_default().red(error.message));
815
+ throw error;
816
+ }
817
+ }
818
+ {
744
819
  const dCompleted = new Deferred.Deferred();
745
820
  const child = external_child_process_default().spawn("docker", [
746
821
  ...["exec", constants/* CONTAINER_NAME */.sv],
@@ -760,7 +835,7 @@ async function dumpContainerConfig(params) {
760
835
  ], { shell: true });
761
836
  let output = "";
762
837
  const onExit = (code) => {
763
- dCompleted.reject(new Error(`Exited with code ${code}`));
838
+ dCompleted.reject(new Error(`docker exec kc.sh export command failed with code ${code}`));
764
839
  };
765
840
  child.once("exit", onExit);
766
841
  child.stdout.on("data", data => {
@@ -789,31 +864,51 @@ async function dumpContainerConfig(params) {
789
864
  (0,assert/* assert */.h)((0,assert.is)(error));
790
865
  console.log(source_default().red(error.message));
791
866
  console.log(output);
792
- process.exit(1);
867
+ throw error;
793
868
  }
794
- if (doesUseLockedH2Database) {
795
- const dCompleted = new Deferred.Deferred();
796
- external_child_process_default().exec(`docker exec ${constants/* CONTAINER_NAME */.sv} sh -c "rm -rf /tmp/h2"`, error => {
797
- if (error !== null) {
798
- dCompleted.reject(error);
799
- return;
800
- }
801
- dCompleted.resolve();
802
- });
869
+ }
870
+ if (doesUseLockedH2Database) {
871
+ const dCompleted = new Deferred.Deferred();
872
+ const cmd = `docker exec ${constants/* CONTAINER_NAME */.sv} sh -c "rm -rf /tmp/h2"`;
873
+ external_child_process_default().exec(cmd, error => {
874
+ if (error !== null) {
875
+ dCompleted.reject(error);
876
+ return;
877
+ }
878
+ dCompleted.resolve();
879
+ });
880
+ try {
803
881
  await dCompleted.pr;
804
882
  }
883
+ catch (error) {
884
+ (0,assert/* assert */.h)((0,assert.is)(error));
885
+ console.log(source_default().red(`Docker command failed: ${cmd}`));
886
+ console.log(source_default().red(error.message));
887
+ throw error;
888
+ }
805
889
  }
806
890
  const targetRealmConfigJsonFilePath_tmp = (0,external_path_.join)(buildContext.cacheDirPath, "realm.json");
807
891
  {
808
892
  const dCompleted = new Deferred.Deferred();
809
- external_child_process_default().exec(`docker cp ${constants/* CONTAINER_NAME */.sv}:/tmp/${realmName}-realm.json ${targetRealmConfigJsonFilePath_tmp}`, error => {
893
+ const cmd = `docker cp ${constants/* CONTAINER_NAME */.sv}:/tmp/${realmName}-realm.json ${(0,external_path_.basename)(targetRealmConfigJsonFilePath_tmp)}`;
894
+ external_child_process_default().exec(cmd, {
895
+ cwd: (0,external_path_.dirname)(targetRealmConfigJsonFilePath_tmp)
896
+ }, error => {
810
897
  if (error !== null) {
811
898
  dCompleted.reject(error);
812
899
  return;
813
900
  }
814
901
  dCompleted.resolve();
815
902
  });
816
- await dCompleted.pr;
903
+ try {
904
+ await dCompleted.pr;
905
+ }
906
+ catch (error) {
907
+ (0,assert/* assert */.h)((0,assert.is)(error));
908
+ console.log(source_default().red(`Docker command failed: ${cmd}`));
909
+ console.log(source_default().red(error.message));
910
+ throw error;
911
+ }
817
912
  }
818
913
  return readRealmJsonFile({
819
914
  realmJsonFilePath: targetRealmConfigJsonFilePath_tmp
@@ -877,11 +972,18 @@ async function getRealmConfig(params) {
877
972
  const run = runExclusive.build(async () => {
878
973
  const start = Date.now();
879
974
  console.log(source_default().grey(`Changes detected to the '${realmName}' config, backing up...`));
880
- const parsedRealmJson = await dumpContainerConfig({
881
- buildContext,
882
- realmName,
883
- keycloakMajorVersionNumber
884
- });
975
+ let parsedRealmJson;
976
+ try {
977
+ parsedRealmJson = await dumpContainerConfig({
978
+ buildContext,
979
+ realmName,
980
+ keycloakMajorVersionNumber
981
+ });
982
+ }
983
+ catch (error) {
984
+ console.log(source_default().red(`Failed to backup '${realmName}' config:`));
985
+ return;
986
+ }
885
987
  await writeRealmJsonFile({ parsedRealmJson });
886
988
  console.log([
887
989
  source_default().grey(`Save changed to \`.${external_path_.sep}${(0,external_path_.relative)(buildContext.projectDirPath, realmJsonFilePath)}\``),
@@ -30,7 +30,14 @@ export type ParsedRealmJson = {
30
30
  "post.logout.redirect.uris"?: string;
31
31
  };
32
32
  protocol?: string;
33
- protocolMappers?: unknown[];
33
+ protocolMappers?: {
34
+ id: string;
35
+ name: string;
36
+ protocol: string;
37
+ protocolMapper: string;
38
+ consentRequired: boolean;
39
+ config?: Record<string, string>;
40
+ }[];
34
41
  }[];
35
42
  };
36
43
  export declare function readRealmJsonFile(params: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keycloakify",
3
- "version": "11.5.0",
3
+ "version": "11.5.1",
4
4
  "description": "Framework to create custom Keycloak UIs",
5
5
  "repository": {
6
6
  "type": "git",
@@ -39,7 +39,14 @@ export type ParsedRealmJson = {
39
39
  "post.logout.redirect.uris"?: string;
40
40
  };
41
41
  protocol?: string;
42
- protocolMappers?: unknown[];
42
+ protocolMappers?: {
43
+ id: string;
44
+ name: string;
45
+ protocol: string; // "openid-connect" or something else
46
+ protocolMapper: string; // "oidc-hardcoded-claim-mapper" or something else
47
+ consentRequired: boolean;
48
+ config?: Record<string, string>;
49
+ }[];
43
50
  }[];
44
51
  };
45
52
 
@@ -89,7 +96,18 @@ const zParsedRealmJson = (() => {
89
96
  })
90
97
  .optional(),
91
98
  protocol: z.string().optional(),
92
- protocolMappers: z.array(z.unknown()).optional()
99
+ protocolMappers: z
100
+ .array(
101
+ z.object({
102
+ id: z.string(),
103
+ name: z.string(),
104
+ protocol: z.string(),
105
+ protocolMapper: z.string(),
106
+ consentRequired: z.boolean(),
107
+ config: z.record(z.string()).optional()
108
+ })
109
+ )
110
+ .optional()
93
111
  })
94
112
  )
95
113
  });
@@ -985,6 +985,24 @@
985
985
  "claim.name": "locale",
986
986
  "jsonType.label": "String"
987
987
  }
988
+ },
989
+ {
990
+ "id": "8fd0d584-7052-4d04-a615-d18a71050873",
991
+ "name": "allowed-origins",
992
+ "protocol": "openid-connect",
993
+ "protocolMapper": "oidc-hardcoded-claim-mapper",
994
+ "consentRequired": false,
995
+ "config": {
996
+ "introspection.token.claim": "true",
997
+ "claim.value": "[\"*\"]",
998
+ "userinfo.token.claim": "true",
999
+ "id.token.claim": "false",
1000
+ "lightweight.claim": "false",
1001
+ "access.token.claim": "true",
1002
+ "claim.name": "allowed-origins",
1003
+ "jsonType.label": "JSON",
1004
+ "access.tokenResponse.claim": "false"
1005
+ }
988
1006
  }
989
1007
  ],
990
1008
  "defaultClientScopes": [
@@ -1640,13 +1658,13 @@
1640
1658
  "config": {
1641
1659
  "allowed-protocol-mapper-types": [
1642
1660
  "oidc-usermodel-property-mapper",
1643
- "saml-user-attribute-mapper",
1644
1661
  "saml-user-property-mapper",
1645
- "oidc-full-name-mapper",
1646
- "oidc-sha256-pairwise-sub-mapper",
1647
1662
  "oidc-address-mapper",
1663
+ "saml-user-attribute-mapper",
1664
+ "saml-role-list-mapper",
1665
+ "oidc-sha256-pairwise-sub-mapper",
1648
1666
  "oidc-usermodel-attribute-mapper",
1649
- "saml-role-list-mapper"
1667
+ "oidc-full-name-mapper"
1650
1668
  ]
1651
1669
  }
1652
1670
  },
@@ -1676,14 +1694,14 @@
1676
1694
  "subComponents": {},
1677
1695
  "config": {
1678
1696
  "allowed-protocol-mapper-types": [
1679
- "oidc-sha256-pairwise-sub-mapper",
1680
1697
  "saml-user-attribute-mapper",
1681
- "oidc-usermodel-property-mapper",
1682
1698
  "oidc-full-name-mapper",
1683
- "saml-role-list-mapper",
1699
+ "oidc-sha256-pairwise-sub-mapper",
1684
1700
  "saml-user-property-mapper",
1685
- "oidc-usermodel-attribute-mapper",
1686
- "oidc-address-mapper"
1701
+ "oidc-usermodel-property-mapper",
1702
+ "saml-role-list-mapper",
1703
+ "oidc-address-mapper",
1704
+ "oidc-usermodel-attribute-mapper"
1687
1705
  ]
1688
1706
  }
1689
1707
  },
@@ -1,6 +1,6 @@
1
1
  import { CONTAINER_NAME } from "../../shared/constants";
2
2
  import child_process from "child_process";
3
- import { join as pathJoin } from "path";
3
+ import { join as pathJoin, dirname as pathDirname, basename as pathBasename } from "path";
4
4
  import chalk from "chalk";
5
5
  import { Deferred } from "evt/tools/Deferred";
6
6
  import { assert, is } from "tsafe/assert";
@@ -20,16 +20,37 @@ export async function dumpContainerConfig(params: {
20
20
  }): Promise<ParsedRealmJson> {
21
21
  const { realmName, keycloakMajorVersionNumber, buildContext } = params;
22
22
 
23
- {
24
- // https://github.com/keycloak/keycloak/issues/33800
25
- const doesUseLockedH2Database = keycloakMajorVersionNumber >= 25;
23
+ // https://github.com/keycloak/keycloak/issues/33800
24
+ const doesUseLockedH2Database = keycloakMajorVersionNumber >= 25;
26
25
 
27
- if (doesUseLockedH2Database) {
28
- child_process.execSync(
29
- `docker exec ${CONTAINER_NAME} sh -c "cp -rp /opt/keycloak/data/h2 /tmp"`
30
- );
26
+ if (doesUseLockedH2Database) {
27
+ const dCompleted = new Deferred<void>();
28
+
29
+ const cmd = `docker exec ${CONTAINER_NAME} sh -c "cp -rp /opt/keycloak/data/h2 /tmp"`;
30
+
31
+ child_process.exec(cmd, error => {
32
+ if (error !== null) {
33
+ dCompleted.reject(error);
34
+ return;
35
+ }
36
+
37
+ dCompleted.resolve();
38
+ });
39
+
40
+ try {
41
+ await dCompleted.pr;
42
+ } catch (error) {
43
+ assert(is<Error>(error));
44
+
45
+ console.log(chalk.red(`Docker command failed: ${cmd}`));
46
+
47
+ console.log(chalk.red(error.message));
48
+
49
+ throw error;
31
50
  }
51
+ }
32
52
 
53
+ {
33
54
  const dCompleted = new Deferred<void>();
34
55
 
35
56
  const child = child_process.spawn(
@@ -56,7 +77,9 @@ export async function dumpContainerConfig(params: {
56
77
  let output = "";
57
78
 
58
79
  const onExit = (code: number | null) => {
59
- dCompleted.reject(new Error(`Exited with code ${code}`));
80
+ dCompleted.reject(
81
+ new Error(`docker exec kc.sh export command failed with code ${code}`)
82
+ );
60
83
  };
61
84
 
62
85
  child.once("exit", onExit);
@@ -96,25 +119,34 @@ export async function dumpContainerConfig(params: {
96
119
 
97
120
  console.log(output);
98
121
 
99
- process.exit(1);
122
+ throw error;
100
123
  }
124
+ }
101
125
 
102
- if (doesUseLockedH2Database) {
103
- const dCompleted = new Deferred<void>();
126
+ if (doesUseLockedH2Database) {
127
+ const dCompleted = new Deferred<void>();
104
128
 
105
- child_process.exec(
106
- `docker exec ${CONTAINER_NAME} sh -c "rm -rf /tmp/h2"`,
107
- error => {
108
- if (error !== null) {
109
- dCompleted.reject(error);
110
- return;
111
- }
129
+ const cmd = `docker exec ${CONTAINER_NAME} sh -c "rm -rf /tmp/h2"`;
112
130
 
113
- dCompleted.resolve();
114
- }
115
- );
131
+ child_process.exec(cmd, error => {
132
+ if (error !== null) {
133
+ dCompleted.reject(error);
134
+ return;
135
+ }
116
136
 
137
+ dCompleted.resolve();
138
+ });
139
+
140
+ try {
117
141
  await dCompleted.pr;
142
+ } catch (error) {
143
+ assert(is<Error>(error));
144
+
145
+ console.log(chalk.red(`Docker command failed: ${cmd}`));
146
+
147
+ console.log(chalk.red(error.message));
148
+
149
+ throw error;
118
150
  }
119
151
  }
120
152
 
@@ -126,8 +158,13 @@ export async function dumpContainerConfig(params: {
126
158
  {
127
159
  const dCompleted = new Deferred<void>();
128
160
 
161
+ const cmd = `docker cp ${CONTAINER_NAME}:/tmp/${realmName}-realm.json ${pathBasename(targetRealmConfigJsonFilePath_tmp)}`;
162
+
129
163
  child_process.exec(
130
- `docker cp ${CONTAINER_NAME}:/tmp/${realmName}-realm.json ${targetRealmConfigJsonFilePath_tmp}`,
164
+ cmd,
165
+ {
166
+ cwd: pathDirname(targetRealmConfigJsonFilePath_tmp)
167
+ },
131
168
  error => {
132
169
  if (error !== null) {
133
170
  dCompleted.reject(error);
@@ -138,7 +175,17 @@ export async function dumpContainerConfig(params: {
138
175
  }
139
176
  );
140
177
 
141
- await dCompleted.pr;
178
+ try {
179
+ await dCompleted.pr;
180
+ } catch (error) {
181
+ assert(is<Error>(error));
182
+
183
+ console.log(chalk.red(`Docker command failed: ${cmd}`));
184
+
185
+ console.log(chalk.red(error.message));
186
+
187
+ throw error;
188
+ }
142
189
  }
143
190
 
144
191
  return readRealmJsonFile({
@@ -276,7 +276,7 @@ function editAccountConsoleAndSecurityAdminConsole(params: {
276
276
  }) {
277
277
  const { parsedRealmJson } = params;
278
278
 
279
- for (const clientId of ["account-console", "security-admin-console"]) {
279
+ for (const clientId of ["account-console", "security-admin-console"] as const) {
280
280
  const client = parsedRealmJson.clients.find(
281
281
  client => client.clientId === clientId
282
282
  );
@@ -298,5 +298,68 @@ function editAccountConsoleAndSecurityAdminConsole(params: {
298
298
  (client.attributes ??= {})["post.logout.redirect.uris"] = "+";
299
299
 
300
300
  client.webOrigins = ["*"];
301
+
302
+ admin_specific: {
303
+ if (clientId !== "security-admin-console") {
304
+ break admin_specific;
305
+ }
306
+
307
+ const protocolMapper_preexisting = client.protocolMappers?.find(
308
+ protocolMapper => {
309
+ if (protocolMapper.protocolMapper !== "oidc-hardcoded-claim-mapper") {
310
+ return false;
311
+ }
312
+
313
+ if (protocolMapper.protocol !== "openid-connect") {
314
+ return false;
315
+ }
316
+
317
+ if (protocolMapper.config === undefined) {
318
+ return false;
319
+ }
320
+
321
+ if (protocolMapper.config["claim.name"] !== "allowed-origins") {
322
+ return false;
323
+ }
324
+
325
+ return true;
326
+ }
327
+ );
328
+
329
+ let protocolMapper: NonNullable<typeof protocolMapper_preexisting>;
330
+
331
+ const config = {
332
+ "introspection.token.claim": "true",
333
+ "claim.value": '["*"]',
334
+ "userinfo.token.claim": "true",
335
+ "id.token.claim": "false",
336
+ "lightweight.claim": "false",
337
+ "access.token.claim": "true",
338
+ "claim.name": "allowed-origins",
339
+ "jsonType.label": "JSON",
340
+ "access.tokenResponse.claim": "false"
341
+ };
342
+
343
+ if (protocolMapper_preexisting !== undefined) {
344
+ protocolMapper = protocolMapper_preexisting;
345
+ } else {
346
+ protocolMapper = {
347
+ id: "8fd0d584-7052-4d04-a615-d18a71050873",
348
+ name: "allowed-origins",
349
+ protocol: "openid-connect",
350
+ protocolMapper: "oidc-hardcoded-claim-mapper",
351
+ consentRequired: false,
352
+ config
353
+ };
354
+
355
+ (client.protocolMappers ??= []).push(protocolMapper);
356
+ }
357
+
358
+ assert(protocolMapper.config !== undefined);
359
+
360
+ if (config !== protocolMapper.config) {
361
+ Object.assign(protocolMapper.config, config);
362
+ }
363
+ }
301
364
  }
302
365
  }
@@ -105,11 +105,19 @@ export async function getRealmConfig(params: {
105
105
  chalk.grey(`Changes detected to the '${realmName}' config, backing up...`)
106
106
  );
107
107
 
108
- const parsedRealmJson = await dumpContainerConfig({
109
- buildContext,
110
- realmName,
111
- keycloakMajorVersionNumber
112
- });
108
+ let parsedRealmJson: ParsedRealmJson;
109
+
110
+ try {
111
+ parsedRealmJson = await dumpContainerConfig({
112
+ buildContext,
113
+ realmName,
114
+ keycloakMajorVersionNumber
115
+ });
116
+ } catch (error) {
117
+ console.log(chalk.red(`Failed to backup '${realmName}' config:`));
118
+
119
+ return;
120
+ }
113
121
 
114
122
  await writeRealmJsonFile({ parsedRealmJson });
115
123