- Automatic Login
- Add a custom location in EnginFrame File Manager
- Multi-Factor-Authentication (MFA) for EnginFrame
- EnginFrame SSO and MFA with OKTA
- Add a custom location in EnginFrame File Manager
- Extend the administration rights to other users
- Static
- Dynamic
- Session cleanup
- Minimizing the built-in account locking mechanism
- Output size of this service exceeds the maximum limit defined in EnginFrame configuration
- EnginFrame login is taking 25 seconds
- Mapping internal hosts with public DNS names
- Mapping EF Portal users to local Linux users
- Unusual or high storage usage
EnginFrame is a very powerful HPC and visualization session management portal. In this section we want to highlight some of the features and configuration options of EnginFrame.
A powerful overview of EnginFrame customization options can be found in the Technology Showcase available from the startpage of EnginFrame as administrator user.
Automatic Login
The steps to scrape data from Enginframe through curl are the following:
- Get JSESSIONID cookie end CSRF token
- Make login (use a license)
- Retrieve data
- Make log out (to release the license)
The following script implements these steps:
#!/bin/bash
workdir='/tmp/'
curl="curl --silent --insecure \
--cookie $workdir/cookies.txt \
--cookie-jar $workdir/cookies.txt"
endpoint='http://localhost:8080'
user='efadmin'
password='123456'
function session {
$curl --junk-session-cookies "$endpoint/enginframe/admin/com.enginframe.admin.xml" > /dev/null
$curl -X POST \
-H "Referer: $endpoint/enginframe" \
-H "FETCH-CSRF-TOKEN: 1" \
"$endpoint/enginframe/CsrfGuardServlet" | awk -F ':' '{print $1"=" $2}' > $workdir/csrftoken
}
function login {
$curl -X POST \
-H "Referer: $endpoint/enginframe" \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Language: en,it;q=0.5' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Upgrade-Insecure-Requests: 1' \
--data "_username=$user" \
--data "_password=$password" \
--data 'submit=Login' \
--data $(< $workdir/csrftoken) \
"$endpoint/enginframe/admin/com.enginframe.admin.xml?_uri=//com.enginframe.admin/server.load" > /dev/null
}
function logout {
$curl \
-H "Referer: $endpoint/enginframe" \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Language: en,it;q=0.5' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Upgrade-Insecure-Requests: 1' \
"$endpoint/enginframe/admin/com.enginframe.admin.xml?_uri=//com.enginframe.system/logout" > /dev/null
}
function license_status {
$curl -X POST \
-H "Referer: $endpoint/enginframe" \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Language: en,it;q=0.5' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Upgrade-Insecure-Requests: 1' \
--data "$(< $workdir/csrftoken)" \
"$endpoint/enginframe/admin/com.enginframe.admin.xml?_uri=//com.enginframe.admin/view.license.usage"
}
session
login
license_status
logout
To get human readable results install w3m
package and pipe the output of the script to:
w3m -dump -T text/html
To extract only the numbers you need you can use xmllint
with an XPath expression.
Add a custom location in EnginFrame File Manager
To add a custom file manager location in “Files” page, proceed as follows:
- Identify the plugin you’re using. E.g. applications, views or demo
You can also check it by looking at the browser url: it is the string immediately following EnginFrame root context (default: /enginframe), e.g. /enginframe/applications - Log into EnginFrame server node
- Change directory to $EF_ROOT/plugins/applications (or your plugin folder), bin subdirectory
- Create a file named
fm.browse.ui
with the following contents:
#!/bin/bash
newFilesLocation=/tmp
newFileslabel="Temporary folder"
source "${EF_ROOT}/plugins/ef/conf/ef.xmlns.conf"
source "${EF_ROOT}/plugins/ef/lib/xmlfuncs"
printf '<ef:ui-configure-widget ui="hydrogen" id="fm-browse" %s %s %s>\n' \
"${EF_XMLNS_ef}" "${EF_XMLNS_hy}" "${EF_XMLNS_efactions}"
vroot=$("${EF_ROOT}/plugins/fm/bin/fm.vroot.create" "${FM_BROWSE_SPOOLER}" 'fm' "file://${newFilesLocation}")
printf '<hy:add-vroot id="%s">\n' "${vroot}"
printf '<hy:label>%s</hy:label>\n' "$(ef_xml_escape_content --input "${newFileslabel}")"
printf '</hy:add-vroot>\n'
printf '</ef:ui-configure-widget>\n'
- You can customize the first 2 parameters, the new filesystem location and the associated label in Files page
- Give fm.browse.ui executable permissions:
chmod +x fm.browse.ui
Multi-Factor-Authentication (MFA) for EnginFrame
EnginFrame SSO and MFA with OKTA
The AWS team has created a guide how to integrate EnginFrame with OKTA to provide Single-Sign-On and MFA.
Add a custom location in EnginFrame File Manager
To add a custom file manager location in “Files” page, proceed as follows:
- Identify the plugin you’re using. E.g. applications, views or demo
You can also check it by looking at the browser url: it is the string immediately following EnginFrame root context (default: /enginframe), e.g. /enginframe/applications - Log into EnginFrame server node
- Change directory to EF_ROOT/plugins/applications (or your plugin folder), bin subdirectory
- Create a file named fm.browse.ui with the following contents
#!/bin/bash
newFilesLocation=/tmp
newFileslabel="Temporary folder"
source "${EF_ROOT}/plugins/ef/conf/ef.xmlns.conf"
source "${EF_ROOT}/plugins/ef/lib/xmlfuncs"
printf '<ef:ui-configure-widget ui="hydrogen" id="fm-browse" %s %s %s>\n' \
"${EF_XMLNS_ef}" "${EF_XMLNS_hy}" "${EF_XMLNS_efactions}"
vroot=$("${EF_ROOT}/plugins/fm/bin/fm.vroot.create" "${FM_BROWSE_SPOOLER}" 'fm' "file://${newFilesLocation}")
printf '<hy:add-vroot id="%s">\n' "${vroot}"
printf '<hy:label>%s</hy:label>\n' "$(ef_xml_escape_content --input "${newFileslabel}")"
printf '</hy:add-vroot>\n'
printf '</ef:ui-configure-widget>\n'
- You can customize the first 2 parameters, the new filesystem location and the associated label in Files page
- Give fm.browse.ui executable permissions
Some content is inspired by NICE Support articles.
Extend the administration rights to other users
There are two ways to add extra admin users:
- Static, where you define admin users manually
- Dynamic, where you define admin users based in rules
Static
In this case, EnginFrame will read a authorization.xconf file and store in the database which users are admin.
Create or edit the /opt/nisp/enginframe/conf/enginframe/authorization.xconf
(needs to be the global config) and add the users like this:
<?xml version="1.0"?>
<ef:authorization xmlns:ef=\"http://www.enginframe.com/2000/EnginFrame\">
<ef:acl-actor-list>
<ef:acl-actor id="efadmins" type="osgroup" plugin="ef">
<ef:info>EF Portal Administrators</ef:info>
<ef:acl-member type="efuser">${EF_ADMIN}</ef:acl-member>
<ef:acl-member type="efuser">myuser1</ef:acl-member>
<ef:acl-member type="efuser">myuser2</ef:acl-member>
</ef:acl-actor>
</ef:acl-actor-list>
</ef:authorization>
Notes:
- Do not remove the ${EF_ADMIN}, to preserve efadmin user rights.
- You do not need to restart EF Portal.
- If you remove the file, the users will continue being admin users. The information will be stored in the database. You need to manually remove the users from EF dashboard (users section), or at least disable them as admin users.
Dynamic
Create or edit the /opt/nisp/enginframe/conf/enginframe/authorization.xconf
(needs to be the global config) to have this content:
<?xml version="1.0"?>
<ef:authorization xmlns:ef="http://www.enginframe.com/2000/EnginFrame">
<ef:acl-actor-list>
<ef:acl-actor id="efadmins" type="osgroup" plugin="ef"/>
</ef:acl-actor-list>
</ef:authorization>
You do not need to add anything more in authorization.xconf
file.
Then, create the /opt/nisp/enginframe/VERSION/enginframe/plugins/ef/bin/ef.load.users
file, with the dynamic config:
#!/bin/bash
admin_group_usernames = myadminsgroup
admin_users=$(getent group $admin_group_usernames | cut -d: -f4 | tr ',' ' ')
echo "<?xml version=\"1.0\"?>"
echo "<ef:authorization xmlns:ef=\"http://www.enginframe.com/2000/EnginFrame\">"
echo " <ef:acl-actor-list>"
echo " <ef:acl-actor id=\"efadmins\" type=\"osgroup\" plugin=\"ef\">"
echo " <ef:info>EF Portal Administrators</ef:info>"
for admin_user in $admin_users
do
echo "<ef:acl-member type=\"efuser\">${admin_user}</ef:acl-member>"
done
echo "</ef:acl-actor>"
echo " </ef:acl-actor-list>"
echo "</ef:authorization>"
Notes:
- Add execution permission (chmod +x) to
ef.load.users
- Set in admin_group_usernames variable the group that will have all users with admin rights under EnginFrame.
- If you remove the file, the users will continue being admin users. The information will be stored in the database. You need to manually remove the users from EF dashboard (users section), or at least disable them as admin users.
Session cleanup
To clean persistent of the damaged user, please follow the below steps:
- Identify all files from the damaged user. As example, the use will be “nisp”.
ls /opt/nice/enginframe/{repository,sessions,spoolers}/nisp/
Note: Replace the path with your real EnginFrame path. - Stop the EF systemd service:
systemctl stop enginframe
- Backup and remove all files and directories found in the previous step.
- Backup the below files and replace them with original files from fresh users (usually located in
/etc/skel
directory):.bashrc
.bash_profile
.profile
- Then start the EnginFrame again:
systemctl stop enginframe
Minimizing the built-in account locking mechanism
Edit the file /opt/nice/enginframe/conf/enginframe/server.conf and set these parameters to mitigate your locking account problem:
ef.account.lockout.after.attempts=1000 # Set an high value
ef.account.lockout.time.admins=0 # Zero disable the lockout for admins
ef.account.lockout.time.users=1 # Minimum time is 1 minute
Then restart the EnginFrame service:
systemctl restart enginframe
Output size of this service exceeds the maximum limit defined in EnginFrame configuration
Please edit your $EF_ROOT/conf/server.conf file and increase the maximum limit:
ef.output.limit=52428800
Then you need to restart EnginFrame service:
systemctl stop enginframe
systemctl start enginframe
EnginFrame login is taking 25 seconds
This is a known issue with systemd
, is not related with EnginFrame. There is an old bug in systemd
that does not remove sessions scope and, mainly in environments with a lot of users doing login and logout, eventually the abandoned sessions list will increase making systemctl list-unit-files
performance very bad. For servers that depends of systemd to login (check your /etc/nsswitch.conf
for systemd
string), systemctl list-unit-files
will have a very bad performance and just after systemd default timeout (25000ms or 25s), you will be able to login (ssh, sudo, su etc). As this is related with systemd bug, it can affect a lot of linux distributios versions. In case of RedHat linux based distributions, it will affect EL 7, 8 and 9. The permanent solution is update systemd for a version where the bug was fixed (2022+ releases). If is not an option to you, you can set a cronjob that will execute this script (author):
#!/bin/bash
system_show () {
local t="${1##*.}"
systemctl show "$1" --no-pager --no-legend --no-ask-password | sed -e 's/"/\\"/g' -e 's/\([^=]*\)=\(.*\)/'"$t"'_\1="\2"/'
}
for unit in $(systemctl list-units --state=abandoned -t scope --no-legend --no-pager --no-ask-password | cut -d' ' -f1) ; do
eval "$(system_show "$unit")"
[ "$(systemd-cgls "$scope_ControlGroup" 2>/dev/null | wc -l)" -eq 1 ] && systemctl stop "$unit"
done
If you want to do a simple test before set this cronjob, you can run this command to check the 25 seconds timeout:
systemctl list-unit-files –all
And then execute this command to remove all scopes:
find /run/systemd/system -name "session-*.scope" -delete
rm -rf /run/systemd/system/session*scope*
systemctl | grep "abandoned" | grep -e "-[[:digit:]]" | sed "s/\.scope.*/.scope/" | xargs systemctl stop
And then run again this command to see the problem fixed:
systemctl list-unit-files –all
Mapping internal hosts with public DNS names
If you installed your EF Portal in the intranet, the connection file or remote browser access will use the internal DCV Server DNS name. However, for external users, the local name can not be resolved because is not a valid name under internet. To fix the URL of the remote browser access or the connection file, you need to edit the /opt/nisp/enginframe/conf/plugins/interactive/nat.conf
file and follow this syntax:
- The syntax consists of a line made of a pair: the real host:port followed by the public host:port pair.
- It is possible to omit the :port which case it is assumed to be the same for the real and public hosts.
- It is also possible to specify a group of ports using this syntax: host:fromport-toport.
- If you want to redirect all internal nodes to the same public name, you can use *
Some examples:
node01 remote.mycompany.com
node02 121.122.123.124
node0342976 remote.mycompany.com:42976
node04:7900-7910 remote.mycompany.com:5900-5910
node05:7900-7910 121.122.123.124:5900-5910
Mapping EF Portal users to local Linux users
EF Portal need to set the right permissions to the session and spoolers directories to provide correct access to the logged users. If you are using the PAM plugin, you need to have the remote users mapped locally. When you are using services like SSSD, this is automatically done, but if you are using using a custom ef.auth that query for the users that does not exist locally, you need to mape external users in local users.
You can map the users 1:1 or in groups (2:1, 5:1 or a random number by 1). You just need to create a bash script with the logic to map the users. We will exemplify with the most common case, 1:1 (each user will be mapped to one user locally).
First, find the ef.auth.conf
file with the command:
find /opt/nisp -iname ef.auth.conf | egrep -i "enginframe/plugins/pam/conf"
Edit the file and set:
EFAUTH_USERMAPPING=”true”
Then you need to edit the file ef.user.mapping
. The file will be in the same common path of ef.auth.conf
file, but instead of conf/
dir, it needs to be created under bin/
dir.
Suppose that you want to map one user by one user, which means that every user will have your own rights, without share any EF Portal resources. This means that remote user Francisco will be local user Francisco, or the remote user id12345 will be mapped to the local user id12345. The username does not matter, you just need to make sure that the username (mapped) will be a valid linux username.
Valid characters for Linux usernames include:
- Lower and upper case letters
- Digits
- Underscores
- Dashes
- A dollar sign at the end
- Linux usernames must not contain spaces or “@”.
- They must also start with an alphabetic character and be 30 characters or fewer.
Now that is clear why you need to map the external users to EF Portal environment, you can edit the file ef.user.mapping
and add this content:
#!/bin/bash
# Check if a username was provided
if [ $# -eq 0 ]; then
exit 1
fi
username="$1"
# Check if the user exists
if ! id "$username" > /dev/null 2>&1
then
sudo useradd -m "$username" > /dev/null 2>&1
fi
# Generate a random password
password=$(openssl rand -base64 12)
# Set the password for the user
echo "$username:$password" | sudo chpasswd > /dev/null 2>&1
# Set password expiration to 1 month (30 days)
sudo chage -M 30 "$username" > /dev/null 2>&1
# map the user to EF
echo $username
Then save the file and give executable permissions (chmod +x).
Basically the script will do:
- Check if the username was provided as parameter
- Check if the user already exist. If not, it will create it.
- Create a random password and set.
- Set expiration time for 30 days.
- Print the mapped user.
This printed user is the user that EF Portal will use locally.
Important: If your external usernames are not valid Linux usernames, then you need to create a logic that will remove the non allowed characters, but at the same time still make them unique.
For example, if your username start with number, you can write a logic that will replace the number for a alphapetic char (example: 1 will be A, 2 will be B, 3 will be C etc). But if sometimes it start with number and sometimes not, then is more simple just add an extra char before everything (exemple: 0abcde will be a0abdce, 5asdfg will be a5asdfg, 9zxcvb will be a9zxcvb, etc).
You can also just map all users to one user. This is not usual, but can be done. For example, if you want all external users being mapped to “efadmin” user, you can set the ef.user.mapping
file to have just this:
#!/bin/bash
echo “efadmin”
And you can combine the ideas. You can create a bash script that will map some specific users to “efadmin”, and the rest will be 1:1, like this:
#!/bin/bash
# Check if a username was provided
if [ $# -eq 0 ]; then
exit 1
fi
username="$1"
admin_users="francisco john mary"
if echo $admin_users | egrep -iq "username"
then
echo "efadmin"
else
# Check if the user exists
if ! id "$username" > /dev/null 2>&1
sudo useradd -m "$username" > /dev/null 2>&1
fi
# Generate a random password
password=$(openssl rand -base64 12)
# Set the password for the user
echo "$username:$password" | sudo chpasswd > /dev/null 2>&1
# Set password expiration to 1 month (30 days)
sudo chage -M 30 "$username" > /dev/null 2>&1
# map the user to EF
echo $username
fi
Finally you need to add efnobody into sudoers. Please execute visudo and add in the last line:
efnobody ALL=(ALL) NOPASSWD: ALL
Unusual or high storage usage
If you are seeing EF Portal using a good amount of storage space, this guide will present a checklist to help you understand if the storage usage is normal or not.
Is expected that two directories will grow through the time:
/opt/nisp/enginframe/spoolers/
: Data container used to store user files in the host/opt/nisp/enginframe/sessions/
: Data container used to store user sessions in the host
You can not manually delete those files. If you need to clear this content, you need to contact us.
Another directory that can grow, but is limited due the rotation:
/opt/nisp/enginframe/logs/HOSTNAME/
: All logs related with EF Portal services
If needed, you can remove the oldest logs or even all the files. Before that, you need to stop EF Portal service, remove the files and start the service again.
/opt/nisp/enginframe/tmp/
: The EF Portal temporary directory
If needed, the content of the directory can be completely removed. Before that, you need to stop EF Portal service, remove the content and start the service again.
/opt/nisp/enginframe/202{1,4}-r*
: Every EF Portal setup will happen in a new directory based in the version
If you have multiple versions installed, you will see multiple directories here. You can remove all unused versions, but make sure to do a backup before remove anything.
- find /opt/nisp -type f -size +10M -exec du -hs {} \;
You can also look for files with certain size (or more) to check if there is something not usual. +10M means 10 Mb or more.
- Logs being flooded by “
Warning: Nashorn engine is planned to be removed from a future JDK release
” message
You need to use the right Java version to avoid issues. Please check in the EF Portal site the updated requirements to run the service.
Note: This warning can be mitigated using JDK-8 version.
If you have any other question about a possible not usual storage usage, please contact us.