Skip to content

Commit

Permalink
Merge pull request #1534 from hajkmap/feature/1533-userDetails-for-ad…
Browse files Browse the repository at this point in the history
…-header-approach

Feature/1533 user details for ad header approach
  • Loading branch information
jesade-vbg authored Jul 2, 2024
2 parents d9db61d + 062e6c2 commit 4c57949
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- CookieNotice: The cookie notice dialog now appears at the top of other dialogs and pop up windows. PR: [#1521](https://github.com/hajkmap/Hajk/pull/1521).
- Backend (Node): Added possibility to use Authorization token in FME Server proxy. [#1530](https://github.com/hajkmap/Hajk/pull/1530).
- Measurer: The measurer now allows for selecting objects by clicking them to get measurement information (area and circumference). PR: [#1532](https://github.com/hajkmap/Hajk/pull/1532).
- Backend (Node): Added (very) limited userDetails to response when using the AD Header approach (for example NodeHoster). [#1534](https://github.com/hajkmap/Hajk/pull/1534)

### Fixed

Expand Down
7 changes: 7 additions & 0 deletions apps/backend/.env
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ AD_TRUSTED_HEADER=X-Control-Header
# Name of the HTTP header that will contain the trusted groups, only used when
# AD_USE_HEADER_GROUP_METHOD is true.
AD_TRUSTED_GROUP_HEADER=X-Control-Group-Header
# Name of the HTTP header that will contain the trusted email, only used when
# AD_USE_HEADER_GROUP_METHOD is true.
AD_TRUSTED_EMAIL_HEADER=X-Control-Email-Header

AD_URL=ldap://some.domain.com # Also, check out the AD_TLS_* settings below for ldaps://
AD_BASE_DN=DC=test,DC=example,DC=com
AD_USERNAME=user
Expand Down Expand Up @@ -202,6 +206,9 @@ AD_RECONNECT=true
# For development and testing purposes, a user name can be supplied here.
# Make sure to always disable this in production!
# AD_OVERRIDE_USER_WITH_VALUE=someUser
# For development and testing purposes, an email can be supplied here.
# Make sure to always disable this in production!
# AD_OVERRIDE_USER_EMAIL_WITH_VALUE=test@email.com
# For development and testing purposes, groups can be supplied here.
# Make sure to always disable this in production!
# AD_OVERRIDE_USER_GROUPS_WITH_VALUE=someGroup1,someGroup2
Expand Down
67 changes: 63 additions & 4 deletions apps/backend/server/apis/v2/services/adgroupheader.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,32 @@ class AdGroupHeaderService extends AdBaseService {
}

init() {
// Other overrides are located in initEnvOverrides (in AdBaseService) but this email override
// is only applicable in the Header based AD case.
this.overrideUserEmail = this.getEnv(
process.env.AD_OVERRIDE_USER_EMAIL_WITH_VALUE
);
if (this.overrideUserEmail) {
this.logger.warn(
'AD_OVERRIDE_USER_EMAIL_WITH_VALUE is set in .env! Will use "%s" as email. DON\'T USE THIS IN PRODUCTION!',
this.overrideUserEmail
);
}

this.users = {};
}

postRequestHandler(request, user) {
let groups = [];
let email = "";
if (user) {
// Use override groups or get groups from header.
if (this.overrideUserGroups) {
groups = this.overrideUserGroups;
} else {
const xControlGroupHeader =
process.env.AD_TRUSTED_GROUP_HEADER || "X-Control-Group-Header";
const groupString =
this.overrideUserGroups || request.get(xControlGroupHeader);
const groupString = request.get(xControlGroupHeader);
if (groupString) {
groups = groupString.split(",").map((group) => group.trim());
}
Expand All @@ -31,16 +43,45 @@ class AdGroupHeaderService extends AdBaseService {
process.env.AD_TRUSTED_GROUP_HEADER,
groups
);

// Use override email or get email from header.
if (this.overrideUserEmail) {
email = this.overrideUserEmail;
} else {
const xControlEmailHeader =
process.env.AD_TRUSTED_EMAIL_HEADER || "X-Control-Email-Header";
const emailString = request.get(xControlEmailHeader);
if (emailString) {
email = emailString.trim();
}
}
}

// Create user if it doesn't exist
if (user && !this.users[user]) {
this.users[user] = {
groups: [],
email: "",
};
}

// Set user groups and email
this.#setUserGroups(user, groups);
this.#setUserEmail(user, email);
}

#setUserGroups(userName, groups) {
if (!this.getUser(userName)) {
return;
}
this.users[userName] = groups;
this.users[userName].groups = groups;
}

#setUserEmail(userName, email) {
if (!this.getUser(userName)) {
return;
}
this.users[userName].email = email;
}

validUserName(userName) {
Expand Down Expand Up @@ -69,7 +110,15 @@ class AdGroupHeaderService extends AdBaseService {
return [];
}

return this.users[userName];
return this.users[userName].groups;
}

getUserEmail(userName) {
if (!this.getUser(userName)) {
return "";
}

return this.users[userName].email;
}

async isUserValid(userName) {
Expand All @@ -80,6 +129,16 @@ class AdGroupHeaderService extends AdBaseService {
return this.getUser(userName) ? {} : null;
}

async getUserDetails(userName) {
// This functionality is somewhat limited.
// We only return user name, groups and email because thats all we have for now.
return {
user: userName,
groups: this.getUserGroups(userName),
mail: this.getUserEmail(userName),
};
}

async getGroupMembershipForUser(userName) {
return this.getUserGroups(userName);
}
Expand Down
11 changes: 10 additions & 1 deletion apps/backend/server/apis/v2/services/config.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,16 @@ class ConfigServiceV2 {
// some user details to the client.
let userDetails = undefined;
if (user !== undefined && process.env.AD_EXPOSE_USER_OBJECT === "true") {
userDetails = await ad.findUser(user);
if (
process.env.AD_USE_GROUPS_FROM_HEADER === "true" &&
ad.getUserDetails
) {
// This is the Header based approach which has support for user, group and email.
userDetails = await ad.getUserDetails(user);
} else {
// This is the default behavior with the ldap approach.
userDetails = await ad.findUser(user);
}
}

return { mapConfig, layersConfig, userSpecificMaps, userDetails };
Expand Down
2 changes: 1 addition & 1 deletion apps/client/src/controls/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const getTooltipString = (userDetails) => {
*/
const User = React.memo(({ userDetails }) => {
return (
(userDetails && (
(userDetails?.displayName && (
<HajkToolTip title={getTooltipString(userDetails)}>
<StyledPaper>
<StyledIconButton aria-label={userDetails.displayName}>
Expand Down

0 comments on commit 4c57949

Please sign in to comment.