-
Notifications
You must be signed in to change notification settings - Fork 4
UserManagement
This is a collection of notes about MiG user management for use on MiGrid and any future systems using the migrid software. Most facility scripts are available in the mig/server directory of the migrid source code checkout, which is typically installed in /home/mig/mig/server on those systems.
A script to create MiG users interactively or from saved account requests from the reqcert or reqoid web interface. Basically it creates the user in MiG-users.db and initializes all the user-specific subdirs and files in ~/state/ . The actual command to use is included in the admin notification email triggered on account requests and for an openid request could be something like:
~/mig/server/createuser.py -a oid -u '/home/mig/state/user_pending/tmpHfOLef' -p AUTO
to accept the pickled account request saved in tmpHfOLef using automatic detection of Peer acceptance. In the rare cases where no peer is wanted (own test accounts) the -p arg can be left out, but '''all''' external users should have somebody vouch for them using Peers. For certificate requests the one would instead have -a cert and a third option of -a custom can be used to specify e.g. mixed auth accounts. The auth type is currently only used to configure/decide individual account expire value for each type.
The email will include additional instructions for other relevant actions like informing the user on account creation or deleting the user again at a later point.
Please note that createuser can also be used to renew an existing user account e.g. because it expired, to change the role field or to add an OpenID aliases
~/mig/server/createuser.py -r -e 1758837600 -R '' -o nobel@chem.example.edu -i '/C=DK/ST=NA/L=NA/O=nano/OU=NA/CN=Alfred Nobel/emailAddress=nobel@nano.example.edu'
The expire value for -e
expects the basic unix epoch time format, so it may be more convenient to use an inline expanded actual date like
-e $(date +%s -d 2025-09-26)
If local management policy requires employees to vouch for external users: Employees do so either by entering and optionally inviting the external user up front, or by asking the external user to sign up with employee ID in the comment field. When an employee enters a peer or accepts a peer request it triggers a peerupdate email to the site operators to inform them to proceed with any pending or coming account requests from the user. The email also contains an Expire value used to limit account lifetime and to decide if the account can be renewed without repeated explicit employee acceptance.
If an external user requested an account without previous Peer invite but with a reference to an instutions employee who already has an account we just forward the request to that employee. She will then receive an email linking to the Peers page where she can accept or reject vouching for the user. As an example we forwarded the account request in tmp_wQsEZ to mariec@phys.example.edu with the command:
~/mig/server/reqacceptpeer.py -u '/home/mig/state/user_pending/tmp_wQsEZ' -a -C -I '*mariec@phys.example.edu*'
After acceptance we could either use the original createuser command with -p AUTO if the request included the explicit email in the comment, or we could replace AUTO with a (wildcard) pattern uniquely identifying the employee. In this case the explict create command was therefore:
~/mig/server/createuser.py -a oid -u '/home/mig/state/user_pending/tmp_wQsEZ' -p '*mariec@phys.example.edu*'
It should be noted that account status is set to temporal when createuser is used with a peer value or with an explicit expire time so that the expire value gets enforced. More about that in editmeta below.
Edit an existing user in the MiG-users.db and in the ~/state/ subdirs. This is the general version to completely edit even ID-specific fields of a user so that all the state dirs and most user files including the ID must be updated. For the user data not part of the ID fields it is usually easier to use the lighter editmeta script, which only changes the MiG-users.db entry and is therefore limited to non-ID fields. To change the email address of a user from galileo.galilei@studenti.example.com to galileo.galilei@personale.example.com we would use:
nice ~/mig/server/edituser.py -i '/C=IT/ST=NA/L=NA/O=Universita di Pisa/OU=NA/CN=Galileo Galilei/emailAddress=galileo.galilei@studenti.example.com' \
'Galileo Galilei' 'Universita di Pisa' '' IT 'galileo.galilei@personale.example.com'
The format is obviously a bit cumbersome with all ID fields before the changed one needed even if redundant.
Edit the metadata of a user in the MiG-users.db in order to e.g. change the role of a user.
~/mig/server/editmeta.py -v '/C=DK/ST=NA/L=NA/O=BIO/OU=NA/CN=Charles Darwin/emailAddress=charles.darwin@bio.example.edu' 'role' 'vip'
MiGrid sites rely on account status as a central method of controlling account expiry and access. Thus, in case of abuse or similar it is possible to lock an account by changing account status to suspended or retired with editmeta:
~/mig/server/editmeta.py '/C=DK/ST=NA/L=NA/O=PHYS/OU=NA/CN=John Dalton/emailAddress=dalton@phys.example.edu' status suspended
In order to time-limit an existing account the status can be set to temporal to prevent all automatic renewal
~/mig/server/editmeta.py '/C=DK/ST=NA/L=NA/O=Manchester Academy/OU=NA/CN=Joe Dalton/emailAddress=dalton@phys.example.edu' status temporal
Finally suspended or temporal accounts can be set back to the default active status in order to again let all web logins proceed and auto-renew the account expire value:
~/mig/server/editmeta.py '/C=DK/ST=NA/L=NA/O=Manchester Academy/OU=NA/CN=Joe Dalton/emailAddress=dalton@phys.example.edu' status active
Please note that account status and expire does NOT cover any associated Seafile accounts. Furthermore on sensitive data sites with GDP-enabled additional measures may be needed.
MiGrid sites additonally include the io_account_expire configuration option to toggle enforcing expiry for the IO protocols to avoid the security implications of stale old accounts. In that way users can only log in on the IO protocols if they have logged in on web within the last few months or explicitly renewed their account for a full year using repeated sign up.
Sometimes it's convenient to lookup a user in the MiG-users.db e.g in relation to support questions. The searchusers.py script allows searching on fields like email
~/mig/server/searchusers.py -E dalton@phys.example.com
or on wildcard patterns for the full ID:
~/mig/server/searchusers.py -I '*Niels B*'
Used to clean up completely after no longer active users both in MiG-users.db and in the ~/state/ subdirs. This includes all user data so use with care! To delete a test user for the AtomicTheory1808 workshop we would run:
~/mig/server/deleteuser.py -i '/C=UK/ST=NA/L=NA/O=AtomicTheory1808/OU=NA/CN=John Dalton/emailAddress=john@dalton.info'
Use the rejectuser.py script to reject an external user requesting an account or renewal e.g. in case no valid access reason or insufficient info on internal employee contact was provided. The rejectuser script removes the request file and informs the requester that the request was denied and why on email. A link to retry with most fields pre-filled is also included in the email. As an example the command to reject the MATERIALS account renewal request in tmpaEg8V0 due to missing UCPH contact details in the request Comment would be:
~/mig/server/rejectuser.py -a oid -C -u '/home/mig/state/user_pending/tmpaEg8V0' -r 'comment field MUST include the name and email of your contact employed at UCPH, as emphasized in the inline help and explained in our FAQ and documentation. HINT: probably John Dalton (dalton@phys.examaple.edu) for MATERIALS'
Use the notifymigoid.py script to send out an email with basic login info for users with login through the local migoid OpenID service. Upon sign up with reqoid the admin email includes the specific command to create the user and send out the intro email.
As an example the command to inform John and the server admins about his account access would be:
~/mig/server/notifymigoid.py -a -C -I '/C=DK/ST=NA/L=NA/O=PHYS/OU=NA/CN=John Dalton/emailAddress=dalton@example.edu'
Given using a single sign-on provider for internal users, say students or employees at a university, will renew their passwords through the single sign-on provider.
When using MiGrid's authentication for external users, the external users can request a new password through the "Forgot Password?" link found https://ext.example.edu. Currently, site operators will have to accept/reject these password renewal requests manually. In future versions, it is possible to make this process fully automated.
With automatic expiry on the built-in migoid logins, typically used for external collaboration partner accounts, it is useful to warn users a bit ahead of expiry. We run the notifyexpire.py script from cron to do so up to three times starting 30 days before. In that way users get a chance to do semi-automatic renewal with the authenticated Xgi-bin version of reqoid where they only need to enter password and comment. After expire they either need to enter their account fields again in the form or use the personal link now included in notify emails to auto-fill most of the form.
MiGrid sites support mass importing users through the importusers.py script. It basically takes a list of user IDs and runs the core createuser actions for each of them. Additionally it allows password auto-generation and integrates support for VGrid membership requests. Typically someone teaching a class or in charge of a project hands over a list of users on e.g. csv-format. We may have to tweak it to some extent but it could like this:
cat workshop-extra-participants.csv
### full_name;email;organization;country
Ada Lovelace;ada.lovelace@example.com;Babbage Research Group;UK
Dorothy Hodgkin;dorothy.hodgkin@example.com;University of Cambridge;UK
where the first line is a mandatory header specifying the MiG-users.db fields and order of the following entries. Site operators can then use the parsecsv.py script to translate to the internal MiG ID format and the importusers.py to actually create the users. Please note that you may have to juggle with file encodings if the csv comes from Windows or a spreadsheet export. It '''must''' be UTF-8 if it contains non-ascii characters. Optional random password generation can be requested with -P AUTO as shown:
python ~/mig/server/parsecsvusers.py workshop-extra-participants.csv > workshop-extra-participants.list
~/mig/server/importusers.py -v -P AUTO -e $(date --date="2025-0-18 0:00" +'%s') workshop-extra-participants.list
Finally it is usually convenient to send out the account intro email and a password reminder to inform said users about where they login and what their credentials are.
IFS=$(echo -en "\n\b") ; for i in $(cat workshop-extra-participants.list ); do
~/mig/server/notifymigoid.py -a -C -I "$i" && ~/mig/server/notifypassword.py -a -I "$i"
done
Note the IFS variable which is needed to prevent the shell breaking IDs with space into individual parts. With automatic account expire we typically don't need to care too much about removing the accounts again but if needed a similar shell loop can be used for the deleteuser.py script.
NB: in most cases it is now easier to let them use Peers as a self-service solution to import and invite the list of users.
We have a couple of helpers to check user password compliance with the site password policy and to check if 2FA is enabled. To check if David has valid passwords we could run:
~/mig/server/checkpwpolicy.py -I '*Hume*'
Password policy errors:
No password set for /C=DK/ST=NA/L=NA/O=Edinburgh/OU=NA/CN=David Hume/emailAddress=acb123@alumni.example.edu
Similarly one can check what 2FA settings for Winter has with:
~/mig/server/checktwofactor.py -v -I '*winter@bio*'
Loaded existing user DB from: ./MiG-users.db
2FA status:
Checking /C=DK/ST=NA/L=NA/O=Trinity College/OU=NA/CN=Gregory Winter/emailAddress=winter@bio.example.edu
inspecting /home/mig/state/user_settings/+C=DK+ST=NA+L=NA+O=Trinity_College+OU=NA+CN=Greogory_Winter+emailAddress=winter@bio.example.edu/twofactor
EXT_OID_TWOFACTOR enabled for /C=DK/ST=NA/L=NA/O=Trinity College/OU=NA/Gregory Winter/emailAddress=winter@bio.example.edu
MIG_OID_TWOFACTOR not enabled for: /C=DK/ST=NA/L=NA/O=Trinity CollegeNBI/OU=NA/CN=Gregory Winter/emailAddress=winter@bio.example.edu
WEBDAVS_TWOFACTOR not enabled for: /C=DK/ST=NA/L=NA/O=Trinity College/OU=NA/CN=Gregory Winter/emailAddress=winter@bio.example.edu
FTPS_TWOFACTOR not enabled for: /C=DK/ST=NA/L=NA/O=Trinity College/OU=NA/CN=Gregory Winter/emailAddress=winter@bio.example.edu
A custom seed and interval is needed for some TOTP hardware devices. To avoid exposing seeds in shell history and (sudo) logs we read the custom seed from a file.
To read a custom seed from file X.txt with interval 60 for Gregory run:
~/mig/server/reset2fakey.py -v -i '/C=DK/ST=NA/L=NA/O=Trinity College/OU=NA/CN=Gregory Winter/emailAddress=winter@bio.example.edu' 'X.txt' 60
To reset the twofactor key using a random seed and default interval:
~/mig/server/reset2fakey.py -v -i '/C=DK/ST=NA/L=NA/O=Trinity College/OU=NA/CN=Gregory Winter/emailAddress=winter@bio.example.edu'
We run a simple collection of stat extraction commands weekly with the usagestats.py script. It looks up disk use, counts users and workgroups, with guesstimates on the number of recent changes and user affiliation.
On high server load the internal VGrid/Workgroup cache may go out of sync and result in lost admin links for certain VGrid / Workgroup owners. It's a bug but the easiest way to fix such issues is to have the owner manually open the admin URL and use the Repair-button at the bottom of that page. The admin page URL for the workgroup called VGRIDNAME on migrid instance is https://example.edu/wsgi-bin/adminvgrid.py?vgrid_name=VGRIDNAME .
Alternatively the same can be done by a site operator using the underlying command on migrid.
In a fictive case for the Quantum workgroup of user /C=DK/ST=NA/L=NA/O=NBI/OU=NA/CN=Niels Bohr/emailAddress=niels.bohr@nbi.example.edu
it can be done with the command:
cd ~/mig/cgi-bin && \
python fakecgi.py 'updatevgrid.py' POST 'vgrid_name=Quantum' \
'/C=DK/ST=NA/L=NA/O=NBI/OU=NA/CN=Niels Bohr/emailAddress=niels.bohr@nbi.example.edu' \
'niels.bohr@nbi.example.edu' localhost true
Afterwards operators can inspect the output of the vgridman.py backend for the user to verify the link is restored.
cd ~/mig/cgi-bin && \
python fakecgi.py 'vgridman.py' GET 'operation=showlist' \
'/C=DK/ST=NA/L=NA/O=NBI/OU=NA/CN=Niels Bohr/emailAddress=niels.bohr@nbi.example.edu'