api keycloak setup
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export * from "./keycloak-admin.js";
|
||||
@@ -0,0 +1,74 @@
|
||||
import RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
|
||||
import { Injectable } from "../../../infrastructure/di/injectable-decorator";
|
||||
import kcClientConfig from "./nodejs-api.json" with { type: "json" };
|
||||
|
||||
import KeycloakAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import { Claim } from "../../../models/claim";
|
||||
import { User } from "../../../models/user";
|
||||
|
||||
@Injectable()
|
||||
export class KeycloakAdmin {
|
||||
private readonly kcAdminClient: Promise<KeycloakAdminClient>;
|
||||
constructor() {
|
||||
this.kcAdminClient = new Promise(async resolve => {
|
||||
const client = new KeycloakAdminClient({
|
||||
baseUrl: kcClientConfig.baseUrl,
|
||||
realmName: "taekwondo",
|
||||
});
|
||||
|
||||
await client.auth({
|
||||
...kcClientConfig,
|
||||
grantType: "client_credentials",
|
||||
});
|
||||
resolve(client);
|
||||
});
|
||||
}
|
||||
|
||||
public async addRoleToUser(uid: string, roleName: string): Promise<void> {
|
||||
const client = await this.kcAdminClient;
|
||||
const role = await this.getRole(roleName);
|
||||
if (!role.id || !role.name) {
|
||||
throw new Error(`Role ${roleName} is missing id or name`);
|
||||
}
|
||||
|
||||
await client.users.addRealmRoleMappings({
|
||||
id: uid,
|
||||
roles: [{ id: role.id, name: role.name }],
|
||||
});
|
||||
}
|
||||
|
||||
public async removeRoleFromUser(uid: string, claim: Claim): Promise<void> {
|
||||
const client = await this.kcAdminClient;
|
||||
const role = await this.getRole(claim);
|
||||
if (!role.id || !role.name) {
|
||||
throw new Error(`Role ${claim} is missing id or name`);
|
||||
}
|
||||
|
||||
await client.users.delRealmRoleMappings({
|
||||
id: uid,
|
||||
roles: [{ id: role.id, name: role.name }],
|
||||
});
|
||||
}
|
||||
|
||||
public async getUsers(): Promise<User[]> {
|
||||
const client = await this.kcAdminClient;
|
||||
const kcUsers = await client.users.find();
|
||||
return kcUsers.map(kcUser => ({
|
||||
id: kcUser.id,
|
||||
username: kcUser.username || "",
|
||||
roles: (kcUser.realmRoles || []).map(role => role as Claim),
|
||||
}));
|
||||
}
|
||||
|
||||
private async getRole(name: string): Promise<RoleRepresentation> {
|
||||
const client = await this.kcAdminClient;
|
||||
const role = await client.roles.findOneByName({
|
||||
name: name,
|
||||
realm: "taekwondo",
|
||||
});
|
||||
if (!role) {
|
||||
throw new Error(`Role ${name} not found`);
|
||||
}
|
||||
return role;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"clientId": "nodejs-api",
|
||||
"name": "NodejsApi",
|
||||
"description": "",
|
||||
"rootUrl": "https://tkd-api.toni714.de",
|
||||
"adminUrl": "https://tkd-api.toni714.de",
|
||||
"baseUrl": "https://tkd-api.toni714.de",
|
||||
"surrogateAuthRequired": false,
|
||||
"enabled": true,
|
||||
"alwaysDisplayInConsole": false,
|
||||
"clientAuthenticatorType": "client-secret",
|
||||
"secret": "btdeoaq2mgtoa7SpCEL1phLYcw2gGhGp",
|
||||
"redirectUris": ["https://tkd-api.toni714.de/*"],
|
||||
"webOrigins": ["https://tkd-api.toni714.de"],
|
||||
"notBefore": 0,
|
||||
"bearerOnly": false,
|
||||
"consentRequired": false,
|
||||
"standardFlowEnabled": false,
|
||||
"implicitFlowEnabled": false,
|
||||
"directAccessGrantsEnabled": false,
|
||||
"serviceAccountsEnabled": true,
|
||||
"publicClient": false,
|
||||
"frontchannelLogout": true,
|
||||
"protocol": "openid-connect",
|
||||
"attributes": {
|
||||
"realm_client": "false",
|
||||
"oidc.ciba.grant.enabled": "false",
|
||||
"client.secret.creation.time": "1762463686",
|
||||
"backchannel.logout.session.required": "true",
|
||||
"standard.token.exchange.enabled": "true",
|
||||
"oauth2.device.authorization.grant.enabled": "false",
|
||||
"pkce.code.challenge.method": "S256",
|
||||
"backchannel.logout.revoke.offline.tokens": "false",
|
||||
"dpop.bound.access.tokens": "false"
|
||||
},
|
||||
"authenticationFlowBindingOverrides": {},
|
||||
"fullScopeAllowed": true,
|
||||
"nodeReRegistrationTimeout": -1,
|
||||
"defaultClientScopes": [
|
||||
"service_account",
|
||||
"web-origins",
|
||||
"acr",
|
||||
"roles",
|
||||
"profile",
|
||||
"basic",
|
||||
"email"
|
||||
],
|
||||
"optionalClientScopes": [
|
||||
"address",
|
||||
"phone",
|
||||
"organization",
|
||||
"offline_access",
|
||||
"microprofile-jwt"
|
||||
],
|
||||
"access": {
|
||||
"view": true,
|
||||
"configure": true,
|
||||
"manage": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./keycloak-user.js";
|
||||
@@ -0,0 +1,11 @@
|
||||
import KeycloakConnect from "keycloak-connect";
|
||||
import { sessionStore } from "../../../infrastructure/session.js";
|
||||
import keycloakConfig from "./keycloak.json" with { type: "json" };
|
||||
|
||||
export const KC_SECURITY_NAME = "bearerAuth";
|
||||
|
||||
export const keycloak = new KeycloakConnect(
|
||||
{ store: sessionStore },
|
||||
keycloakConfig,
|
||||
);
|
||||
export const kcUserConfig = keycloakConfig;
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"realm": "taekwondo",
|
||||
"auth-server-url": "https://keycloak.toni714.de:8443",
|
||||
"ssl-required": "external",
|
||||
"resource": "nodejs-api",
|
||||
"credentials": {
|
||||
"secret": "btdeoaq2mgtoa7SpCEL1phLYcw2gGhGp"
|
||||
},
|
||||
"confidential-port": 0
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { Injectable } from "../infrastructure/di/index.js";
|
||||
|
||||
@Injectable()
|
||||
export class MembersService {
|
||||
// public async getMembers(): Promise<Member[]> {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Injectable } from "../infrastructure/di/index.js";
|
||||
|
||||
@Injectable()
|
||||
export class MessagingService {
|
||||
public async sendTestMessage(): Promise<void> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { inject } from "../infrastructure/di/index.js";
|
||||
import { Claim } from "../models/claim";
|
||||
import { Topic } from "../models/topic.js";
|
||||
import { User } from "../models/user.js";
|
||||
import { KeycloakAdmin } from "./keycloak/admin/index.js";
|
||||
|
||||
export class UserService {
|
||||
private readonly keycloakAdmin = inject(KeycloakAdmin);
|
||||
public async setClaim(
|
||||
uid: string,
|
||||
claim: Claim,
|
||||
value: boolean,
|
||||
): Promise<void> {
|
||||
if (value) {
|
||||
return await this.keycloakAdmin.addRoleToUser(uid, claim);
|
||||
} else {
|
||||
return await this.keycloakAdmin.removeRoleFromUser(uid, claim);
|
||||
}
|
||||
}
|
||||
|
||||
public async getUsers(): Promise<User[]> {
|
||||
return await this.keycloakAdmin.getUsers();
|
||||
}
|
||||
|
||||
public async setSubscriptions(token: string, topics: Topic[]) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user