Skip to content

Commit

Permalink
Merge pull request #1453 from cloud-pi-native/refactor/keycloak-internal
Browse files Browse the repository at this point in the history
Refactor/keycloak-internal
  • Loading branch information
ArnaudTA authored Nov 13, 2024
2 parents e312088 + d0f63f3 commit 3471ee8
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 43 deletions.
29 changes: 12 additions & 17 deletions plugins/keycloak/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
import KcAdminClient from '@keycloak/keycloak-admin-client'
import { requiredEnv } from '@cpn-console/shared'

export const keycloakToken = process.env.KEYCLOAK_ADMIN_PASSWORD
export const keycloakUser = process.env.KEYCLOAK_ADMIN

let keycloakDomain: string | undefined
let keycloakProtocol: string | undefined
let keycloakRealm: string | undefined
import getConfig from './config.js'

export async function getkcClient() {
keycloakDomain = keycloakDomain ?? requiredEnv('KEYCLOAK_DOMAIN')
keycloakProtocol = keycloakProtocol ?? requiredEnv('KEYCLOAK_PROTOCOL')
keycloakRealm = keycloakRealm ?? requiredEnv('KEYCLOAK_REALM')

const kcClient = new KcAdminClient({
baseUrl: `${keycloakProtocol}://${keycloakDomain}`,
baseUrl: getConfig().url,
})

await kcClient.auth({
clientId: 'admin-cli',
grantType: 'password',
username: keycloakUser,
password: keycloakToken,
username: process.env.KEYCLOAK_ADMIN,
password: process.env.KEYCLOAK_ADMIN_PASSWORD,
})
kcClient.setConfig({ realmName: keycloakRealm })
kcClient.setConfig({ realmName: getConfig().realm })
return kcClient
}

export function start() {
getkcClient()
getkcClient().catch((error) => {
console.log(error)
if (process.env.IGNORE_PLUGINS_START_FAIL?.includes('keycloak')) {
return
}
throw new Error('failed to start keycloak plugin')
})
}
23 changes: 23 additions & 0 deletions plugins/keycloak/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { removeTrailingSlash, requiredEnv } from '@cpn-console/shared'

class Config {
url: string
realm: string

constructor() {
this.url = process.env.KEYCLOAK_INTERNAL_URL
? removeTrailingSlash(process.env.KEYCLOAK_INTERNAL_URL)
: `${requiredEnv('KEYCLOAK_PROTOCOL')}://${requiredEnv('KEYCLOAK_DOMAIN')}`
this.realm = requiredEnv('KEYCLOAK_REALM')
}
}

let config: Config | undefined

function getConfig() {
if (!config) {
config = new Config()
}
return config
}
export default getConfig
64 changes: 38 additions & 26 deletions plugins/keycloak/src/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,24 +66,27 @@ export const upsertProject: StepCall<Project> = async ({ args: project }) => {
const projectGroup = await getOrCreateProjectGroup(kcClient, projectName)
const groupMembers = await kcClient.groups.listMembers({ id: projectGroup.id })

// Ensure project membership exists
for (const member of groupMembers) {
if (!project.users.some(({ id }) => id === member.id)) {
await kcClient.users.delFromGroup({
await Promise.all([
...groupMembers.map((member) => {
if (!project.users.some(({ id }) => id === member.id)) {
return kcClient.users.delFromGroup({
// @ts-ignore id is present on user, bad typing in lib
id: member.id,
groupId: projectGroup.id,
})
}
}
for (const user of project.users) {
if (!groupMembers.some(({ id }) => id === user.id)) {
await kcClient.users.addToGroup({
id: user.id,
groupId: projectGroup.id,
})
}
}
id: member.id,
groupId: projectGroup.id,
})
}
return undefined
}),
...project.users.map((user) => {
if (!groupMembers.some(({ id }) => id === user.id)) {
return kcClient.users.addToGroup({
id: user.id,
groupId: projectGroup.id,
})
}
return undefined
}),
])

// Ensure envs subgroups exists
const projectGroups = await getAllSubgroups(kcClient, projectGroup.id, 0)
Expand All @@ -93,30 +96,39 @@ export const upsertProject: StepCall<Project> = async ({ args: project }) => {

const envGroups = await getAllSubgroups(kcClient, consoleGroup.id, 0) as CustomGroup[]

const promises: Promise<any>[] = []
for (const environment of project.environments) {
const envGroup: Required<CustomGroup> = envGroups.find(group => group.name === environment.name) as Required<CustomGroup>
?? await getOrCreateChildGroup(kcClient, consoleGroup.id, environment.name)

const roGroup = await getOrCreateChildGroup(kcClient, envGroup.id, 'RO')
const rwGroup = await getOrCreateChildGroup(kcClient, envGroup.id, 'RW')
const [roGroup, rwGroup] = await Promise.all([
getOrCreateChildGroup(kcClient, envGroup.id, 'RO'),
getOrCreateChildGroup(kcClient, envGroup.id, 'RW'),
])

// Ensure envs permissions membership exists
for (const permission of environment.permissions) {
if (permission.permissions.ro) {
await kcClient.users.addToGroup({ id: permission.userId, groupId: roGroup.id })
promises.push(kcClient.users.addToGroup({ id: permission.userId, groupId: roGroup.id }))
} else {
await kcClient.users.delFromGroup({ id: permission.userId, groupId: roGroup.id })
promises.push(kcClient.users.delFromGroup({ id: permission.userId, groupId: roGroup.id }))
}
if (permission.permissions.rw) {
await kcClient.users.addToGroup({ id: permission.userId, groupId: rwGroup.id })
} else { await kcClient.users.delFromGroup({ id: permission.userId, groupId: rwGroup.id }) }
promises.push(kcClient.users.addToGroup({ id: permission.userId, groupId: rwGroup.id }))
} else {
promises.push(kcClient.users.delFromGroup({ id: permission.userId, groupId: rwGroup.id }))
}
}
}
for (const subGroup of envGroups) {

await Promise.all(promises)

await Promise.all(envGroups.map((subGroup) => {
if (!project.environments.some(({ name }) => name === subGroup.name)) {
kcClient.groups.del({ id: subGroup.id })
return kcClient.groups.del({ id: subGroup.id })
}
}
return undefined
}))

return {
status: {
Expand Down

0 comments on commit 3471ee8

Please sign in to comment.