UNPKG

testcontainers-keycloak

Version:
174 lines (173 loc) 7.68 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.StartedKeycloakContainer = exports.KeycloakContainer = void 0; const testcontainers_1 = require("testcontainers"); const axios_1 = __importDefault(require("axios")); const qs_1 = __importDefault(require("qs")); class KeycloakContainer extends testcontainers_1.GenericContainer { waitingLog = 'Admin console listening on http://127.0.0.1:9990'; adminUsername = 'admin'; adminPassword = 'admin'; constructor(image = 'quay.io/keycloak/keycloak:16.1.1') { super(image); } withWaitingLog(log) { this.waitingLog = log; } withAdminUsername(username) { this.adminUsername = username; return this; } withAdminPassword(password) { this.adminPassword = password; return this; } async start() { this.withWaitStrategy(testcontainers_1.Wait.forLogMessage(this.waitingLog)) .withEnvironment({ KEYCLOAK_USER: this.adminUsername }) .withEnvironment({ KEYCLOAK_PASSWORD: this.adminPassword }); return new StartedKeycloakContainer(await super.start(), this.adminUsername, this.adminPassword); } } exports.KeycloakContainer = KeycloakContainer; class StartedKeycloakContainer extends testcontainers_1.AbstractStartedContainer { adminUsername; adminPassword; KCADM = `/opt/jboss/keycloak/bin/kcadm.sh`; SERVER = 'http://localhost:8080'; constructor(startedTestContainer, adminUsername, adminPassword) { super(startedTestContainer); this.adminUsername = adminUsername; this.adminPassword = adminPassword; } getAdminUsername() { return this.adminUsername; } getAdminPassword() { return this.adminPassword; } async runCmd(command) { const commandArray = command.split(' '); const execResult = await this.exec(commandArray); if (execResult.exitCode === 0) { return Promise.resolve(execResult.output.trim()); } else { return Promise.reject(execResult.output.trim()); } } /** * Start an authenticated session on this keycloak server * @params realmName th3 realm name you want to config * @params user the user who starting this session, usually the username of admin * @params user password, usually is the password of admin */ async configCredentials(realmName, user, password) { return await this.runCmd(`${this.KCADM} config credentials --server ${this.SERVER}/auth --realm ${realmName} --user ${user} --password ${password}`); } async createRealm(realmName, enabled = true) { return await this.runCmd(`${this.KCADM} create realms -s realm=${realmName} -s enabled=${enabled}`); } async getRealm(realmName) { const realmResult = await this.runCmd(`${this.KCADM} get realms/${realmName}`); const realm = JSON.parse(realmResult); return realm; } async createUser(realmName, username, firstName, lastName, enabled = true) { return await this.runCmd(`${this.KCADM} create users -r ${realmName} -s username=${username} -s firstName=${firstName} -s lastName=${lastName} -s enabled=${enabled}`); } async getUserById(realmName, userId) { const userResult = await this.runCmd(`${this.KCADM} get users/${userId} -r ${realmName}`); const user = JSON.parse(userResult); return user; } async getUserIdByUsername(realmName, username) { const usersResult = await this.runCmd(`${this.KCADM} get users -r ${realmName} -q username=${username}`); const userArray = JSON.parse(usersResult); if (userArray.length === 1) { return Promise.resolve(userArray[0].id); } else { return Promise.reject(`Cannot find username '${username}' in realm '${realmName}'`); } } async setUserPassword(realmName, username, password) { return await this.runCmd(`${this.KCADM} set-password -r ${realmName} --username ${username} --new-password ${password}`); } async createClient(realmName, clientId, clientSecret, redirectUris = [], webOrigins = [], directAccessGrantsEnabled = true, enabled = true) { const redirectUrisString = redirectUris.map((uri) => `"${uri}"`).join(','); const webOriginsString = webOrigins.map((uri) => `"${uri}"`).join(','); return await this.runCmd(`${this.KCADM} create clients -r ${realmName} -s clientId=${clientId} -s secret=${clientSecret} -s enabled=${enabled} -s redirectUris=[${redirectUrisString}] -s webOrigins=[${webOriginsString}] -s directAccessGrantsEnabled=${directAccessGrantsEnabled}`); } async getCidByClientId(realmName, clientId) { const clientsResult = await this.runCmd(`${this.KCADM} get clients -r ${realmName} --fields id -q clientId=${clientId}`); const clients = JSON.parse(clientsResult); if (clients.length === 1) { return Promise.resolve(clients[0]['id']); } else { return Promise.reject(`Can't find client '${clientId}' in realm '${realmName}'`); } } async getClientByCid(realmName, cid) { const clientResult = await this.runCmd(`${this.KCADM} get clients/${cid} -r ${realmName}`); const client = JSON.parse(clientResult); return client; } async getClientSecretByCid(realmName, cid) { const clientSecretResult = await this.runCmd(`${this.KCADM} get clients/${cid}/client-secret -r ${realmName}`); const secret = JSON.parse(clientSecretResult); return secret; } async getAccessToken(realmName, username, password, clientId, clientSecret) { const tokenEndpoint = `http://${this.getHost()}:${this.getMappedPort(8080)}/auth/realms/${realmName}/protocol/openid-connect/token`; const payload = qs_1.default.stringify({ username, password, client_id: clientId, client_secret: clientSecret, grant_type: 'password' }); try { const response = await axios_1.default.post(tokenEndpoint, payload); const accessToken = response.data['access_token']; if (accessToken) { return accessToken; } else { throw new Error(`Failed to get access_token: access_token undefined`); } } catch (error) { throw new Error(`Failed to get access_token: ${error}`); } } async getIdToken(realmName, username, password, clientId, clientSecret) { const tokenEndpoint = `http://${this.getHost()}:${this.getMappedPort(8080)}/auth/realms/${realmName}/protocol/openid-connect/token`; const payload = qs_1.default.stringify({ username, password, client_id: clientId, client_secret: clientSecret, grant_type: 'password', scope: 'openid' }); try { const response = await axios_1.default.post(tokenEndpoint, payload); const idToken = response.data['id_token']; if (idToken) { return idToken; } else { throw new Error(`Failed to get id_token: id_token undefined`); } } catch (error) { throw new Error(`Failed to get id_token: ${error}`); } } } exports.StartedKeycloakContainer = StartedKeycloakContainer;