Skip to content

Commit

Permalink
fix updates because of change to Keycloak 25
Browse files Browse the repository at this point in the history
  • Loading branch information
guFalcon committed Jul 15, 2024
1 parent 7677e77 commit 237a7ed
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 19 deletions.
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,16 @@ Then you can run the REST-examples in the `http` directory.
## Keycloak Setup
In order for this setup to work correctly, you'll have to have a Keycloak-client (private with secret) and standard-authorization-flow enabled (should be enabled anyway).
You need the following user-attributes of type `string` with mapper to the token.
| ATTRIBUTE-NAME | TYPE | DESCRIPTION |
| ------------------------------------------------------------------------------------------------------------------ | ------ | ----------------------------------------------------------------------------------------------------- |
| Client -> Client Scopes -> ...-dedicated -> Add Mapper (User Attribute)<br>`config` | string | Holds several preference-values like dark-mode or not or the preferred font, fontsize or line-height. |
| Client -> Client Scopes -> ...-dedicated -> Add Mapper (User Attribute)<br>`lastVisitedUrl` | string | Holds the last-visited page of the current user. |
| Client -> Client Scopes -> ...-dedicated -> Add Mapper (User Attribute)<br>map the field `LDAP_ENTRY_DN` to `ldap` | string | Holds the users LDAP information (class, teacher, etc.). |
You also need to add the user-attributes to the user-profile first (`Realm settings` -> `User profile (Attribute group = none, not user-metadata)`) in order to allow for the addition of data to your users. Be sure to set those to `allow edit and view for User and Admin` so that the application is able to change the values.
The application uses the following endpoints of the Keycloak-API to do that:
- `GET {{keycloakUrl}}/realms/{{realm}}/account`
- `POST {{keycloakUrl}}/realms/{{realm}}/account`
The user-metadata field `LDAP_ENTRY_DN` will be automatically present because of the LDAP mapper in your Keycloak instance. It will be readable from the `access-token`. So there are no additional setup-steps requried.
| ATTRIBUTE-NAME | TYPE | DESCRIPTION |
| ------------------------------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- |
| Client -> Client Scopes -> ...-dedicated -> Add Mapper (User Attribute)<br>`config` | string | Holds several preference-values like dark-mode or not or the preferred font, fontsize or line-height. |
| Client -> Client Scopes -> ...-dedicated -> Add Mapper (User Attribute)<br>`lastVisitedUrl` | string | Holds the last-visited page of the current user. |
## MD-File Conversion
This is done using [marked](https://www.npmjs.com/package/marked) which is installed on the web-server (via `package.json`).
With the help of this you can link to any MD-file and show it in the context of your site.
Expand Down
24 changes: 13 additions & 11 deletions middlewares/keycloak-middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export function getLdapGroups(req) {
return r;
}
const ldap = req.user.ldap;
// console.log("LDAP-String", ldap)

// Regular expression to match "OU=..."
const regex = /OU=[^,]*/gi;
Expand All @@ -170,7 +171,7 @@ export function getLdapGroups(req) {
r[value] = true;
});
}

// console.log("LDAP-Groups", r);
return r;
}

Expand All @@ -194,13 +195,14 @@ export async function getUserAttributes(req, getAll = false) {
return response.json();
})
.then((data) => {
for(let key in data) {
data[key] = data[key][0];
// console.log("data of user attributes", data);
for(let key in data.attributes) {
data.attributes[key] = data.attributes[key][0];
}
if(getAll) {
// Remove fields from the object that are not needed.
let { userProfileMetadata, id, username, emailVerified, ...d} = data;
return d;
// Remove fields from the object that are not needed.
let { userProfileMetadata, id, username, emailVerified, ...d} = data;
return d;
}
return data;
})
Expand All @@ -222,12 +224,12 @@ export async function setUserAttribute(req, attributeName, attributeValue) {

// Fetch current user attributes
const currentAttributes = await getUserAttributes(req, true);
// console.log("current attributes", currentAttributes);

// Merge current and new attributes at the root level
let mergedAttributes = { ...currentAttributes, [attributeName]: attributeValue };
mergedAttributes = {
attributes: mergedAttributes
}
// Merge current and new attributes
const mas = { ...currentAttributes.attributes, [attributeName]: attributeValue };
const mergedAttributes = { ...currentAttributes, attributes: mas };
// console.log("merged attributes before saving", mergedAttributes);

const result = fetch(url, {
method: "POST",
Expand Down
8 changes: 6 additions & 2 deletions utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,17 @@ async function hasRoles(req, clientRoles, all, override) {
let clientAccess = null;
const attributes = await getUserAttributes(req);
const ccr = await getClientRoles(req, clientRoles);
// console.log("Client roles", ccr);
// console.log("Request user rolesCalculated", req.user.rolesCalculated);
if (
req.user.rolesCalculated !== undefined &&
req.user.rolesCalculated !== null
) {
if (attributes && attributes.config) {
const a = JSON.parse(attributes.config);
// console.log("attributes", attributes);
if (attributes && attributes.attributes && attributes.attributes.config) {
const a = JSON.parse(attributes.attributes.config);
const r = JSON.parse(req.user.rolesCalculated);
// console.log("Roles Calculated", r);
const cr = await getClientRoles(req, clientRoles);
if (cr) {
for (const role of cr) {
Expand Down

0 comments on commit 237a7ed

Please sign in to comment.