From 4b4ea1a10f6da5b34b66b269943dab4ee384c193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pac=C3=B4me=20Rivier?= Date: Tue, 14 Jun 2022 18:08:20 +0200 Subject: [PATCH 1/2] feat: support clients for keycloak --- src/server/middlewares/auth.ts | 42 ++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/server/middlewares/auth.ts b/src/server/middlewares/auth.ts index 979604d8b..ddf0a18e9 100644 --- a/src/server/middlewares/auth.ts +++ b/src/server/middlewares/auth.ts @@ -80,6 +80,48 @@ if (process.env.AUTH_TYPE === authenticationType.keycloak) { path: 'positionAttributes.category', model: 'PositionAttributeCategory', }); + // === CLIENT === + } else if (token.azp) { + // Checks if client already exists in the DB + Client.findOne({ clientId: token.azp }, (err, client: Client) => { + if (err) { + return done(err); + } + if (client) { + // Returns the client if found + return done(null, client, token); + } else { + // Creates the client from client ID if not found + let name = String(token.azp).replace(/-/g, ' '); + name = name.charAt(0).toUpperCase() + name.slice(1); + client = new Client({ + name, + clientId: token.azp, + roles: [], + positionAttributes: [], + }); + client.save((err2, res) => { + if (err2) { + return done(err2); + } + return done(null, res, token); + }); + } + }) + .populate({ + // Add to the context all roles / permissions the client has + path: 'roles', + model: 'Role', + populate: { + path: 'permissions', + model: 'Permission', + }, + }) + .populate({ + // Add to the context all positionAttributes with corresponding categories + path: 'positionAttributes.category', + model: 'PositionAttributeCategory', + }); } }) ); From d9a6e684284a61195bcb06fd1644d7cf7336a3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pac=C3=B4me=20Rivier?= Date: Tue, 14 Jun 2022 18:09:18 +0200 Subject: [PATCH 2/2] feat: assign correct roles to public client --- .env.keycloak | 1 + src/security/defineUser.ts | 37 +++++++++++++++++++++++++++++++ src/server/middlewares/graphql.ts | 5 +++-- src/server/middlewares/rest.ts | 5 +++-- 4 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 src/security/defineUser.ts diff --git a/.env.keycloak b/.env.keycloak index d32d2fc27..98bdb397e 100644 --- a/.env.keycloak +++ b/.env.keycloak @@ -14,3 +14,4 @@ RABBITMQ_DEFAULT_USER= RABBITMQ_DEFAULT_PASS= AES_ENCRYPTION_KEY= OWN_URL= +PUBLIC_CLIENT_ID= diff --git a/src/security/defineUser.ts b/src/security/defineUser.ts new file mode 100644 index 000000000..eb19f4ab2 --- /dev/null +++ b/src/security/defineUser.ts @@ -0,0 +1,37 @@ +import { Client, User } from 'models'; +import * as dotenv from 'dotenv'; +dotenv.config(); + +/** + * Define roles for user if it's the public client. + * + * @param user user to define roles of. + * @param req original request. + * @returns user with correct roles. + */ +const defineUser = async ( + user: User | Client, + req: any +): Promise => { + console.log('IN DEFINE USER'); + if ((user as Client).clientId === process.env.PUBLIC_CLIENT_ID) { + const pageID = req.originalUrl + .split(req.params.name) + .pop() + .substring(1) + .split('/') + .pop(); + console.log('PAGE ID', pageID); + /** + * Apply following logic + * + * Check if page is public, otherwise return null + * If page is public, retrieve roles/positionAttributes associated with the page + * Add those roles/positionAttributes to the client + * Populate those roles/positionAttributes + * Return user + */ + } + return user; +}; +export default defineUser; diff --git a/src/server/middlewares/graphql.ts b/src/server/middlewares/graphql.ts index d196fda47..bfc7534b9 100644 --- a/src/server/middlewares/graphql.ts +++ b/src/server/middlewares/graphql.ts @@ -1,5 +1,6 @@ import passport from 'passport'; import defineAbilitiesFor from '../../security/defineAbilityFor'; +import defineUser from '../../security/defineUser'; import { authenticationType } from '../../oort.config'; import * as dotenv from 'dotenv'; dotenv.config(); @@ -18,9 +19,9 @@ const strategy = * @param next Callback argument to the middleware function */ export const graphqlMiddleware = (req, res, next) => { - passport.authenticate(strategy, { session: false }, (err, user) => { + passport.authenticate(strategy, { session: false }, async (err, user) => { if (user) { - req.user = user; + req.user = await defineUser(user, req); // Define the rights of the user req.user.ability = defineAbilitiesFor(user); req.user.isAdmin = user.roles diff --git a/src/server/middlewares/rest.ts b/src/server/middlewares/rest.ts index fd2eb29ba..3ca12a18e 100644 --- a/src/server/middlewares/rest.ts +++ b/src/server/middlewares/rest.ts @@ -1,5 +1,6 @@ import passport from 'passport'; import defineAbilitiesFor from '../../security/defineAbilityFor'; +import defineUser from '../../security/defineUser'; import { authenticationType } from '../../oort.config'; import * as dotenv from 'dotenv'; import i18next from 'i18next'; @@ -19,9 +20,9 @@ const strategy = * @param next Callback argument to the middleware function */ export const restMiddleware = (req, res, next) => { - passport.authenticate(strategy, { session: false }, (err, user) => { + passport.authenticate(strategy, { session: false }, async (err, user) => { if (user) { - req.context = { user }; + req.context = { user: await defineUser(user, req) }; // req.context.user = user; // Define the rights of the user req.context.user.ability = defineAbilitiesFor(user);