feat: add keycloak and postgres
This commit is contained in:
70
keycloak/scripts/add-audience-mapper.ts
Normal file
70
keycloak/scripts/add-audience-mapper.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmName = process.env.KEYCLOAK_REALM;
|
||||
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
|
||||
|
||||
const clientId = process.env.KEYCLOAK_CLIENT_ID;
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID environment variable is required");
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
const clients = await kcAdminClient.clients.find({ clientId });
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found.`);
|
||||
}
|
||||
const client = clients[0];
|
||||
invariant(client.id, "Client ID is not set");
|
||||
|
||||
const mapperName = `aud-mapper-${clientId}`;
|
||||
const audienceMapper = {
|
||||
name: mapperName,
|
||||
protocol: "openid-connect",
|
||||
protocolMapper: "oidc-audience-mapper",
|
||||
config: {
|
||||
"included.client.audience": clientId,
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
},
|
||||
};
|
||||
|
||||
const existingMappers = await kcAdminClient.clients.listProtocolMappers({ id: client.id });
|
||||
|
||||
if (existingMappers.some((mapper) => mapper.name === mapperName)) {
|
||||
console.warn(`Audience Mapper '${mapperName}' already exists for the client.`);
|
||||
} else {
|
||||
await kcAdminClient.clients.addProtocolMapper({ id: client.id }, audienceMapper);
|
||||
console.log(`Audience Mapper '${mapperName}' added directly to the client.`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("An error occurred:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
121
keycloak/scripts/add-minio-policy.ts
Normal file
121
keycloak/scripts/add-minio-policy.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmName = process.env.KEYCLOAK_REALM;
|
||||
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
|
||||
|
||||
const minioClientId = process.env.MINIO_OIDC_CLIENT_ID;
|
||||
invariant(minioClientId, "MINIO_OIDC_CLIENT_ID environment variable is required");
|
||||
|
||||
const policyValue = process.env.MINIO_POLICY || "readwrite";
|
||||
console.log(`Setting minioPolicy attribute with value: ${policyValue}`);
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
// Set realm to work with
|
||||
kcAdminClient.setConfig({
|
||||
realmName,
|
||||
});
|
||||
|
||||
// Get current User Profile configuration
|
||||
const userProfile = await kcAdminClient.users.getProfile();
|
||||
|
||||
// Check if minioPolicy attribute already exists
|
||||
const existingAttribute = userProfile.attributes?.find(
|
||||
(attr: any) => attr.name === "minioPolicy"
|
||||
);
|
||||
|
||||
if (existingAttribute) {
|
||||
console.log("minioPolicy attribute already exists in User Profile.");
|
||||
} else {
|
||||
// Add minioPolicy attribute to User Profile with proper permissions
|
||||
if (!userProfile.attributes) {
|
||||
userProfile.attributes = [];
|
||||
}
|
||||
|
||||
userProfile.attributes.push({
|
||||
name: "minioPolicy",
|
||||
displayName: "MinIO Policy",
|
||||
permissions: {
|
||||
view: ["admin", "user"],
|
||||
edit: ["admin"],
|
||||
},
|
||||
validations: {
|
||||
options: { options: ["readwrite", "readonly", "writeonly"] },
|
||||
},
|
||||
});
|
||||
|
||||
// Update User Profile
|
||||
await kcAdminClient.users.updateProfile(userProfile);
|
||||
console.log(
|
||||
"minioPolicy attribute added to User Profile successfully with admin edit permissions."
|
||||
);
|
||||
}
|
||||
|
||||
// Create protocol mapper for the minioPolicy attribute if it doesn't exist
|
||||
const minioClient = await kcAdminClient.clients.find({ clientId: minioClientId });
|
||||
if (minioClient.length === 0) {
|
||||
console.error(`Client '${minioClientId}' not found.`);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
const clientId = minioClient[0].id;
|
||||
invariant(clientId, "Client ID is required");
|
||||
|
||||
// Check if the mapper already exists
|
||||
const mappers = await kcAdminClient.clients.listProtocolMappers({ id: clientId });
|
||||
const existingMapper = mappers.find((mapper) => mapper.name === "MinIO Policy");
|
||||
|
||||
if (existingMapper) {
|
||||
console.log("MinIO Policy mapper already exists.");
|
||||
} else {
|
||||
// Create the protocol mapper
|
||||
await kcAdminClient.clients.addProtocolMapper(
|
||||
{ id: clientId },
|
||||
{
|
||||
name: "MinIO Policy",
|
||||
protocol: "openid-connect",
|
||||
protocolMapper: "oidc-usermodel-attribute-mapper",
|
||||
config: {
|
||||
"userinfo.token.claim": "true",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "minioPolicy",
|
||||
"jsonType.label": "String",
|
||||
"user.attribute": "minioPolicy",
|
||||
multivalued: "false",
|
||||
},
|
||||
}
|
||||
);
|
||||
console.log("MinIO Policy mapper created successfully.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("An error occurred:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
76
keycloak/scripts/add-user-to-group.ts
Normal file
76
keycloak/scripts/add-user-to-group.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmName = process.env.KEYCLOAK_REALM;
|
||||
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
|
||||
|
||||
const username = process.env.USERNAME;
|
||||
invariant(username, "USERNAME environment variable is required");
|
||||
|
||||
const groupName = process.env.GROUP_NAME;
|
||||
invariant(groupName, "GROUP_NAME environment variable is required");
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
// Find user
|
||||
const users = await kcAdminClient.users.find({ username });
|
||||
const user = users.find(u => u.username === username);
|
||||
if (!user) {
|
||||
throw new Error(`User '${username}' not found`);
|
||||
}
|
||||
|
||||
// Find group
|
||||
const groups = await kcAdminClient.groups.find({ search: groupName });
|
||||
const group = groups.find(g => g.name === groupName);
|
||||
if (!group) {
|
||||
throw new Error(`Group '${groupName}' not found`);
|
||||
}
|
||||
|
||||
// Check if user is already in group
|
||||
const userGroups = await kcAdminClient.users.listGroups({ id: user.id! });
|
||||
const isAlreadyMember = userGroups.some(ug => ug.id === group.id);
|
||||
|
||||
if (isAlreadyMember) {
|
||||
console.log(`User '${username}' is already a member of group '${groupName}'`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add user to group
|
||||
await kcAdminClient.users.addToGroup({
|
||||
id: user.id!,
|
||||
groupId: group.id!,
|
||||
});
|
||||
|
||||
console.log(`User '${username}' added to group '${groupName}' successfully`);
|
||||
} catch (error) {
|
||||
console.error("Error adding user to group:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
64
keycloak/scripts/create-client.ts
Normal file
64
keycloak/scripts/create-client.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmName = process.env.KEYCLOAK_REALM;
|
||||
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
|
||||
|
||||
const clientId = process.env.KEYCLOAK_CLIENT_ID;
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID environment variable is required");
|
||||
|
||||
const clientSecret = process.env.KEYCLOAK_CLIENT_SECRET;
|
||||
|
||||
const redirectUrl = process.env.KEYCLOAK_REDIRECT_URL;
|
||||
invariant(redirectUrl, "KEYCLOAK_REDIRECT_URL environment variable is required");
|
||||
|
||||
const redirectUris = redirectUrl.split(',').map(url => url.trim());
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
const existingClients = await kcAdminClient.clients.find({ clientId });
|
||||
if (existingClients.length > 0) {
|
||||
console.warn(`Client '${clientId}' already exists.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const createdClient = await kcAdminClient.clients.create({
|
||||
clientId: clientId,
|
||||
secret: clientSecret,
|
||||
enabled: true,
|
||||
redirectUris: redirectUris,
|
||||
publicClient: clientSecret && clientSecret !== '' ? false : true,
|
||||
});
|
||||
console.log(`Client created successfully with ID: ${createdClient.id}`);
|
||||
} catch (error) {
|
||||
console.error("An error occurred:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
82
keycloak/scripts/create-group.ts
Normal file
82
keycloak/scripts/create-group.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmName = process.env.KEYCLOAK_REALM;
|
||||
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
|
||||
|
||||
const groupName = process.env.GROUP_NAME;
|
||||
invariant(groupName, "GROUP_NAME environment variable is required");
|
||||
|
||||
const parentGroupName = process.env.PARENT_GROUP_NAME || "";
|
||||
const groupDescription = process.env.GROUP_DESCRIPTION || "";
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
// Check if group already exists
|
||||
const existingGroups = await kcAdminClient.groups.find({ search: groupName });
|
||||
const existingGroup = existingGroups.find(group => group.name === groupName);
|
||||
|
||||
if (existingGroup) {
|
||||
console.log(`Group '${groupName}' already exists with ID: ${existingGroup.id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find parent group if specified
|
||||
let parentGroupId: string | undefined;
|
||||
if (parentGroupName) {
|
||||
const parentGroups = await kcAdminClient.groups.find({ search: parentGroupName });
|
||||
const parentGroup = parentGroups.find(group => group.name === parentGroupName);
|
||||
if (!parentGroup) {
|
||||
throw new Error(`Parent group '${parentGroupName}' not found`);
|
||||
}
|
||||
parentGroupId = parentGroup.id;
|
||||
}
|
||||
|
||||
// Create group payload
|
||||
const groupPayload = {
|
||||
name: groupName,
|
||||
...(groupDescription && { attributes: { description: [groupDescription] } }),
|
||||
};
|
||||
|
||||
// Create group
|
||||
const group = parentGroupId
|
||||
? await kcAdminClient.groups.createChildGroup({ id: parentGroupId }, groupPayload)
|
||||
: await kcAdminClient.groups.create(groupPayload);
|
||||
|
||||
console.log(`Group '${groupName}' created successfully with ID: ${group.id}`);
|
||||
|
||||
if (parentGroupName) {
|
||||
console.log(`Group '${groupName}' created as child of '${parentGroupName}'`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error creating group:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
50
keycloak/scripts/create-realm.ts
Normal file
50
keycloak/scripts/create-realm.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmName = process.env.KEYCLOAK_REALM;
|
||||
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
const existingRealms = await kcAdminClient.realms.find();
|
||||
const realmExists = existingRealms.some((realm) => realm.realm === realmName);
|
||||
if (realmExists) {
|
||||
console.warn(`Realm '${realmName}' already exists.`);
|
||||
return;
|
||||
}
|
||||
|
||||
await kcAdminClient.realms.create({
|
||||
realm: realmName,
|
||||
enabled: true,
|
||||
});
|
||||
console.log(`Realm '${realmName}' created successfully.`);
|
||||
} catch (error) {
|
||||
console.error("An error occurred:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
99
keycloak/scripts/create-user.ts
Normal file
99
keycloak/scripts/create-user.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmName = process.env.KEYCLOAK_REALM;
|
||||
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
|
||||
|
||||
const username = process.env.USERNAME;
|
||||
invariant(username, "USERNAME environment variable is required");
|
||||
|
||||
const email = process.env.EMAIL;
|
||||
const firstName = process.env.FIRST_NAME;
|
||||
const lastName = process.env.LAST_NAME;
|
||||
|
||||
const password = process.env.PASSWORD;
|
||||
invariant(password, "PASSWORD environment variable is required");
|
||||
|
||||
const createAsAdmin = process.env.CREATE_AS_ADMIN === "true";
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
const userPayload = {
|
||||
username,
|
||||
email,
|
||||
emailVerified: true,
|
||||
firstName,
|
||||
lastName,
|
||||
enabled: true,
|
||||
};
|
||||
const user = await kcAdminClient.users.create(userPayload);
|
||||
console.log(`User created successfully with ID: ${user.id}`);
|
||||
|
||||
if (createAsAdmin && realmName === "master") {
|
||||
const adminRole = await kcAdminClient.roles.findOneByName({
|
||||
realm: "master",
|
||||
name: "admin",
|
||||
});
|
||||
|
||||
const createRealmRole = await kcAdminClient.roles.findOneByName({
|
||||
realm: "master",
|
||||
name: "create-realm",
|
||||
});
|
||||
|
||||
await kcAdminClient.users.addRealmRoleMappings({
|
||||
realm: "master",
|
||||
id: user.id,
|
||||
roles: [
|
||||
{
|
||||
id: adminRole!.id!,
|
||||
name: adminRole!.name!,
|
||||
},
|
||||
{
|
||||
id: createRealmRole!.id!,
|
||||
name: createRealmRole!.name!,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
await kcAdminClient.users.resetPassword({
|
||||
id: user.id!,
|
||||
credential: {
|
||||
type: "password",
|
||||
value: password,
|
||||
temporary: false,
|
||||
},
|
||||
});
|
||||
console.log(`Password set for user '${user.id}'.`);
|
||||
} catch (error) {
|
||||
console.error("Error creating user:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
54
keycloak/scripts/delete-client.ts
Normal file
54
keycloak/scripts/delete-client.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmName = process.env.KEYCLOAK_REALM;
|
||||
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
|
||||
|
||||
const clientId = process.env.KEYCLOAK_CLIENT_ID;
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID environment variable is required");
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: 'master',
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
const existingClients = await kcAdminClient.clients.find({ clientId });
|
||||
if (existingClients.length === 0) {
|
||||
console.warn(`Client '${clientId}' does not exist.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const client = existingClients[0];
|
||||
invariant(client.id, "Client ID is not set");
|
||||
|
||||
await kcAdminClient.clients.del({ id: client.id });
|
||||
console.log(`Client '${clientId}' successfully deleted.`);
|
||||
} catch (error) {
|
||||
console.error("An error occurred:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
76
keycloak/scripts/delete-group.ts
Normal file
76
keycloak/scripts/delete-group.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmName = process.env.KEYCLOAK_REALM;
|
||||
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
|
||||
|
||||
const groupName = process.env.GROUP_NAME;
|
||||
invariant(groupName, "GROUP_NAME environment variable is required");
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
// Find group to delete
|
||||
const groups = await kcAdminClient.groups.find({ search: groupName });
|
||||
const group = groups.find(g => g.name === groupName);
|
||||
|
||||
if (!group) {
|
||||
console.log(`Group '${groupName}' not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if group has members
|
||||
const groupMembers = await kcAdminClient.groups.listMembers({ id: group.id! });
|
||||
if (groupMembers.length > 0) {
|
||||
console.log(`Warning: Group '${groupName}' has ${groupMembers.length} members:`);
|
||||
groupMembers.forEach(member => {
|
||||
console.log(` - ${member.username} (${member.firstName} ${member.lastName})`);
|
||||
});
|
||||
console.log("All members will be removed from the group when it's deleted.");
|
||||
}
|
||||
|
||||
// Check for subgroups
|
||||
const subGroups = await kcAdminClient.groups.listSubGroups({ id: group.id! });
|
||||
if (subGroups.length > 0) {
|
||||
console.log(`Warning: Group '${groupName}' has ${subGroups.length} subgroups:`);
|
||||
subGroups.forEach(subGroup => {
|
||||
console.log(` - ${subGroup.name}`);
|
||||
});
|
||||
console.log("All subgroups will be deleted as well.");
|
||||
}
|
||||
|
||||
// Delete group
|
||||
await kcAdminClient.groups.del({ id: group.id! });
|
||||
|
||||
console.log(`Group '${groupName}' deleted successfully`);
|
||||
} catch (error) {
|
||||
console.error("Error deleting group:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
61
keycloak/scripts/delete-realm.ts
Normal file
61
keycloak/scripts/delete-realm.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmNameToDelete = process.env.KEYCLOAK_REALM_TO_DELETE;
|
||||
invariant(realmNameToDelete, "KEYCLOAK_REALM_TO_DELETE environment variable is required");
|
||||
|
||||
if (realmNameToDelete === "master") {
|
||||
console.error("Error: Deleting the 'master' realm is a highly destructive operation and is not allowed by this script.");
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master", // Authenticate against master realm to delete other realms
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful with master realm.");
|
||||
|
||||
// Check if realm exists before attempting deletion
|
||||
const realm = await kcAdminClient.realms.findOne({ realm: realmNameToDelete });
|
||||
|
||||
if (!realm) {
|
||||
console.warn(`Realm '${realmNameToDelete}' not found. Nothing to delete.`);
|
||||
return; // Exit gracefully if realm doesn't exist
|
||||
}
|
||||
|
||||
console.log(`Attempting to delete realm: '${realmNameToDelete}'...`);
|
||||
await kcAdminClient.realms.del({ realm: realmNameToDelete });
|
||||
console.log(`Realm '${realmNameToDelete}' deleted successfully.`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`An error occurred while trying to delete realm '${realmNameToDelete}':`, error);
|
||||
const err = error as any;
|
||||
if (err.response?.data) {
|
||||
console.error("Error details:", JSON.stringify(err.response.data, undefined, 2));
|
||||
}
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
76
keycloak/scripts/delete-user-from-group.ts
Normal file
76
keycloak/scripts/delete-user-from-group.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmName = process.env.KEYCLOAK_REALM;
|
||||
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
|
||||
|
||||
const username = process.env.USERNAME;
|
||||
invariant(username, "USERNAME environment variable is required");
|
||||
|
||||
const groupName = process.env.GROUP_NAME;
|
||||
invariant(groupName, "GROUP_NAME environment variable is required");
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
// Find user
|
||||
const users = await kcAdminClient.users.find({ username });
|
||||
const user = users.find(u => u.username === username);
|
||||
if (!user) {
|
||||
throw new Error(`User '${username}' not found`);
|
||||
}
|
||||
|
||||
// Find group
|
||||
const groups = await kcAdminClient.groups.find({ search: groupName });
|
||||
const group = groups.find(g => g.name === groupName);
|
||||
if (!group) {
|
||||
throw new Error(`Group '${groupName}' not found`);
|
||||
}
|
||||
|
||||
// Check if user is in group
|
||||
const userGroups = await kcAdminClient.users.listGroups({ id: user.id! });
|
||||
const isMember = userGroups.some(ug => ug.id === group.id);
|
||||
|
||||
if (!isMember) {
|
||||
console.log(`User '${username}' is not a member of group '${groupName}'`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove user from group
|
||||
await kcAdminClient.users.delFromGroup({
|
||||
id: user.id!,
|
||||
groupId: group.id!,
|
||||
});
|
||||
|
||||
console.log(`User '${username}' removed from group '${groupName}' successfully`);
|
||||
} catch (error) {
|
||||
console.error("Error removing user from group:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
60
keycloak/scripts/delete-user.ts
Normal file
60
keycloak/scripts/delete-user.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmName = process.env.KEYCLOAK_REALM;
|
||||
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
|
||||
|
||||
const usernameToDelete = process.env.USERNAME;
|
||||
invariant(
|
||||
usernameToDelete,
|
||||
"USERNAME environment variable (for the user to be deleted) is required"
|
||||
);
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
const users = await kcAdminClient.users.find({ username: usernameToDelete });
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn(`User '${usernameToDelete}' not found in realm '${realmName}'.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const user = users[0];
|
||||
invariant(user.id, `User ID not found for user '${usernameToDelete}'.`);
|
||||
|
||||
await kcAdminClient.users.del({ id: user.id });
|
||||
console.log(
|
||||
`User '${usernameToDelete}' (ID: ${user.id}) successfully deleted from realm '${realmName}'.`
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("An error occurred during user deletion:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
57
keycloak/scripts/user-exists.ts
Normal file
57
keycloak/scripts/user-exists.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
|
||||
|
||||
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
|
||||
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
|
||||
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
|
||||
const realmName = process.env.KEYCLOAK_REALM;
|
||||
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
|
||||
|
||||
const username = process.env.USERNAME;
|
||||
invariant(username, "USERNAME environment variable is required");
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
const users = await kcAdminClient.users.find({
|
||||
username,
|
||||
exact: true,
|
||||
});
|
||||
|
||||
if (users && users.length > 0) {
|
||||
console.log(`User '${username}' exists with ID: ${users[0].id}`);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.log(`User '${username}' does not exist.`);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error checking user existence:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user