Hey,
Iâve implemented custom web-based frontends that offer a limited set of domain manipulation functions to a limited set of users multiple times. I usually divide those up into two components:
- The web frontend, usually a CGI script written in whichever scripting language Iâm most comfortable with (Perl, Ruby for me).
- A backend script that receives a very limited set of parameters from the web frontend script and translates those into domain modification calls (either modifying the LDAP directory directly or by calling the
udm
command-line tool), again written whatever language you want to.
Thereâs a very good reason for using two components: security. All CGI scripts usually run as the user the web server runs as, which is www-data
, a non-privileged user. In order to modify the LDAP you need some kind of elevated privileges (e.g. udm
uses the machine account and needs access to /etc/machine.secret
which is only readable by root
). One could give www-data
that access, but the huge drawback is that suddenly all CGI scripts, all PHP scripts etc. all have that access. And all too often arbitrary users can upload arbitrary PHP files to be interpreted by the web server (e.g. via /home/username/public_html
which is then accessible as http://server.name/~username/âŠ
).
Hence the split. I usually allow the user www-data
to execute the backend script with arbitrary parameters via sudo
.
In order to be really secure, you must implement all verification in the backend script (and some in both the backend and the frontend script). For example, if you want to restrict access to that tool to members of the group user admins
, you will have to implement that in both scripts. The frontend script should show some kind of login screen and error out if the credentials provided donât belong to a user who is a member of said group.
However, those same credentials must be passed on to the backend script which has to check the same. If the backend script didnât verify credentials and relied on the frontend script to do so, any other rogue PHP/CGI script could simply pretend to make that check and call the backend script in order to make changes the calling rogue script shouldnât be allowed to trigger.
As a communication channel I usually use temporary files containing JSON. I only pass the name of the temporary file to the backend script â for simplicity reasons. JSON is easy to read and write (use existing libraries, donât implement your own parser, of course), you donât have to worry about command line parameters being visible in the process list or in any history files etc.
I can usually whip up something simple within a day. Depending on the scope of functionality this can take an arbitrary amount of time, of course.
What I like about implementing your own solution is that youâre much more aware of where the security boundaries are and what the consequences of violating them are. Your frontend usually offers a very small number of functions with a small number of parameters. Validating them in the backend is therefore straightforward and fast. For example: users created by your user admins
must always be members of certain groups? Easy, donât offer the choice of which groups to add to in the frontend in the first place and hardcode them in the backend. Or you want to allow certain groups? Great, hardcode that list in the backend and make sure the âadditional groupsâ passed from the frontend are all members of said list.
Using a real programming/scripting language also allows you to express arbitrary constraints â unlike LDAP ACLs.
Another real benefit is that your frontend only offers those controls/attributes that may actually be changed or set by the user admins
members. This is unlike the UMC which would always offer you the full âedit userâ mask, no matter what LDAP ACLs allow and prohibit. Itâs very confusing to figure out which parameters you may or may not change in the UMC because it seems to suggest you may change each and every of those.
Kind regards,
mosu