Compare commits
6 Commits
keycloak_c
...
v11.5.1
Author | SHA1 | Date | |
---|---|---|---|
70570faed6 | |||
5d3b7c9a82 | |||
95b9b12a3b | |||
0e027055cb | |||
e47b002535 | |||
8dd6dcd1fc |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "keycloakify",
|
||||
"version": "11.4.5",
|
||||
"version": "11.5.1",
|
||||
"description": "Framework to create custom Keycloak UIs",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -39,7 +39,14 @@ export type ParsedRealmJson = {
|
||||
"post.logout.redirect.uris"?: string;
|
||||
};
|
||||
protocol?: string;
|
||||
protocolMappers?: unknown[];
|
||||
protocolMappers?: {
|
||||
id: string;
|
||||
name: string;
|
||||
protocol: string; // "openid-connect" or something else
|
||||
protocolMapper: string; // "oidc-hardcoded-claim-mapper" or something else
|
||||
consentRequired: boolean;
|
||||
config?: Record<string, string>;
|
||||
}[];
|
||||
}[];
|
||||
};
|
||||
|
||||
@ -89,7 +96,18 @@ const zParsedRealmJson = (() => {
|
||||
})
|
||||
.optional(),
|
||||
protocol: z.string().optional(),
|
||||
protocolMappers: z.array(z.unknown()).optional()
|
||||
protocolMappers: z
|
||||
.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
protocol: z.string(),
|
||||
protocolMapper: z.string(),
|
||||
consentRequired: z.boolean(),
|
||||
config: z.record(z.string()).optional()
|
||||
})
|
||||
)
|
||||
.optional()
|
||||
})
|
||||
)
|
||||
});
|
||||
|
@ -985,6 +985,24 @@
|
||||
"claim.name": "locale",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "8fd0d584-7052-4d04-a615-d18a71050873",
|
||||
"name": "allowed-origins",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-hardcoded-claim-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"introspection.token.claim": "true",
|
||||
"claim.value": "[\"*\"]",
|
||||
"userinfo.token.claim": "true",
|
||||
"id.token.claim": "false",
|
||||
"lightweight.claim": "false",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "allowed-origins",
|
||||
"jsonType.label": "JSON",
|
||||
"access.tokenResponse.claim": "false"
|
||||
}
|
||||
}
|
||||
],
|
||||
"defaultClientScopes": [
|
||||
@ -1640,13 +1658,13 @@
|
||||
"config": {
|
||||
"allowed-protocol-mapper-types": [
|
||||
"oidc-usermodel-property-mapper",
|
||||
"saml-user-attribute-mapper",
|
||||
"saml-user-property-mapper",
|
||||
"oidc-full-name-mapper",
|
||||
"oidc-sha256-pairwise-sub-mapper",
|
||||
"oidc-address-mapper",
|
||||
"saml-user-attribute-mapper",
|
||||
"saml-role-list-mapper",
|
||||
"oidc-sha256-pairwise-sub-mapper",
|
||||
"oidc-usermodel-attribute-mapper",
|
||||
"saml-role-list-mapper"
|
||||
"oidc-full-name-mapper"
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -1676,14 +1694,14 @@
|
||||
"subComponents": {},
|
||||
"config": {
|
||||
"allowed-protocol-mapper-types": [
|
||||
"oidc-sha256-pairwise-sub-mapper",
|
||||
"saml-user-attribute-mapper",
|
||||
"oidc-usermodel-property-mapper",
|
||||
"oidc-full-name-mapper",
|
||||
"saml-role-list-mapper",
|
||||
"oidc-sha256-pairwise-sub-mapper",
|
||||
"saml-user-property-mapper",
|
||||
"oidc-usermodel-attribute-mapper",
|
||||
"oidc-address-mapper"
|
||||
"oidc-usermodel-property-mapper",
|
||||
"saml-role-list-mapper",
|
||||
"oidc-address-mapper",
|
||||
"oidc-usermodel-attribute-mapper"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { CONTAINER_NAME } from "../../shared/constants";
|
||||
import child_process from "child_process";
|
||||
import { join as pathJoin } from "path";
|
||||
import { join as pathJoin, dirname as pathDirname, basename as pathBasename } from "path";
|
||||
import chalk from "chalk";
|
||||
import { Deferred } from "evt/tools/Deferred";
|
||||
import { assert, is } from "tsafe/assert";
|
||||
@ -20,16 +20,37 @@ export async function dumpContainerConfig(params: {
|
||||
}): Promise<ParsedRealmJson> {
|
||||
const { realmName, keycloakMajorVersionNumber, buildContext } = params;
|
||||
|
||||
{
|
||||
// https://github.com/keycloak/keycloak/issues/33800
|
||||
const doesUseLockedH2Database = keycloakMajorVersionNumber >= 25;
|
||||
// https://github.com/keycloak/keycloak/issues/33800
|
||||
const doesUseLockedH2Database = keycloakMajorVersionNumber >= 25;
|
||||
|
||||
if (doesUseLockedH2Database) {
|
||||
child_process.execSync(
|
||||
`docker exec ${CONTAINER_NAME} sh -c "cp -rp /opt/keycloak/data/h2 /tmp"`
|
||||
);
|
||||
if (doesUseLockedH2Database) {
|
||||
const dCompleted = new Deferred<void>();
|
||||
|
||||
const cmd = `docker exec ${CONTAINER_NAME} sh -c "cp -rp /opt/keycloak/data/h2 /tmp"`;
|
||||
|
||||
child_process.exec(cmd, error => {
|
||||
if (error !== null) {
|
||||
dCompleted.reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
dCompleted.resolve();
|
||||
});
|
||||
|
||||
try {
|
||||
await dCompleted.pr;
|
||||
} catch (error) {
|
||||
assert(is<Error>(error));
|
||||
|
||||
console.log(chalk.red(`Docker command failed: ${cmd}`));
|
||||
|
||||
console.log(chalk.red(error.message));
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const dCompleted = new Deferred<void>();
|
||||
|
||||
const child = child_process.spawn(
|
||||
@ -56,7 +77,9 @@ export async function dumpContainerConfig(params: {
|
||||
let output = "";
|
||||
|
||||
const onExit = (code: number | null) => {
|
||||
dCompleted.reject(new Error(`Exited with code ${code}`));
|
||||
dCompleted.reject(
|
||||
new Error(`docker exec kc.sh export command failed with code ${code}`)
|
||||
);
|
||||
};
|
||||
|
||||
child.once("exit", onExit);
|
||||
@ -96,25 +119,34 @@ export async function dumpContainerConfig(params: {
|
||||
|
||||
console.log(output);
|
||||
|
||||
process.exit(1);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (doesUseLockedH2Database) {
|
||||
const dCompleted = new Deferred<void>();
|
||||
if (doesUseLockedH2Database) {
|
||||
const dCompleted = new Deferred<void>();
|
||||
|
||||
child_process.exec(
|
||||
`docker exec ${CONTAINER_NAME} sh -c "rm -rf /tmp/h2"`,
|
||||
error => {
|
||||
if (error !== null) {
|
||||
dCompleted.reject(error);
|
||||
return;
|
||||
}
|
||||
const cmd = `docker exec ${CONTAINER_NAME} sh -c "rm -rf /tmp/h2"`;
|
||||
|
||||
dCompleted.resolve();
|
||||
}
|
||||
);
|
||||
child_process.exec(cmd, error => {
|
||||
if (error !== null) {
|
||||
dCompleted.reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
dCompleted.resolve();
|
||||
});
|
||||
|
||||
try {
|
||||
await dCompleted.pr;
|
||||
} catch (error) {
|
||||
assert(is<Error>(error));
|
||||
|
||||
console.log(chalk.red(`Docker command failed: ${cmd}`));
|
||||
|
||||
console.log(chalk.red(error.message));
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,8 +158,13 @@ export async function dumpContainerConfig(params: {
|
||||
{
|
||||
const dCompleted = new Deferred<void>();
|
||||
|
||||
const cmd = `docker cp ${CONTAINER_NAME}:/tmp/${realmName}-realm.json ${pathBasename(targetRealmConfigJsonFilePath_tmp)}`;
|
||||
|
||||
child_process.exec(
|
||||
`docker cp ${CONTAINER_NAME}:/tmp/${realmName}-realm.json ${targetRealmConfigJsonFilePath_tmp}`,
|
||||
cmd,
|
||||
{
|
||||
cwd: pathDirname(targetRealmConfigJsonFilePath_tmp)
|
||||
},
|
||||
error => {
|
||||
if (error !== null) {
|
||||
dCompleted.reject(error);
|
||||
@ -138,7 +175,17 @@ export async function dumpContainerConfig(params: {
|
||||
}
|
||||
);
|
||||
|
||||
await dCompleted.pr;
|
||||
try {
|
||||
await dCompleted.pr;
|
||||
} catch (error) {
|
||||
assert(is<Error>(error));
|
||||
|
||||
console.log(chalk.red(`Docker command failed: ${cmd}`));
|
||||
|
||||
console.log(chalk.red(error.message));
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return readRealmJsonFile({
|
||||
|
@ -276,7 +276,7 @@ function editAccountConsoleAndSecurityAdminConsole(params: {
|
||||
}) {
|
||||
const { parsedRealmJson } = params;
|
||||
|
||||
for (const clientId of ["account-console", "security-admin-console"]) {
|
||||
for (const clientId of ["account-console", "security-admin-console"] as const) {
|
||||
const client = parsedRealmJson.clients.find(
|
||||
client => client.clientId === clientId
|
||||
);
|
||||
@ -298,5 +298,68 @@ function editAccountConsoleAndSecurityAdminConsole(params: {
|
||||
(client.attributes ??= {})["post.logout.redirect.uris"] = "+";
|
||||
|
||||
client.webOrigins = ["*"];
|
||||
|
||||
admin_specific: {
|
||||
if (clientId !== "security-admin-console") {
|
||||
break admin_specific;
|
||||
}
|
||||
|
||||
const protocolMapper_preexisting = client.protocolMappers?.find(
|
||||
protocolMapper => {
|
||||
if (protocolMapper.protocolMapper !== "oidc-hardcoded-claim-mapper") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (protocolMapper.protocol !== "openid-connect") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (protocolMapper.config === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (protocolMapper.config["claim.name"] !== "allowed-origins") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
let protocolMapper: NonNullable<typeof protocolMapper_preexisting>;
|
||||
|
||||
const config = {
|
||||
"introspection.token.claim": "true",
|
||||
"claim.value": '["*"]',
|
||||
"userinfo.token.claim": "true",
|
||||
"id.token.claim": "false",
|
||||
"lightweight.claim": "false",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "allowed-origins",
|
||||
"jsonType.label": "JSON",
|
||||
"access.tokenResponse.claim": "false"
|
||||
};
|
||||
|
||||
if (protocolMapper_preexisting !== undefined) {
|
||||
protocolMapper = protocolMapper_preexisting;
|
||||
} else {
|
||||
protocolMapper = {
|
||||
id: "8fd0d584-7052-4d04-a615-d18a71050873",
|
||||
name: "allowed-origins",
|
||||
protocol: "openid-connect",
|
||||
protocolMapper: "oidc-hardcoded-claim-mapper",
|
||||
consentRequired: false,
|
||||
config
|
||||
};
|
||||
|
||||
(client.protocolMappers ??= []).push(protocolMapper);
|
||||
}
|
||||
|
||||
assert(protocolMapper.config !== undefined);
|
||||
|
||||
if (config !== protocolMapper.config) {
|
||||
Object.assign(protocolMapper.config, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,11 +105,19 @@ export async function getRealmConfig(params: {
|
||||
chalk.grey(`Changes detected to the '${realmName}' config, backing up...`)
|
||||
);
|
||||
|
||||
const parsedRealmJson = await dumpContainerConfig({
|
||||
buildContext,
|
||||
realmName,
|
||||
keycloakMajorVersionNumber
|
||||
});
|
||||
let parsedRealmJson: ParsedRealmJson;
|
||||
|
||||
try {
|
||||
parsedRealmJson = await dumpContainerConfig({
|
||||
buildContext,
|
||||
realmName,
|
||||
keycloakMajorVersionNumber
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(chalk.red(`Failed to backup '${realmName}' config:`));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await writeRealmJsonFile({ parsedRealmJson });
|
||||
|
||||
|
@ -44,6 +44,7 @@ export function startViteDevServer(params: {
|
||||
//Local: http://localhost:8083/
|
||||
const match = data
|
||||
.toString("utf8")
|
||||
.replace(/\x1b[[0-9;]*m/g, "")
|
||||
.match(/Local:\s*http:\/\/(?:localhost|127\.0\.0\.1):(\d+)\//);
|
||||
|
||||
if (match === null) {
|
||||
|
Reference in New Issue
Block a user