Use other attributes (#77)

* Changes to allow using different account attributes, additional objectclasses, protection against accidentally removing all admin acccess, remove Helm files, username sanity updates

* Fixed LDAP user searches using the base DN

* Don't render the menu if there are fatal errors

* FIx tag parsing.  No TLS warning for local LDAP connections.

* Fix bug retrieving account attributes

* Multi-arch support and tidied-up README
This commit is contained in:
Brian Lycett 2021-03-13 14:11:38 +00:00 committed by GitHub
parent 882816ac1d
commit 5acc835be9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 708 additions and 723 deletions

View File

@ -6,21 +6,21 @@ RUN apt-get update && \
libfreetype6-dev \ libfreetype6-dev \
libjpeg-dev \ libjpeg-dev \
libpng-dev && \ libpng-dev && \
rm -rf /var/lib/apt/lists/* && \ rm -rf /var/lib/apt/lists/*
ln -s /usr/lib/x86_64-linux-gnu/libldap.so /usr/lib/libldap.so && \
ln -s /usr/lib/x86_64-linux-gnu/liblber.so /usr/lib/liblber.so
RUN docker-php-ext-configure gd \ RUN docker-php-ext-configure gd \
--enable-gd-native-ttf \ --enable-gd-native-ttf \
--with-freetype-dir=/usr/include/freetype2 \ --with-freetype-dir=/usr/include/freetype2 \
--with-png-dir=/usr/include \ --with-png-dir=/usr/include \
--with-jpeg-dir=/usr/include && \ --with-jpeg-dir=/usr/include && \
docker-php-ext-install -j$(nproc) ldap gd docker-php-ext-install -j$(nproc) gd && \
libdir=$(find /usr -name "libldap.so*" | sed -e 's/\/usr\///' -e 's/\/libldap.so//') && \
docker-php-ext-configure ldap --with-libdir=$libdir && \
docker-php-ext-install -j$(nproc) ldap
ADD https://github.com/PHPMailer/PHPMailer/archive/v6.2.0.tar.gz /tmp ADD https://github.com/PHPMailer/PHPMailer/archive/v6.2.0.tar.gz /tmp
RUN a2enmod rewrite ssl RUN a2enmod rewrite ssl && a2dissite 000-default default-ssl
RUN a2dissite 000-default default-ssl
EXPOSE 80 EXPOSE 80
EXPOSE 443 EXPOSE 443

188
README.md
View File

@ -1,11 +1,11 @@
LDAP User Manager # LDAP User Manager
--
This is a PHP LDAP account manager; a web-based GUI interface which allows you to quickly populate a new LDAP directory and easily manage user accounts and groups. It also has a self-service password change module. This is a PHP LDAP account manager; a web-based GUI interface which allows you to quickly populate a new LDAP directory and easily manage user accounts and groups. It also has a self-service password change module.
It's designed to work with OpenLDAP and to be run as a container. It complements OpenLDAP containers such as [*osixia/openldap*](https://hub.docker.com/r/osixia/openldap/). It's designed to work with OpenLDAP and to be run as a container. It complements OpenLDAP containers such as [*osixia/openldap*](https://hub.docker.com/r/osixia/openldap/).
Features ***
---
## Features
* Setup wizard: this will create the necessary structure to allow you to add users and groups and will set up an initial admin user that can log into the user manager. * Setup wizard: this will create the necessary structure to allow you to add users and groups and will set up an initial admin user that can log into the user manager.
* Group creation and management. * Group creation and management.
@ -16,27 +16,27 @@ Features
* Self-service password change: non-admin users can log in to change their password. * Self-service password change: non-admin users can log in to change their password.
* An optional form for people to request accounts (request emails are sent to an administrator). * An optional form for people to request accounts (request emails are sent to an administrator).
Screenshots ***
---
**Initial setup: add an administrator account**: ## Screenshots
![administrator_setup](https://user-images.githubusercontent.com/17613683/59344224-8bb8ae80-8d05-11e9-869b-d08a44f4939d.png)
**Add a new group**:
![new_group](https://user-images.githubusercontent.com/17613683/59344242-95421680-8d05-11e9-9a72-1f55c06dd43d.png)
**Manage group membership**:
![group_membership](https://user-images.githubusercontent.com/17613683/59344247-97a47080-8d05-11e9-8606-0bcc40471458.png)
**Edit accounts**: **Edit accounts**:
![account_overview](https://user-images.githubusercontent.com/17613683/59344255-9c692480-8d05-11e9-9207-051291bafd91.png) ![account_overview](https://user-images.githubusercontent.com/17613683/59344255-9c692480-8d05-11e9-9207-051291bafd91.png)
**Manage group membership**:
![group_membership](https://user-images.githubusercontent.com/17613683/59344247-97a47080-8d05-11e9-8606-0bcc40471458.png)
**Self-service password change**: **Self-service password change**:
![self_service_password_change](https://user-images.githubusercontent.com/17613683/59344258-9ffcab80-8d05-11e9-9dc2-27dfd373fcc8.png) ![self_service_password_change](https://user-images.githubusercontent.com/17613683/59344258-9ffcab80-8d05-11e9-9dc2-27dfd373fcc8.png)
***
Quick start ## Quick start
---
``` ```
docker run \ docker run \
@ -53,21 +53,21 @@ docker run \
-e "LDAP_ADMIN_BIND_PWD=secret"\ -e "LDAP_ADMIN_BIND_PWD=secret"\
-e "LDAP_IGNORE_CERT_ERRORS=true" \ -e "LDAP_IGNORE_CERT_ERRORS=true" \
-e "EMAIL_DOMAIN=ldapusermanager.org" \ -e "EMAIL_DOMAIN=ldapusermanager.org" \
wheelybird/ldap-user-manager:v1.5 wheelybird/ldap-user-manager:v1.6
``` ```
Change the variable values to suit your environment. Now go to https://lum.example.com/setup. Change the variable values to suit your environment. Now go to https://lum.example.com/setup.
***
Configuration ## Configuration
---
Configuration is via environmental variables. Please bear the following in mind: Configuration is via environmental variables. Please bear the following in mind:
* This tool needs to bind to LDAP as a user that has the permissions to modify everything under the base DN. * This tool needs to bind to LDAP as a user that has the permissions to modify everything under the base DN.
* This interface is designed to work with a fresh LDAP server and should only be against existing, populated LDAP directories with caution and at your own risk. * This interface is designed to work with a fresh LDAP server and should only be against existing, populated LDAP directories with caution and at your own risk.
Mandatory: ### Mandatory:
----
* `LDAP_URI`: The URI of the LDAP server, e.g. `ldap://ldap.example.com` or `ldaps://ldap.example.com` * `LDAP_URI`: The URI of the LDAP server, e.g. `ldap://ldap.example.com` or `ldaps://ldap.example.com`
@ -79,10 +79,9 @@ Mandatory:
* `LDAP_ADMINS_GROUP`: The name of the group used to define accounts that can use this tool to manage LDAP accounts. e.g. `admins` * `LDAP_ADMINS_GROUP`: The name of the group used to define accounts that can use this tool to manage LDAP accounts. e.g. `admins`
Optional: ### Optional:
----
**Organisation settings** #### Organisation settings
* `SERVER_HOSTNAME` (default: *ldapusername.org*): The hostname that this interface will be served from. * `SERVER_HOSTNAME` (default: *ldapusername.org*): The hostname that this interface will be served from.
@ -91,7 +90,7 @@ Optional:
* `SITE_NAME` (default: *{ORGANISATION_NAME} user manager*): Change this to replace the title in the menu, e.g. "My Company Account Management". * `SITE_NAME` (default: *{ORGANISATION_NAME} user manager*): Change this to replace the title in the menu, e.g. "My Company Account Management".
**LDAP settings** #### LDAP settings
* `LDAP_USER_OU` (default: *people*): The name of the OU used to store user accounts (without the base DN appended). * `LDAP_USER_OU` (default: *people*): The name of the OU used to store user accounts (without the base DN appended).
@ -103,18 +102,24 @@ Optional:
* `LDAP_TLS_CACERT` (no default): If you need to use a specific CA certificate for TLS connections to the LDAP server (when `LDAP_REQUIRE_STARTTLS` is set) then assign the contents of the CA certificate to this variable. e.g. `-e LDAP_TLS_CACERT="$(</path/to/ca.crt)"` (ensure you're using quotes or you'll get an "invalid reference format: repository name must be lowercase" error. * `LDAP_TLS_CACERT` (no default): If you need to use a specific CA certificate for TLS connections to the LDAP server (when `LDAP_REQUIRE_STARTTLS` is set) then assign the contents of the CA certificate to this variable. e.g. `-e LDAP_TLS_CACERT="$(</path/to/ca.crt)"` (ensure you're using quotes or you'll get an "invalid reference format: repository name must be lowercase" error.
**Advanced LDAP settings** #### Advanced LDAP settings
These settings should only be changed if you're trying to make the user manager work with an LDAP directory that's already populated and the defaults don't work. These settings should only be changed if you're trying to make the user manager work with an LDAP directory that's already populated and the defaults don't work.
* `LDAP_GROUP_MEMBERSHIP_ATTRIBUTE` (default: *memberUID* or *uniqueMember*): The attribute used when adding a user's account to a group. When the `groupOfMembers` objectClass is detected or force-enabled it defaults to `uniqueMember`, otherwise it'll default to `memberUID`. Explicitly setting this variable will override any default. * `LDAP_ACCOUNT_ATTRIBUTE` (default: *uid*): The account attribute used as the account identifier. See [Account names](#account-names) for more information.
* `LDAP_GROUP_MEMBERSHIP_USES_UID` (default: *TRUE* or *FALSE*): If *TRUE* then the entry for a member of a group will be just the username, otherwise it's the member's full DN. When the `groupOfMembers` objectClass is detected or force-enabled it defaults to `FALSE`, otherwise it'll default to `TRUE`. Explicitly setting this variable will override the default. * `LDAP_GROUP_MEMBERSHIP_ATTRIBUTE` (default: *memberUID* or *uniqueMember*): The attribute used when adding a user's account to a group. When the `groupOfMembers` objectClass is detected `FORCE_RFC2307BIS` is `TRUE` it defaults to `uniqueMember`, otherwise it'll default to `memberUID`. Explicitly setting this variable will override any default.
* `LDAP_ACCOUNT_ADDITIONAL_OBJECTCLASSES` (no default): A comma-separated list of additional objectClasses to use when creating an account. See [Extra objectClasses and attributes](#extra-objectclasses-and-attributes) for more information.
* `LDAP_ACCOUNT_ADDITIONAL_ATTRIBUTES` (no default): A comma-separated list of extra attributes to display when creating an account. See [Extra objectClasses and attributes](#extra-objectclasses-and-attributes) for more information.
* `LDAP_GROUP_MEMBERSHIP_USES_UID` (default: *TRUE* or *FALSE*): If *TRUE* then the entry for a member of a group will be just the username, otherwise it's the member's full DN. When the `groupOfMembers` objectClass is detected or `FORCE_RFC2307BIS` is `TRUE` it defaults to `FALSE`, otherwise it'll default to `TRUE`. Explicitly setting this variable will override the default.
* `FORCE_RFC2307BIS` (default: *FALSE*): Set to *TRUE* if the auto-detection is failing to spot that the RFC2307BIS schema is available. When *FALSE* the user manager will use auto-detection. See [Using the RFC2307BIS schema](#using-the-rfc2307bis-schema) for more information. * `FORCE_RFC2307BIS` (default: *FALSE*): Set to *TRUE* if the auto-detection is failing to spot that the RFC2307BIS schema is available. When *FALSE* the user manager will use auto-detection. See [Using the RFC2307BIS schema](#using-the-rfc2307bis-schema) for more information.
**User account settings** #### User account settings
* `DEFAULT_USER_GROUP` (default: *everybody*): The group that new accounts are automatically added to when created. *NOTE*: If this group doesn't exist then a group is created with the same name as the username and the user is added to that group. * `DEFAULT_USER_GROUP` (default: *everybody*): The group that new accounts are automatically added to when created. *NOTE*: If this group doesn't exist then a group is created with the same name as the username and the user is added to that group.
@ -122,16 +127,18 @@ These settings should only be changed if you're trying to make the user manager
* `EMAIL_DOMAIN` (no default): If set then the email address field will be automatically populated in the form of `username@email_domain`. * `EMAIL_DOMAIN` (no default): If set then the email address field will be automatically populated in the form of `username@email_domain`.
* `USERNAME_FORMAT` (default: *{first_name}-{last_name}*): The template used to dynamically generate usernames. See [Username format](#username-format). * `ENFORCE_SAFE_SYSTEM_NAMES` (default: *TRUE*): If set to `TRUE` (the default) this will check system login and group names against `USERNAME_REGEX` to ensure they're safe to use on servers. See [Account names](#account-names) for more information.
* `USERNAME_REGEX` (default: *^[a-z][a-zA-Z0-9\._-]{3,32}$*): The regular expression used to ensure a username (and group name) is valid. See [Username format](#username-format). * `USERNAME_FORMAT` (default: *{first_name}-{last_name}*): The template used to dynamically generate the usernames stored in the `uid` attribute. See [Username format](#username-format).
* `USERNAME_REGEX` (default: *^[a-z][a-zA-Z0-9\._-]{3,32}$*): The regular expression used to ensure account names and group names are safe to use on servers. See [Username format](#username-format).
* `PASSWORD_HASH` (no default): Select which hashing method which will be used to store passwords in LDAP. Options are (in order of precedence) `SHA512CRYPT`, `SHA256CRYPT`, `MD5CRYPT`, `SSHA`, `SHA`, `SMD5`, `MD5`, `CRYPT` & `CLEAR`. If your chosen method isn't available on your system then the strongest available method will be automatically selected - `SSHA` is the strongest method guaranteed to be available. Cleartext passwords should NEVER be used in any situation outside of a test. * `PASSWORD_HASH` (no default): Select which hashing method which will be used to store passwords in LDAP. Options are (in order of precedence) `SHA512CRYPT`, `SHA256CRYPT`, `MD5CRYPT`, `SSHA`, `SHA`, `SMD5`, `MD5`, `CRYPT` & `CLEAR`. If your chosen method isn't available on your system then the strongest available method will be automatically selected - `SSHA` is the strongest method guaranteed to be available. Cleartext passwords should NEVER be used in any situation outside of a test.
* `ACCEPT_WEAK_PASSWORDS` (default: *FALSE*): Set this to *TRUE* to prevent a password being rejected for being too weak. The password strength indicators will still gauge the strength of the password. Don't enable this in a production environment. * `ACCEPT_WEAK_PASSWORDS` (default: *FALSE*): Set this to *TRUE* to prevent a password being rejected for being too weak. The password strength indicators will still gauge the strength of the password. Don't enable this in a production environment.
**Email sending** #### Email sending settings
To send emails you'll need to use an existing SMTP server. Email sending will be disabled if `SMTP_HOSTNAME` isn't set. To send emails you'll need to use an existing SMTP server. Email sending will be disabled if `SMTP_HOSTNAME` isn't set.
@ -145,24 +152,23 @@ To send emails you'll need to use an existing SMTP server. Email sending will b
* `SMTP_USE_TLS` (default: *FALSE*): Set to TRUE if the SMTP server requires TLS to be enabled. * `SMTP_USE_TLS` (default: *FALSE*): Set to TRUE if the SMTP server requires TLS to be enabled.
* `EMAIL_FROM_ADDRESS` (default: *admin@{EMAIL_DOMAIN}*): The FROM email address used when sending out emails. The default domain is taken from `EMAIL_DOMAIN` under **User account settings**. * `EMAIL_FROM_ADDRESS` (default: *admin@`EMAIL_DOMAIN`*): The FROM email address used when sending out emails. The default domain is taken from `EMAIL_DOMAIN` under **User account settings**.
* `EMAIL_FROM_NAME` (default: *{SITE_NAME}*): The FROM name used when sending out emails. The default name is taken from `SITE_NAME` under **Organisation settings**. * `EMAIL_FROM_NAME` (default: *`SITE_NAME`*): The FROM name used when sending out emails. The default name is taken from `SITE_NAME` under **Organisation settings**.
**Account requests** #### Account request settings
* `ACCOUNT_REQUESTS_ENABLED` (default: *FALSE*): Set to TRUE in order to enable a form that people can fill in to request an account. This will send an email to {ACCOUNT_REQUESTS_EMAIL} with their details and a link to the account creation page where the details will be filled in automatically. You'll need to set up email sending (see **Email sending**, above) for this to work. If this is enabled but email sending isn't then requests will be disabled and an error message sent to the logs. * `ACCOUNT_REQUESTS_ENABLED` (default: *FALSE*): Set to TRUE in order to enable a form that people can fill in to request an account. This will send an email to `ACCOUNT_REQUESTS_EMAIL` with their details and a link to the account creation page where the details will be filled in automatically. You'll need to set up email sending (see **Email sending**, above) for this to work. If this is enabled but email sending isn't then requests will be disabled and an error message sent to the logs.
* `ACCOUNT_REQUESTS_EMAIL` (default: *{EMAIL_FROM_ADDRESS}*): This is the email address that any requests for a new account are sent to. * `ACCOUNT_REQUESTS_EMAIL` (default: *`EMAIL_FROM_ADDRESS`*): This is the email address that any requests for a new account are sent to.
**Site security settings**
**Website sessions** #### Website security
* `NO_HTTPS` (default: *FALSE*): If you set this to *TRUE* then the server will run in HTTP mode, without any encryption. This is insecure and should only be used for testing. * `NO_HTTPS` (default: *FALSE*): If you set this to *TRUE* then the server will run in HTTP mode, without any encryption. This is insecure and should only be used for testing. See [HTTPS certificates](#https-certificates)
* `SESSION_TIMEOUT` (default: *10 minutes*): How long before an idle session will be timed out. * `SESSION_TIMEOUT` (default: *10 minutes*): How long before an idle session will be timed out.
**Debugging settings** #### Debugging settings
* `LDAP_DEBUG` (default: *FALSE*): Set to TRUE to increase the logging level for LDAP requests. This will output passwords to the error log - don't enable this in a production environment. This is for information on problems updating LDAP records and such. To debug problems connecting to the LDAP server in the first place use `LDAP_VERBOSE_CONNECTION_LOGS`. * `LDAP_DEBUG` (default: *FALSE*): Set to TRUE to increase the logging level for LDAP requests. This will output passwords to the error log - don't enable this in a production environment. This is for information on problems updating LDAP records and such. To debug problems connecting to the LDAP server in the first place use `LDAP_VERBOSE_CONNECTION_LOGS`.
@ -172,10 +178,44 @@ To send emails you'll need to use an existing SMTP server. Email sending will b
* `SMTP_LOG_LEVEL` (default: *0*): Set to between 1-4 to get SMTP logging information (0 disables SMTP debugging logs though it will still display errors). See https://github.com/PHPMailer/PHPMailer/wiki/SMTP-Debugging for details of the levels. * `SMTP_LOG_LEVEL` (default: *0*): Set to between 1-4 to get SMTP logging information (0 disables SMTP debugging logs though it will still display errors). See https://github.com/PHPMailer/PHPMailer/wiki/SMTP-Debugging for details of the levels.
SSL setup
---
When `NO_HTTPS` is set to **FALSE** (the default), the webserver (Apache HTTPD) expects to find `/opt/ssl/server.key` and `/opt/ssl/server.crt`, and these certificates should match `SERVER_HOSTNAME`. If these files aren't found then the startup script will create self-signed certificates based on `SERVER_HOSTNAME`. To use your own key and certificate then you need to bind-mount a directory containing them to `/opt/ssl`. You can also add a certificate chain file (the Apache `SSLCertificateChainFile` option) if needed - name it `chain.pem` and place it in the same directory as `server.key` and `server.crt` . ***
## Initial setup
You can get the LDAP user manager running by following the [Quick start](#quick-start) instructions if you've got an LDAP server running already. If you haven't got an LDAP server then follow the [Testing with an OpenLDAP container](#testing with-an-openldap-container) instructions.
Once you've got got the LDAP user manager up-and-running you should run the setup wizard.
This will create the LDAP structures that the user manager needs in order to create accounts and groups. Go to `https://{SERVER_HOSTNAME}/setup` to get started (replace `{SERVER_HOSTNAME}` with whatever you set `SERVER_HOSTNAME` to in the Docker run command).
The log in password is the admin user's password (the value you set for `LDAP_ADMIN_BIND_DN`).
The setup utility will create the user and account trees, records that store the last UID and GID used when creating a user account or group, a group for admins and the initial admin account.
![initial_setup](https://user-images.githubusercontent.com/17613683/59344213-865b6400-8d05-11e9-9d86-381d59671530.png)
> The setup wizard is primarily designed to use with a new, empty LDAP directory, though it is possible to use it with existing directories as long as you ensure you use the correct advanced LDAP settings.
Once you've set up the initial administrator account you can log into the user manager with it and start creating other accounts. Your username to log in with is (by default) whatever you set **System username** to. See [Account names](#account-names) below if you changed the default by setting `LDAP_ACCOUNT_ATTRIBUTE`.
***
## Account names
Your login ID is whatever the *account identifier* value is for your account. By default the user manager uses the **System username** as your login; this is actually the LDAP `uid` attribute. So if your system username is `test-person`, that's what you'll use to log in with.
The `uid` is the attribute that's normally used as the login username for systems like Linux, FreeBSD, NetBSD etc., and so is a great choice if you're using LDAP to create server accounts.
Other services or software might use the *Common Name* (`cn`) attribute, which is normally a person's full name. So you might therefore log in as `Test Person`.
The account identifier is what uniquely identifies the account, so you can't create multiple accounts where the account identifier is the same.
You should ensure your LDAP clients use the same account identifier attribute when authenticating users.
If you're using LDAP for server accounts then you'll find there are normally constraints on how many cahracters and the type of characters you're allowed to use. The user manager will validate user and group names against `USERNAME_REGEX`. If you don't need to be so strict then you can disable these checks by setting `ENFORCE_SAFE_SYSTEM_NAMES` to `FALSE`.
***
## HTTPS certificates
When `NO_HTTPS` is set to **FALSE** (the default), the user manager expects to find SSL files at `/opt/ssl/server.key` and `/opt/ssl/server.crt`. These certificates should match `SERVER_HOSTNAME`. If these files aren't found then the startup script will create self-signed certificates based on `SERVER_HOSTNAME`. To use your own key and certificate then you need to bind-mount a directory containing them to `/opt/ssl`. You can also add a certificate chain file (the Apache `SSLCertificateChainFile` option) if needed - name it `chain.pem` and place it in the same directory as `server.key` and `server.crt` .
For example, if your key and certificate files are in `/home/myaccount/ssl` you can bind-mount that folder by adding this line to the docker run example above, just after the last line starting with `-e`: For example, if your key and certificate files are in `/home/myaccount/ssl` you can bind-mount that folder by adding this line to the docker run example above, just after the last line starting with `-e`:
``` ```
@ -183,20 +223,10 @@ For example, if your key and certificate files are in `/home/myaccount/ssl` you
``` ```
Initial setup ***
---
Ideally you'll be using this against an empty LDAP directory. You can use the setup utility to create the LDAP structures that this user manager needs in order to create accounts and groups. Go to `https://{SERVER_HOSTNAME}/setup` to get started (replace `{SERVER_HOSTNAME}` with whatever you set `SERVER_HOSTNAME` to in the Docker run command). ## Sending emails
The log in password is the admin user's password (what `LDAP_ADMIN_BIND_DN` was set to).
The setup utility will create the user and account trees, records that store the last UID and GID used when creating a user account or group, a group for admins and the initial admin account.
![initial_setup](https://user-images.githubusercontent.com/17613683/59344213-865b6400-8d05-11e9-9d86-381d59671530.png)
Sending emails
---
When you create an account you'll have an option to send an email to the person you created the account for. The email will give them their new username, password and a link to the self-service password change utility. When you create an account you'll have an option to send an email to the person you created the account for. The email will give them their new username, password and a link to the self-service password change utility.
@ -205,10 +235,11 @@ If you haven't passed in those settings or if the account you've created has no
When the account is created you'll be told if the email was sent or not but be aware that just because your SMTP server accepted the email it doesn't mean that it was able to deliver it. If you get a message saying the email wasn't sent then check the logs for the error. You can increase the log level (`SMTP_LOG_LEVEL`) to above 0 in order to see SMTP debug logs. When the account is created you'll be told if the email was sent or not but be aware that just because your SMTP server accepted the email it doesn't mean that it was able to deliver it. If you get a message saying the email wasn't sent then check the logs for the error. You can increase the log level (`SMTP_LOG_LEVEL`) to above 0 in order to see SMTP debug logs.
Username format ***
---
When entering the user's first and last names a bit of JavaScript automatically generates the username. The way it generates is it based on a template format defined by `USERNAME_FORMAT`. This is basically a string in which predefined macros are replaced by the formatted first and/or last name. ## Username format
When entering a person's name the system username is automatically filled-in based on a template. The template is defined in `USERNAME_FORMAT` and is a string containing predefined macros that are replaced with the relevant value.
The default is `{first_name}-{last_name}` with which *Jonathan Testperson*'s username would be *jonathan-testperson*. The default is `{first_name}-{last_name}` with which *Jonathan Testperson*'s username would be *jonathan-testperson*.
Currently the available macros are: Currently the available macros are:
@ -217,27 +248,44 @@ Currently the available macros are:
* `{last_name}`: the last name in lowercase * `{last_name}`: the last name in lowercase
* `{last_name_initial}`: the first initial of the last name in lowercase * `{last_name_initial}`: the first initial of the last name in lowercase
Anything else in the `USERNAME_FORMAT` string is left as defined, but the username is also checked for validity against `USERNAME_REGEX`. This is to ensure that there aren't any characters forbidden by other systems (i.e. email or Linux/Unix accounts). Anything else in the `USERNAME_FORMAT` string is left unmodified. If `ENFORCE_SAFE_SYSTEM_NAMES` is set then the username is also checked for validity against `USERNAME_REGEX`. This is to ensure that there aren't any characters forbidden when using LDAP to create server or email accounts.
If `EMAIL_DOMAIN` is set then the email address field will be automatically updated in the form of `username@email_domain`. Entering anything manually in that field will stop the automatic update of the email field. If `EMAIL_DOMAIN` is set then the email address field will be automatically updated in the form of `username@email_domain`. Entering anything manually in that field will stop the automatic update of the email field.
***
Using the RFC2307BIS schema ## Extra objectClasses and attributes
---
The user manager will attempt detect if your LDAP server has the RFC2307BIS schema available and, if it does, use it when creating groups. This will allow you to use `memberOf` in LDAP searches which gives you an easy way to check if a user is a member of a group. For example: `(&(objectClass=posixAccount)(memberof=cn=somegroup,ou=groups,dc=ldapusermanager,dc=org))`. See [this guide](https://unofficialaciguide.com/2019/07/31/ldap-schemas-for-aci-administrators-rfc2307-vs-rfc2307bis/) for more information. If you need to use this user manager with an existing LDAP directory and your account records need additional objectClasses and attributes then you can add them via `LDAP_ACCOUNT_ADDITIONAL_OBJECTCLASSES` and `LDAP_ACCOUNT_ADDITIONAL_ATTRIBUTES`.
With OpenLDAP this schema isn't normally available by default; you need to configure your server to use the **RFC2307BIS** schema when setting up your directory. `LDAP_ACCOUNT_ADDITIONAL_OBJECTCLASSES` is a comma-separated list of objectClasses to add when creating the account record. For example, `LDAP_ACCOUNT_ADDITIONAL_OBJECTCLASSES=ldappublickey,couriermailaccount`.
If for some reason you do have the schema available but it isn't being detected then you can force it's use by setting `FORCE_RFC2307BIS` to `TRUE`. To add extra fields for new attributes you need to pass a comma-separated string of the attributes and optionally the label for the attribute (which will be shown on the user form) and a default value to `LDAP_ACCOUNT_ADDITIONAL_ATTRIBUTES` separated by colons (`:`).
The format for configuring an attribute is: `attribute1:label1,default_value1,attribute2:label2:default_value2`. If you don't supply a label then the form field will be labelled with the attribute name.
An example (for the couriermailaccount objectClass) would be: `mailbox:Mailbox:domain.com,quota:Mail quota:20`
ObjectClasses often have attributes that must have a value, so you should definitely set a default for those attributes.
This is advanced stuff and the user manager doesn't attempt to validate any objectClasses or any attributes, labels or default values you pass in. It's up to you to ensure that your LDAP server has the appropriate schemas and that the labels and values are sane.
***
## Using the RFC2307BIS schema
Using the **RFC2307BIS** will allow you to use `memberOf` in LDAP searches which gives you an easy way to check if a user is a member of a group. For example: `(&(objectClass=posixAccount)(memberof=cn=somegroup,ou=groups,dc=ldapusermanager,dc=org))`.
OpenLDAP will use the RFC2307 (NIS) schema by default; you'll need to configure your server to use the **RFC2307BIS** schema when setting up your directory. See [this guide](https://unofficialaciguide.com/2019/07/31/ldap-schemas-for-aci-administrators-rfc2307-vs-rfc2307bis/) for more information regarding RFC2307 vs RFC2307BIS.
Setting up RFC2307BIS is way beyond the scope of this README, but if you plan on using [osixia/openldap](https://github.com/osixia/docker-openldap) as your LDAP server then you can easily enable the RFC2307BIS schema by setting `LDAP_RFC2307BIS_SCHEMA` to `true` during the initial setup.
The user manager will attempt detect if your LDAP server has the RFC2307BIS schema available and, if it does, use it when creating groups. This will allow you to use `memberOf` in LDAP searches which gives you an easy way to check if a user is a member of a group. For example: `(&(objectClass=posixAccount)(memberof=cn=somegroup,ou=groups,dc=ldapusermanager,dc=org))`.
If for some reason you do have the schema available but it isn't being detected then you can force the user manager to use it by setting `FORCE_RFC2307BIS` to `TRUE`.
**Note**: if you force-enable using RFC2307BIS but your LDAP server doesn't have that schema available then creating and adding users to groups won't work and the user manager will throw errors. **Note**: if you force-enable using RFC2307BIS but your LDAP server doesn't have that schema available then creating and adding users to groups won't work and the user manager will throw errors.
If you plan on using [osixia/openldap](https://github.com/osixia/docker-openldap) as your LDAP server you can enable the RFC2307BIS schema by setting `LDAP_RFC2307BIS_SCHEMA` to `true` during the initial setup. ***
## Testing with an OpenLDAP container
Testing with an LDAP container
--
This will set up an OpenLDAP container you can use to test the user manager against. It uses the RFC2307BIS schema. This will set up an OpenLDAP container you can use to test the user manager against. It uses the RFC2307BIS schema.
``` ```

View File

@ -1,9 +0,0 @@
apiVersion: v1
description: A helm chart for ldap-user-manager
name: ldap-user-manager
version: 0.0.1 # Will be replaced during build
sources:
- https://github.com/wheelybird/ldap-user-manager
maintainers:
- name: Abhishek Srivastava
email: abhishekguitarist@gmail.com

View File

@ -1,139 +0,0 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ldap-user-manager
labels:
app: ldap-user-manager
chart: ldap-user-manager-v0.9.34
release: ldap-user-manager
heritage: Tiller
spec:
selector:
matchLabels:
app: ldap-user-manager
release: ldap-user-manager
template:
metadata:
labels:
app: ldap-user-manager
release: ldap-user-manager
spec:
containers:
- name: ldap-user-manager
image: {{ .Values.image.repository | quote }}
imagePullPolicy: {{ .Values.image.pullPolicy | quote }}
ports:
- name: http
containerPort: {{ .Values.service.httpPort }}
protocol: TCP
- name: https
containerPort: {{ .Values.service.httpsPort }}
protocol: TCP
resources:
limits:
cpu: {{ .Values.resources.limits.cpu | quote }}
memory: {{ .Values.resources.limits.memory | quote }}
requests:
cpu: {{ .Values.resources.requests.cpu | quote }}
memory: {{ .Values.resources.requests.memory | quote }}
env:
- name: LDAP_URI
value: {{ .Values.ldap.URI | quote }}
- name: LDAP_BASE_DN
value: {{ .Values.ldap.baseDN | quote }}
- name: LDAP_ADMIN_BIND_DN
value: {{ .Values.ldap.adminBindDN | quote }}
- name: LDAP_ADMIN_BIND_PWD
value: {{ .Values.ldap.adminBindPassword | quote }}
- name: LDAP_ADMINS_GROUP
value: {{ .Values.ldap.adminGroups | quote }}
{{- if .Values.ldap.userOU }}
- name: LDAP_USER_OU
value: {{ .Values.ldap.userOU | quote }}
{{- end }}
{{- if .Values.ldap.groupOU }}
- name: LDAP_GROUP_OU
value: {{ .Values.ldap.groupOU | quote }}
{{- end }}
{{- if .Values.ldap.groupMemAttr }}
- name: LDAP_GROUP_MEMBERSHIP_ATTRIBUTE
value: {{ .Values.ldap.groupMemAttr | quote }}
{{- end }}
{{- if .Values.ldap.groupMemUID }}
- name: LDAP_GROUP_MEMBERSHIP_USES_UID
value: {{ .Values.ldap.groupMemUID | quote }}
{{- end }}
{{- if .Values.ldap.defaultGroup }}
- name: DEFAULT_USER_GROUP
value: {{ .Values.ldap.defaultGroup | quote }}
{{- end }}
{{- if .Values.ldap.userShell }}
- name: DEFAULT_USER_SHELL
value: {{ .Values.ldap.userShell | quote }}
{{- end }}
{{- if .Values.ldap.emailDomain }}
- name: EMAIL_DOMAIN
value: {{ .Values.ldap.emailDomain | quote }}
{{- end }}
{{- if .Values.ldap.usernameFormat }}
- name: USERNAME_FORMAT
value: {{ .Values.ldap.usernameFormat | quote }}
{{- end }}
{{- if .Values.ldap.usernameRegex }}
- name: USERNAME_REGEX
value: {{ .Values.ldap.usernameRegex | quote }}
{{- end }}
{{- if .Values.ldap.loginTimeout }}
- name: LOGIN_TIMEOUT_MINS
value: {{ .Values.ldap.loginTimeout | quote }}
{{- end }}
{{- if .Values.ldap.nisSchema }}
- name: LDAP_USES_NIS_SCHEMA
value: {{ .Values.ldap.nisSchema | quote }}
{{- end }}
{{- if .Values.cert.startTLS }}
- name: LDAP_REQUIRE_STARTTLS
value: {{ .Values.cert.startTLS | quote }}
{{- end }}
{{- if .Values.ldap.cacert }}
- name: LDAP_TLS_CACERT
value: {{ .Values.cert.cacert | quote }}
{{- end }}
{{- if .Values.ldap.hostname }}
- name: SERVER_HOSTNAME
value: {{ .Values.service.hostname | quote }}
{{- end }}
{{- if .Values.ldap.noHttps }}
- name: NO_HTTPS
value: {{ .Values.service.noHttps | quote }}
{{- end }}
{{- if .Values.ldap.siteName }}
- name: SITE_NAME
value: {{ .Values.service.siteName | quote }}
{{- end }}
{{- if .Values.service.ldapDebug }}
- name: LDAP_DEBUG
value: {{ .Values.service.ldapDebug | quote }}
{{- end }}
{{- if .Values.service.sessionDebug }}
- name: SESSION_DEBUG
value: {{ .Values.service.sessionDebug | quote }}
{{- end }}

View File

@ -1,24 +0,0 @@
---
apiVersion: v1
kind: Service
metadata:
name: ldap-user-manager
labels:
app: ldap-user-manager
chart: ldap-user-manager-v0.0.1
release: ldap-user-manager
heritage: Tiller
spec:
ports:
- port: {{ .Values.service.httpPort }}
targetPort: 80
protocol: TCP
name: http
- port: {{ .Values.service.httpsPort }}
targetPort: 443
protocol: TCP
name: https
type: {{ .Values.service.type }}
selector:
app: ldap-user-manager
release: ldap-user-manager

View File

@ -1,80 +0,0 @@
image:
pullPolicy: "IfNotPresent"
repository: "wheelybird/ldap-user-manager:v1.0"
service:
httpPort: 5556
httpsPort: 5557
# Optional:
# The hostname that this interface will be served from.
hostname: "lum.mycompany.com"
ldapDebug: "TRUE"
sessionDebug: "TRUE"
# If you set this to TRUE then the server will run in HTTP mode, without any encryption. This is insecure and should only be used for testing.
noHttps: "FALSE"
# Change this to replace the title in the menu. e.g. "My Company"
siteName: "ldapusermanager.com"
type: LoadBalancer
resources:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "50m"
memory: "64Mi"
ldap:
# The URI of the LDAP server. e.g. ldap://ldap.example.com or ldaps://ldap.example.com
URI: "ldap://my-openldap:389"
# The base DN for your organisation. e.g. *dc=example,dc=com`
baseDN: "dc=example,dc=org"
# The DN for the user with permission to modify all records under LDAP_BASE_DN. e.g. cn=admin,dc=example,dc=com
adminBindDN: "cn=admin,dc=example,dc=org"
# The password for LDAP_ADMIN_BIND_DN
adminBindPassword: "admin"
# The name of the group used to define accounts that can use this tool to manage LDAP accounts. e.g. admins
adminGroups: "admins"
# Optional params
# The name of the OU used to store user accounts (without the base DN appended).
# userOU: "people"
# The name of the OU used to store groups (without the base DN appended).
# groupOU: "groups"
# The attribute used when adding a user to a group.
# groupMemAttr: "memberUID"
# If TRUE then the entry for a member of a group will be just the username. Otherwise it's the member's full DN.
# groupMemUID: ""
# The group that new accounts are automatically added to when created.
# NOTE: If this group doesn't exist then a group is created with the same name as the username and the user is added to that group.
# defaultGroup: ""
# The shell that will be launched when the user logs into a server.
# userShell: ""
# If set then the email address field will be automatically populated in the form of username@email_domain).
# emailDomain: ""
# The template used to dynamically generate usernames. See the Usernames section below.
# usernameFormat: ""
# The regular expression used to ensure a username (and group name) is valid. See the Usernames section below.
# usernameRegex: ""
# How long before an idle session will be timed out.
loginTimeout: "30"
nisSchema: "TRUE"
cert:
# Optional
# If TRUE then a TLS connection is required for this interface to work.
# If set to FALSE then the interface will work without STARTTLS, but a warning will be displayed on the page.
startTLS: "FALSE"
# If you need to use a specific CA certificate for TLS connections to the LDAP server (when LDAP_REQUIRE_STARTTLS is set),
# then assign the contents of the CA certificate to this variable. e.g. -e LDAP_TLS_CERT=$(</path/to/ca.crt)
# cacert:

View File

@ -25,15 +25,13 @@ if (isset($_POST['delete_group'])) {
$this_group = $_POST['delete_group']; $this_group = $_POST['delete_group'];
$this_group = urldecode($this_group); $this_group = urldecode($this_group);
if (preg_match("/$USERNAME_REGEX/",$this_group)) {
$del_group = ldap_delete_group($ldap_connection,$this_group); $del_group = ldap_delete_group($ldap_connection,$this_group);
if ($del_group) { if ($del_group) {
?> ?>
<div class="alert alert-success" role="alert"> <div class="alert alert-success" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button>
<strong>Success!</strong> Group <strong><?php print $this_group; ?> was deleted. <p class="text-center">Group <strong><?php print $this_group; ?> was deleted.</p>
</div> </div>
<?php <?php
} }
@ -41,11 +39,11 @@ if (isset($_POST['delete_group'])) {
?> ?>
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button>
<strong>Problem!</strong> Group <strong><?php print $this_group; ?></strong> wasn't deleted. <p class="text-center">Group <strong><?php print $this_group; ?></strong> wasn't deleted.</p>
</div> </div>
<?php <?php
} }
}
} }

View File

@ -25,15 +25,13 @@ if (isset($_POST['delete_user'])) {
$this_user = $_POST['delete_user']; $this_user = $_POST['delete_user'];
$this_user = urldecode($this_user); $this_user = urldecode($this_user);
if (preg_match("/$USERNAME_REGEX/",$this_user)) {
$del_user = ldap_delete_account($ldap_connection,$this_user); $del_user = ldap_delete_account($ldap_connection,$this_user);
if ($del_user) { if ($del_user) {
?> ?>
<div class="alert alert-success" role="alert"> <div class="alert alert-success" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button>
<strong>Success!</strong> User <strong><?php print $this_user; ?> was deleted. <p class="text-center">User <strong><?php print $this_user; ?> was deleted.</p>
</div> </div>
<?php <?php
} }
@ -41,11 +39,11 @@ if (isset($_POST['delete_user'])) {
?> ?>
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button>
<strong>Problem!</strong> User <strong><?php print $this_user; ?></strong> wasn't deleted. <p class="text-center">User <strong><?php print $this_user; ?></strong> wasn't deleted.</p>
</div> </div>
<?php <?php
} }
}
} }
#' #'
@ -59,7 +57,7 @@ $people = ldap_get_user_list($ldap_connection);
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
<th>Username</th> <th>Account name</th>
<th>First name</th> <th>First name</th>
<th>Last name</th> <th>Last name</th>
<th>Email</th> <th>Email</th>
@ -68,14 +66,14 @@ $people = ldap_get_user_list($ldap_connection);
</thead> </thead>
<tbody> <tbody>
<?php <?php
foreach ($people as $username => $attribs){ foreach ($people as $account_identifier => $attribs){
$group_membership = ldap_user_group_membership($ldap_connection,$username); $group_membership = ldap_user_group_membership($ldap_connection,$account_identifier);
print " <tr>\n <td><a href='/$THIS_MODULE_PATH/show_user.php?username=" . urlencode($username) . "'>$username</a></td>\n"; print " <tr>\n <td><a href='/$THIS_MODULE_PATH/show_user.php?account_identifier=" . urlencode($account_identifier) . "'>$account_identifier</a></td>\n";
print " <td>" . $people[$username]['givenname'] . "</td>\n"; print " <td>" . $people[$account_identifier]['givenname'] . "</td>\n";
print " <td>" . $people[$username]['sn'] . "</td>\n"; print " <td>" . $people[$account_identifier]['sn'] . "</td>\n";
print " <td>" . $people[$username]['mail'] . "</td>\n"; print " <td>" . $people[$account_identifier]['mail'] . "</td>\n";
print " <td>" . implode(", ", $group_membership) . "</td>\n"; print " <td>" . implode(", ", $group_membership) . "</td>\n";
print " </tr>\n"; print " </tr>\n";
} }

View File

@ -6,6 +6,8 @@ include_once "web_functions.inc.php";
include_once "ldap_functions.inc.php"; include_once "ldap_functions.inc.php";
include_once "module_functions.inc.php"; include_once "module_functions.inc.php";
$attribute_map = ldap_complete_account_attribute_array();
if ( $_POST['setup_admin_account'] ) { if ( $_POST['setup_admin_account'] ) {
$admin_setup = TRUE; $admin_setup = TRUE;
@ -34,58 +36,84 @@ $invalid_username = FALSE;
$weak_password = FALSE; $weak_password = FALSE;
$invalid_email = FALSE; $invalid_email = FALSE;
$disabled_email_tickbox = TRUE; $disabled_email_tickbox = TRUE;
$invalid_cn = FALSE;
$invalid_account_attribute = FALSE;
$new_account_r = array();
foreach ($attribute_map as $attribute => $attr_r) {
if (isset($_POST[$attribute])) {
$$attribute = filter_var($_POST[$attribute], FILTER_SANITIZE_STRING);
}
elseif (isset($attr_r['default'])) {
$$attribute = $attr_r['default'];
}
$new_account_r[$attribute] = $$attribute;
}
##
if (isset($_GET['account_request'])) { if (isset($_GET['account_request'])) {
$first_name=filter_var($_GET['first_name'], FILTER_SANITIZE_STRING); $givenname=filter_var($_GET['first_name'], FILTER_SANITIZE_STRING);
$last_name=filter_var($_GET['last_name'], FILTER_SANITIZE_STRING); $new_account_r['givenname'] = $givenname;
$email=filter_var($_GET['email'], FILTER_SANITIZE_EMAIL);
$username = generate_username($first_name,$last_name);
if ($email == "") { $sn=filter_var($_GET['last_name'], FILTER_SANITIZE_STRING);
$new_account_r['sn'] = $sn;
$uid = generate_username($first_name,$last_name);
$new_account_r['uid'] = $uid;
if ($ENFORCE_SAFE_SYSTEM_NAMES == TRUE) {
$cn = "$givenname$sn";
}
else {
$cn = "$givenname $sn";
}
$new_account_r['cn'] = $cn;
$mail=filter_var($_GET['email'], FILTER_SANITIZE_EMAIL);
if ($mail == "") {
if (isset($EMAIL_DOMAIN)) { if (isset($EMAIL_DOMAIN)) {
$email = $username . "@" . $EMAIL_DOMAIN; $mail = $uid . "@" . $EMAIL_DOMAIN;
$disabled_email_tickbox = FALSE; $disabled_email_tickbox = FALSE;
} }
} }
else { else {
$disabled_email_tickbox = FALSE; $disabled_email_tickbox = FALSE;
} }
$new_account_r['mail'] = $mail;
} }
if (isset($_POST['create_account'])) { if (isset($_POST['create_account'])) {
$ldap_connection = open_ldap_connection();
$first_name = stripslashes($_POST['first_name']);
$last_name = stripslashes($_POST['last_name']);
$username = stripslashes($_POST['username']);
$password = $_POST['password']; $password = $_POST['password'];
$new_account_r['password'] = $password;
$account_identifier = $new_account_r[$LDAP["account_attribute"]];
if ($_POST['email']) { $email = stripslashes($_POST['email']); } if (!isset($cn) or $cn == "") { $invalid_cn = TRUE; }
if ((!isset($account_identifier) or $account_identifier == "") and $invalid_cn != TRUE) { $invalid_account_identifier = TRUE; }
if ((!is_numeric($_POST['pass_score']) or $_POST['pass_score'] < 3) and $ACCEPT_WEAK_PASSWORDS != TRUE) { $weak_password = TRUE; } if ((!is_numeric($_POST['pass_score']) or $_POST['pass_score'] < 3) and $ACCEPT_WEAK_PASSWORDS != TRUE) { $weak_password = TRUE; }
if (isset($email) and !is_valid_email($email)) { $invalid_email = TRUE; } if (isset($mail) and !is_valid_email($mail)) { $invalid_email = TRUE; }
if (preg_match("/\"|'/",$password)) { $invalid_password = TRUE; } if (preg_match("/\"|'/",$password)) { $invalid_password = TRUE; }
if ($_POST['password'] != $_POST['password_match']) { $mismatched_passwords = TRUE; } if ($password != $_POST['password_match']) { $mismatched_passwords = TRUE; }
if (!preg_match("/$USERNAME_REGEX/",$username)) { $invalid_username = TRUE; } if ($ENFORCE_SAFE_SYSTEM_NAMES == TRUE and !preg_match("/$POSIX_REGEX/",$account_identifier)) { $invalid_account_identifier = TRUE; }
if (isset($_POST['send_email']) and isset($email) and $EMAIL_SENDING_ENABLED == TRUE) { $send_user_email = TRUE; } if (isset($_POST['send_email']) and isset($mail) and $EMAIL_SENDING_ENABLED == TRUE) { $send_user_email = TRUE; }
if ( isset($givenname)
if ( isset($first_name) and isset($sn)
and isset($last_name)
and isset($username)
and isset($password) and isset($password)
and !$mismatched_passwords and !$mismatched_passwords
and !$weak_password and !$weak_password
and !$invalid_password and !$invalid_password
and !$invalid_username and !$invalid_account_identifier
and !$invalid_cn
and !$invalid_email) { and !$invalid_email) {
$ldap_connection = open_ldap_connection(); $ldap_connection = open_ldap_connection();
$new_account = ldap_new_account($ldap_connection, $new_account_r);
$new_account = ldap_new_account($ldap_connection, $first_name, $last_name, $username, $password, $email);
if ($new_account) { if ($new_account) {
@ -98,7 +126,7 @@ if (isset($_POST['create_account'])) {
$mail_body = <<<EoT $mail_body = <<<EoT
You've been set up with an account for $ORGANISATION_NAME. Your credentials are: You've been set up with an account for $ORGANISATION_NAME. Your credentials are:
Username: $username Username: $account_identifier
Password: $password Password: $password
You should change your password as soon as possible. Go to ${SITE_PROTOCOL}${SERVER_HOSTNAME}/change_password and log in using your new credentials. This will take you to a page where you can change your password. You should change your password as soon as possible. Go to ${SITE_PROTOCOL}${SERVER_HOSTNAME}/change_password and log in using your new credentials. This will take you to a page where you can change your password.
@ -116,10 +144,10 @@ EoT;
} }
if ($admin_setup == TRUE) { if ($admin_setup == TRUE) {
$member_add = ldap_add_member_to_group($ldap_connection, $LDAP['admins_group'], $username); $member_add = ldap_add_member_to_group($ldap_connection, $LDAP['admins_group'], $account_identifier);
if (!$member_add) { ?> if (!$member_add) { ?>
<div class="alert alert-warning"> <div class="alert alert-warning">
<p class="text-center"><?php print $creation_message; ?>. Unfortunately adding it to the admin group failed.</p> <p class="text-center"><?php print $creation_message; ?> Unfortunately adding it to the admin group failed.</p>
</div> </div>
<?php <?php
} }
@ -139,54 +167,53 @@ EoT;
exit(0); exit(0);
} }
else { else {
if (!$new_account) { ?> ?>
<div class="alert alert-warning"> <div class="alert alert-warning">
<p class="text-center">Failed to create the account.</p> <p class="text-center">Failed to create the account:</p>
<pre>
<?php
print ldap_error($ldap_connection) . "\n";
ldap_get_option($ldap_connection, LDAP_OPT_DIAGNOSTIC_MESSAGE, $detailed_err);
print $detailed_err;
?>
</pre>
</div> </div>
<?php <?php
}
render_footer(); render_footer();
exit(0); exit(0);
} }
} }
} }
$errors="";
if ($invalid_cn) { $errors.="<li>The Common Name is required</li>\n"; }
if ($invalid_account_identifier) { $errors.="<li>The account identifier (" . $attribute_map[$LDAP['account_attribute']]['label'] . ") is invalid.</li>\n"; }
if ($weak_password) { $errors.="<li>The password is too weak</li>\n"; }
if ($invalid_password) { $errors.="<li>The password contained invalid characters</li>\n"; }
if ($invalid_email) { $errors.="<li>The email address is invalid</li>\n"; }
if ($mismatched_passwords) { $errors.="<li>The passwords are mismatched</li>\n"; }
if ($invalid_username) { $errors.="<li>The username is invalid</li>\n"; }
if ($weak_password) { ?> if ($errors != "") { ?>
<div class="alert alert-warning"> <div class="alert alert-warning">
<p class="text-center">The password is too weak.</p> <p class="text-align: center">
There were issues creating the account:
<ul>
<?php print $errors; ?>
</ul>
</p>
</div> </div>
<?php } <?php
}
if ($invalid_password) { ?> render_js_username_check();
<div class="alert alert-warning"> render_js_username_generator('givenname','sn','uid','uid_div');
<p class="text-center">The password contained invalid characters.</p> render_js_cn_generator('givenname','sn','cn','cn_div');
</div> render_js_email_generator('uid','mail');
<?php }
if ($invalid_email) { ?>
<div class="alert alert-warning">
<p class="text-center">The email address is invalid.</p>
</div>
<?php }
if ($mismatched_passwords) { ?>
<div class="alert alert-warning">
<p class="text-center">The passwords are mismatched.</p>
</div>
<?php }
if ($invalid_username) { ?>
<div class="alert alert-warning">
<p class="text-center">The username is invalid.</p>
</div>
<?php }
render_js_username_generator('first_name','last_name','username','username_div');
render_js_email_generator('username','email');
?> ?>
<script src="//cdnjs.cloudflare.com/ajax/libs/zxcvbn/1.0/zxcvbn.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/zxcvbn/1.0/zxcvbn.min.js"></script>
@ -227,19 +254,18 @@ render_js_email_generator('username','email');
</script> </script>
<script> <script>
function check_email_validity(email) { function check_email_validity(mail) {
var check_regex = <?php print $JS_EMAIL_REGEX; ?> var check_regex = <?php print $JS_EMAIL_REGEX; ?>
if (! check_regex.test(email) ) { if (! check_regex.test(mail) ) {
document.getElementById("email_div").classList.add("has-error"); document.getElementById("mail_div").classList.add("has-error");
<?php if ($EMAIL_SENDING_ENABLED == TRUE) { ?>document.getElementById("send_email_checkbox").disabled = true;<?php } ?> <?php if ($EMAIL_SENDING_ENABLED == TRUE) { ?>document.getElementById("send_email_checkbox").disabled = true;<?php } ?>
} }
else { else {
document.getElementById("email_div").classList.remove("has-error"); document.getElementById("mail_div").classList.remove("has-error");
<?php if ($EMAIL_SENDING_ENABLED == TRUE) { ?>document.getElementById("send_email_checkbox").disabled = false;<?php } ?> <?php if ($EMAIL_SENDING_ENABLED == TRUE) { ?>document.getElementById("send_email_checkbox").disabled = false;<?php } ?>
} }
@ -260,33 +286,24 @@ render_js_email_generator('username','email');
<input type="hidden" name="create_account"> <input type="hidden" name="create_account">
<input type="hidden" id="pass_score" value="0" name="pass_score"> <input type="hidden" id="pass_score" value="0" name="pass_score">
<div class="form-group">
<label for="first_name" class="col-sm-3 control-label">First name</label>
<div class="col-sm-6">
<input tabindex="1" type="text" class="form-control" id="first_name" name="first_name" <?php if (isset($first_name)){ print " value='$first_name'"; } ?> onkeyup="update_username(); update_email(); check_email_validity(document.getElementById('email').value)">
</div>
</div>
<div class="form-group"> <?php
<label for="last_name" class="col-sm-3 control-label">Last name</label>
<div class="col-sm-6">
<input tabindex="3" type="text" class="form-control" id="last_name" name="last_name" <?php if (isset($last_name)){ print " value='$last_name'"; } ?> onkeyup="update_username(); update_email(); check_email_validity(document.getElementById('email').value)">
</div>
</div>
<div class="form-group" id="username_div"> foreach ($attribute_map as $attribute => $attr_r) {
<label for="username" class="col-sm-3 control-label">Username</label> $label = $attr_r['label'];
$onkeyup = $attr_r['onkeyup'];
if ($attribute == $LDAP['account_attribute']) { $label = "<strong>$label</strong><sup>&ast;</sup>"; }
?>
<div class="form-group" id="<?php print $attribute; ?>_div">
<label for="<?php print $attribute; ?>" class="col-sm-3 control-label"><?php print $label; ?></label>
<div class="col-sm-6"> <div class="col-sm-6">
<input tabindex="3" type="text" class="form-control" id="username" name="username" <?php if (isset($username)){ print " value='$username'"; } ?> onkeyup="check_entity_name_validity(document.getElementById('username').value,'username_div'); update_email(); check_email_validity(document.getElementById('email').value)"> <input type="text" class="form-control" id="<?php print $attribute; ?>" name="<?php print $attribute; ?>" value="<?php if (isset($$attribute)) { print $$attribute; } ?>" <?php
</div> if (isset($onkeyup)) { print "onkeyup=\"$onkeyup;\""; } ?>>
</div>
<div class="form-group" id="email_div">
<label for="username" class="col-sm-3 control-label">Email</label>
<div class="col-sm-6">
<input tabindex="4" type="text" class="form-control" id="email" name="email" <?php if (isset($email)){ print " value='$email'"; } ?> onkeyup="auto_email_update = false; check_email_validity(document.getElementById('email').value)">
</div> </div>
</div> </div>
<?php
}
?>
<div class="form-group" id="password_div"> <div class="form-group" id="password_div">
<label for="password" class="col-sm-3 control-label">Password</label> <label for="password" class="col-sm-3 control-label">Password</label>
@ -324,6 +341,8 @@ render_js_email_generator('username','email');
<div id="StrengthProgressBar" class="progress-bar"></div> <div id="StrengthProgressBar" class="progress-bar"></div>
</div> </div>
<div><sup>&ast;</sup>The account identifier</div>
</div> </div>
</div> </div>

View File

@ -27,7 +27,7 @@ else {
$group_cn = urldecode($group_cn); $group_cn = urldecode($group_cn);
} }
if (!preg_match("/$USERNAME_REGEX/",$group_cn)) { if ($ENFORCE_SAFE_SYSTEM_NAMES == TRUE and !preg_match("/$POSIX_REGEX/",$group_cn)) {
?> ?>
<div class="alert alert-danger"> <div class="alert alert-danger">
<p class="text-center">The group name is invalid.</p> <p class="text-center">The group name is invalid.</p>
@ -62,11 +62,15 @@ if (isset($_POST["update_members"])) {
foreach ($_POST as $index => $member) { foreach ($_POST as $index => $member) {
if (is_numeric($index) and preg_match("/$USERNAME_REGEX/",$member)) { if (is_numeric($index)) {
array_push($updated_membership,$member); array_push($updated_membership,$member);
} }
} }
if ($group_cn == $LDAP['admins_group'] and !array_search($USER_ID, $updated_membership)){
array_push($updated_membership,$USER_ID);
}
$members_to_del = array_diff($current_members,$updated_membership); $members_to_del = array_diff($current_members,$updated_membership);
$members_to_add = array_diff($updated_membership,$current_members); $members_to_add = array_diff($updated_membership,$current_members);
@ -88,7 +92,7 @@ if (isset($_POST["update_members"])) {
</script> </script>
<div class="alert alert-success" role="alert"> <div class="alert alert-success" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button>
<strong>Success!</strong> The group has been updated. <p class="text-center">The group has been updated.</p>
</div> </div>
<?php <?php
@ -207,8 +211,8 @@ ldap_close($ldap_connection);
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading clearfix"> <div class="panel-heading clearfix">
<h3 class="panel-title pull-left" style="padding-top: 7.5px;"><?php print $group_cn; ?></h3> <h3 class="panel-title pull-left" style="padding-top: 7.5px;"><?php print $group_cn; ?><?php if ($group_cn == $LDAP["admins_group"]) { print " <sup>(admin group)</sup>" ; } ?></h3>
<button class="btn btn-warning pull-right" onclick="show_delete_group_button();">Delete group</button> <button class="btn btn-warning pull-right" onclick="show_delete_group_button();" <?php if ($group_cn == $LDAP["admins_group"]) { print "disabled"; } ?>>Delete group</button>
<form action="/<?php print $THIS_MODULE_PATH; ?>/groups.php" method="post"><input type="hidden" name="delete_group" value="<?php print $group_cn; ?>"><button class="btn btn-danger pull-right invisible" id="delete_group">Confirm deletion</button></form> <form action="/<?php print $THIS_MODULE_PATH; ?>/groups.php" method="post"><input type="hidden" name="delete_group" value="<?php print $group_cn; ?>"><button class="btn btn-danger pull-right invisible" id="delete_group">Confirm deletion</button></form>
</div> </div>
<ul class="list-group"> <ul class="list-group">
@ -237,8 +241,13 @@ ldap_close($ldap_connection);
<ul class="list-group" id="membership_list"> <ul class="list-group" id="membership_list">
<?php <?php
foreach ($group_members as $member) { foreach ($group_members as $member) {
if ($group_cn == $LDAP['admins_group'] and $member == $USER_ID) {
print "<div class='list-group-item' style='opacity: 0.5; pointer-events:none;'>$member</div>\n";
}
else {
print "<li class='list-group-item'>$member</li>\n"; print "<li class='list-group-item'>$member</li>\n";
} }
}
?> ?>
</ul> </ul>
</div> </div>

View File

@ -14,72 +14,60 @@ $invalid_password = FALSE;
$mismatched_passwords = FALSE; $mismatched_passwords = FALSE;
$invalid_username = FALSE; $invalid_username = FALSE;
$weak_password = FALSE; $weak_password = FALSE;
$to_update = array();
if ($SMTP['host'] != "") { $can_send_email = TRUE; } else { $can_send_email = FALSE; } if ($SMTP['host'] != "") { $can_send_email = TRUE; } else { $can_send_email = FALSE; }
$attribute_map = array( "givenname" => "First name", $LDAP['default_attribute_map']["uidnumber"] = array("label" => "UID");
"sn" => "Last name", $LDAP['default_attribute_map']["gidnumber"] = array("label" => "GID");
"uidnumber" => "UID", $LDAP['default_attribute_map']["loginshell"] = array("label" => "Login shell");
"gidnumber" => "GID", $LDAP['default_attribute_map']["homedirectory"] = array("label" => "Home directory");
"loginshell" => "Login shell", $LDAP['default_attribute_map']["mail"] = array("label" => "Email", "onkeyup" => "check_if_we_should_enable_sending_email();");
"homedirectory" => "Home directory",
"mail" => "Email"
);
$attribute_map = ldap_complete_account_attribute_array();
$ldap_connection = open_ldap_connection(); if (!isset($_POST['account_identifier']) and !isset($_GET['account_identifier'])) {
if (!isset($_POST['username']) and !isset($_GET['username'])) {
?> ?>
<div class="alert alert-danger"> <div class="alert alert-danger">
<p class="text-center">The username is missing.</p> <p class="text-center">The account identifier is missing.</p>
</div> </div>
<?php <?php
render_footer(); render_footer();
exit(0); exit(0);
} }
else { else {
$username = (isset($_POST['username']) ? $_POST['username'] : $_GET['username']); $account_identifier = (isset($_POST['account_identifier']) ? $_POST['account_identifier'] : $_GET['account_identifier']);
$username = urldecode($username); $account_identifier = urldecode($account_identifier);
} }
if (!preg_match("/$USERNAME_REGEX/",$username)) { $ldap_connection = open_ldap_connection();
?> $ldap_search_query="(${LDAP['account_attribute']}=". ldap_escape($account_identifier, "", LDAP_ESCAPE_FILTER) . ")";
<div class="alert alert-danger"> $ldap_search = ldap_search( $ldap_connection, $LDAP['user_dn'], $ldap_search_query);
<p class="text-center">The username <b><?php print "$username"; ?></b> is invalid.</p>
</div>
<?php
render_footer();
exit(0);
}
$ldap_search_query="(${LDAP['account_attribute']}=". ldap_escape($username, "", LDAP_ESCAPE_FILTER) . ")";
$ldap_search = ldap_search( $ldap_connection, $LDAP['base_dn'], $ldap_search_query);
if ($ldap_search) { if ($ldap_search) {
$user = ldap_get_entries($ldap_connection, $ldap_search); $user = ldap_get_entries($ldap_connection, $ldap_search);
foreach ($attribute_map as $attribute => $attr_r) {
################################################ $$attribute = $user[0][$attribute][0];
### Check for updates if (isset($_POST['update_account']) and isset($_POST[$attribute]) and $_POST[$attribute] != $$attribute) {
$$attribute = filter_var($_POST[$attribute], FILTER_SANITIZE_STRING);
$to_update[$attribute] = $$attribute;
}
elseif (isset($attr_r['default'])) {
$$attribute = $attr_r['default'];
}
}
$dn = $user[0]['dn'];
### Update values
if (isset($_POST['update_account'])) { if (isset($_POST['update_account'])) {
$to_update = array();
foreach ($attribute_map as $key => $value) {
if ($user[0][$key][0] != $_POST[$key]) {
$to_update[$key] = $_POST[$key];
$user[0][$key][0] = $_POST[$key];
}
}
if (isset($_POST['password']) and $_POST['password'] != "") { if (isset($_POST['password']) and $_POST['password'] != "") {
$password = $_POST['password']; $password = $_POST['password'];
@ -87,7 +75,7 @@ if ($ldap_search) {
if ((!is_numeric($_POST['pass_score']) or $_POST['pass_score'] < 3) and $ACCEPT_WEAK_PASSWORDS != TRUE) { $weak_password = TRUE; } if ((!is_numeric($_POST['pass_score']) or $_POST['pass_score'] < 3) and $ACCEPT_WEAK_PASSWORDS != TRUE) { $weak_password = TRUE; }
if (preg_match("/\"|'/",$password)) { $invalid_password = TRUE; } if (preg_match("/\"|'/",$password)) { $invalid_password = TRUE; }
if ($_POST['password'] != $_POST['password_match']) { $mismatched_passwords = TRUE; } if ($_POST['password'] != $_POST['password_match']) { $mismatched_passwords = TRUE; }
if (!preg_match("/$USERNAME_REGEX/",$username)) { $invalid_username = TRUE; } if ($ENFORCE_SAFE_SYSTEM_NAMES == TRUE and !preg_match("/$USERNAME_REGEX/",$account_identifier)) { $invalid_username = TRUE; }
if ( !$mismatched_passwords if ( !$mismatched_passwords
and !$weak_password and !$weak_password
@ -97,32 +85,43 @@ if ($ldap_search) {
} }
} }
if (isset($_POST['send_email']) and isset($user[0]['mail'][0]) and $can_send_email == TRUE) { if (array_key_exists($LDAP['account_attribute'], $to_update)) {
$user_email = $user[0]['mail'][0]; $new_rdn = "${LDAP['account_attribute']}=${to_update[$LDAP['account_attribute']]}";
$first_name = $user[0]['givenname'][0]; $renamed_entry = ldap_rename($ldap_connection, $dn, $new_rdn, $LDAP['user_dn'], true);
$last_name = $user[0]['sn'][0]; if ($renamed_entry) {
$dn = "${new_rdn},${LDAP['user_dn']}";
$account_identifier = $to_update[$LDAP['account_attribute']];
}
else {
ldap_get_option($ldap_connection, LDAP_OPT_DIAGNOSTIC_MESSAGE, $detailed_err);
error_log("$log_prefix Failed to rename the DN for ${account_identifier}: " . ldap_error($ldap_connection) . " -- " . $detailed_err,0);
}
} }
$updated_account = ldap_mod_replace($ldap_connection, $user[0]['dn'] , $to_update); $updated_account = @ ldap_mod_replace($ldap_connection, $dn, $to_update);
if (!$updated_account) {
ldap_get_option($ldap_connection, LDAP_OPT_DIAGNOSTIC_MESSAGE, $detailed_err);
error_log("$log_prefix Failed to modify account details for ${account_identifier}: " . ldap_error($ldap_connection) . " -- " . $detailed_err,0);
}
$sent_email_message=""; $sent_email_message="";
if ($updated_account and isset($user_email)) { if ($updated_account and isset($mail) and $can_send_email == TRUE and isset($_POST['send_email'])) {
$mail_subject = "Your $ORGANISATION_NAME password has been reset."; $mail_subject = "Your $ORGANISATION_NAME password has been reset.";
$mail_body = <<<EoT $mail_body = <<<EoT
Your password for $ORGANISATION_NAME has been reset. Your new credentials are: Your password for $ORGANISATION_NAME has been reset. Your new credentials are:
Username: $username Username: $account_identifier
Password: $password Password: $password
You should change your password as soon as possible. Go to ${SITE_PROTOCOL}${SERVER_HOSTNAME}/change_password and log in using your new credentials. This will take you to a page where you can change your password. You should change your password as soon as possible. Go to ${SITE_PROTOCOL}${SERVER_HOSTNAME}/change_password and log in using your new credentials. This will take you to a page where you can change your password.
EoT; EoT;
include_once "mail_functions.inc.php"; include_once "mail_functions.inc.php";
$sent_email = send_email($user_email,"$first_name $last_name",$mail_subject,$mail_body); $sent_email = send_email($mail,"$givenname $sn",$mail_subject,$mail_body);
if ($sent_email) { if ($sent_email) {
$sent_email_message .= " An email sent to $user_email."; $sent_email_message .= " An email sent to $mail.";
} }
else { else {
$sent_email_message .= " Unfortunately the email wasn't sent; check the logs for more information."; $sent_email_message .= " Unfortunately the email wasn't sent; check the logs for more information.";
@ -138,7 +137,7 @@ EoT;
</script> </script>
<div class="alert alert-success" role="alert"> <div class="alert alert-success" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button>
<strong>Success!</strong> The account has been updated.<?php print $sent_email_message; ?> <p class="text-center">The account has been updated.<?php print $sent_email_message; ?></p>
</div> </div>
<?php <?php
} }
@ -151,7 +150,7 @@ EoT;
</script> </script>
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button>
<strong>Error!</strong> There was a problem updating the account. Check the logs for more information. <p class="text-center">There was a problem updating the account. Check the logs for more information.</p>
</div> </div>
<?php <?php
} }
@ -182,11 +181,10 @@ EoT;
$all_groups = ldap_get_group_list($ldap_connection); $all_groups = ldap_get_group_list($ldap_connection);
$currently_member_of = ldap_user_group_membership($ldap_connection,$username); $currently_member_of = ldap_user_group_membership($ldap_connection,$account_identifier);
$not_member_of = array_diff($all_groups,$currently_member_of); $not_member_of = array_diff($all_groups,$currently_member_of);
######### Add/remove from groups ######### Add/remove from groups
if (isset($_POST["update_member_of"])) { if (isset($_POST["update_member_of"])) {
@ -194,19 +192,23 @@ EoT;
$updated_group_membership = array(); $updated_group_membership = array();
foreach ($_POST as $index => $group) { foreach ($_POST as $index => $group) {
if (is_numeric($index) and preg_match("/$USERNAME_REGEX/",$group)) { if (is_numeric($index)) {
array_push($updated_group_membership,$group); array_push($updated_group_membership,$group);
} }
} }
if ($USER_ID == $account_identifier and !array_search($USER_ID, $updated_group_membership)){
array_push($updated_group_membership,$LDAP["admins_group"]);
}
$groups_to_add = array_diff($updated_group_membership,$currently_member_of); $groups_to_add = array_diff($updated_group_membership,$currently_member_of);
$groups_to_del = array_diff($currently_member_of,$updated_group_membership); $groups_to_del = array_diff($currently_member_of,$updated_group_membership);
foreach ($groups_to_del as $this_group) { foreach ($groups_to_del as $this_group) {
ldap_delete_member_from_group($ldap_connection,$this_group,$username); ldap_delete_member_from_group($ldap_connection,$this_group,$account_identifier);
} }
foreach ($groups_to_add as $this_group) { foreach ($groups_to_add as $this_group) {
ldap_add_member_to_group($ldap_connection,$this_group,$username); ldap_add_member_to_group($ldap_connection,$this_group,$account_identifier);
} }
$not_member_of = array_diff($all_groups,$updated_group_membership); $not_member_of = array_diff($all_groups,$updated_group_membership);
@ -220,7 +222,7 @@ EoT;
</script> </script>
<div class="alert alert-success" role="alert"> <div class="alert alert-success" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="TRUE">&times;</span></button>
<strong>Success!</strong> The group membership has been updated. <p class="text-center">The group membership has been updated.</p>
</div> </div>
<?php <?php
@ -230,9 +232,6 @@ EoT;
$member_of = $currently_member_of; $member_of = $currently_member_of;
} }
$account_name = $user[0]['uid'][0];
$full_dn = $user[0]['dn'];
################ ################
@ -376,35 +375,37 @@ $full_dn = $user[0]['dn'];
</script> </script>
<div class="container"> <div class="container">
<div class="col-sm-7"> <div class="col-sm-8 col-md-offset-2">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading clearfix"> <div class="panel-heading clearfix">
<span class="panel-title pull-left"><h3><?php print $account_name; ?></h3></span> <span class="panel-title pull-left"><h3><?php print $account_identifier; ?></h3></span>
<button class="btn btn-warning pull-right align-self-end" style="margin-top: auto;" onclick="show_delete_user_button();">Delete account</button> <button class="btn btn-warning pull-right align-self-end" style="margin-top: auto;" onclick="show_delete_user_button();" <?php if ($account_identifier == $USER_ID) { print "disabled"; }?>>Delete account</button>
<form action="/<?php print $THIS_MODULE_PATH; ?>/index.php" method="post"><input type="hidden" name="delete_user" value="<?php print urlencode($username); ?>"><button class="btn btn-danger pull-right invisible" id="delete_user">Confirm deletion</button></form> <form action="/<?php print $THIS_MODULE_PATH; ?>/index.php" method="post"><input type="hidden" name="delete_user" value="<?php print urlencode($account_identifier); ?>"><button class="btn btn-danger pull-right invisible" id="delete_user">Confirm deletion</button></form>
</div> </div>
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item"><?php print $full_dn; ?></li> <li class="list-group-item"><?php print $dn; ?></li>
</li> </li>
<div class="panel-body"> <div class="panel-body">
<form class="form-horizontal" action="" method="post"> <form class="form-horizontal" action="" method="post">
<input type="hidden" name="update_account"> <input type="hidden" name="update_account">
<input type="hidden" id="pass_score" value="0" name="pass_score"> <input type="hidden" id="pass_score" value="0" name="pass_score">
<input type="hidden" name="username" value="<?php print $username; ?>"> <input type="hidden" name="account_identifier" value="<?php print $account_identifier; ?>">
<?php <?php
foreach ($attribute_map as $key => $value) { foreach ($attribute_map as $attribute => $attr_r) {
$label = $attr_r['label'];
$onkeyup = $attr_r['onkeyup'];
if ($attribute == $LDAP['account_attribute']) { $label = "<strong>$label</strong><sup>&ast;</sup>"; }
?> ?>
<div class="form-group" id="<?php print $key; ?>_div"> <div class="form-group" id="<?php print $attribute; ?>_div">
<label for="<?php print $key; ?>" class="col-sm-3 control-label"><?php print $value; ?></label> <label for="<?php print $attribute; ?>" class="col-sm-3 control-label"><?php print $label; ?></label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="text" class="form-control" id="<?php print $key; ?>" name="<?php print $key; ?>" value="<?php print $user[0][$key][0]; ?>" <?php <input type="text" class="form-control" id="<?php print $attribute; ?>" name="<?php print $attribute; ?>" value="<?php if (isset($$attribute)) { print $$attribute; } ?>" <?php
if ($key == "mail") { print 'onkeyup="check_if_we_should_enable_sending_email();"'; } if (isset($onkeyup)) { print "onkeyup=\"$onkeyup;\""; } ?>>
?>>
</div> </div>
</div> </div>
<?php <?php
@ -448,6 +449,8 @@ $full_dn = $user[0]['dn'];
<div id="StrengthProgressBar" class="progress-bar"></div> <div id="StrengthProgressBar" class="progress-bar"></div>
</div> </div>
<div><p align='center'><sup>&ast;</sup>The account identifier. Changing this will change the full <strong>DN</strong>.</p></div>
</div> </div>
</div> </div>
@ -484,8 +487,13 @@ $full_dn = $user[0]['dn'];
<ul class="list-group" id="member_of_list"> <ul class="list-group" id="member_of_list">
<?php <?php
foreach ($member_of as $group) { foreach ($member_of as $group) {
if ($group == $LDAP["admins_group"] and $USER_ID == $account_identifier) {
print "<div class='list-group-item' style='opacity: 0.5; pointer-events:none;'>${group}</div>\n";
}
else {
print "<li class='list-group-item'>$group</li>\n"; print "<li class='list-group-item'>$group</li>\n";
} }
}
?> ?>
</ul> </ul>
</div> </div>
@ -500,7 +508,7 @@ $full_dn = $user[0]['dn'];
</button> </button>
<form id="update_with_groups" action="<?php print $CURRENT_PAGE; ?>" method="post"> <form id="update_with_groups" action="<?php print $CURRENT_PAGE; ?>" method="post">
<input type="hidden" name="update_member_of"> <input type="hidden" name="update_member_of">
<input type="hidden" name="username" value="<?php print $username; ?>"> <input type="hidden" name="account_identifier" value="<?php print $account_identifier; ?>">
</form> </form>
<button id="submit_members" class="btn btn-info" disabled type="submit" onclick="update_form_with_groups()">Save</button> <button id="submit_members" class="btn btn-info" disabled type="submit" onclick="update_form_with_groups()">Save</button>
</div> </div>

View File

@ -1,26 +0,0 @@
<?php
set_include_path( ".:" . __DIR__ . "/../includes/");
include_once "web_functions.inc.php";
include_once "ldap_functions.inc.php";
include_once "module_functions.inc.php";
render_header("LDAP manager");
render_submenu();
$ldap_connection = open_ldap_connection();
print "<pre>";
print $schema_base_dn . "\n";
print_r($gom_results);
print "\n\n\n\n";
print_r($gom_r_search);
print "</pre>";
render_footer();
?>

View File

@ -2,6 +2,16 @@
$log_prefix = ""; $log_prefix = "";
#Fixed
$LDAP['account_objectclasses'] = array( 'person', 'inetOrgPerson', 'posixAccount' );
$LDAP['default_attribute_map'] = array( "givenname" => array("label" => "First name", "onkeyup" => "update_username(); update_email(); update_cn(); check_email_validity(document.getElementById('mail').value)"),
"sn" => array("label" => "Last name", "onkeyup" => "update_username(); update_email(); update_cn(); check_email_validity(document.getElementById('mail').value)"),
"uid" => array("label" => "System username", "onkeyup" => "check_entity_name_validity(document.getElementById('uid').value,'uid_div'); update_email(); check_email_validity(document.getElementById('mail').value)"),
"cn" => array("label" => "Common Name", "onkeyup" => "auto_cn_update = false;"),
"mail" => array("label" => "Email", "onkeyup" => "auto_email_update = false; check_email_validity(document.getElementById('mail').value)")
);
#Mandatory #Mandatory
$LDAP['uri'] = getenv('LDAP_URI'); $LDAP['uri'] = getenv('LDAP_URI');
@ -9,19 +19,22 @@
$LDAP['admins_group'] = getenv('LDAP_ADMINS_GROUP'); $LDAP['admins_group'] = getenv('LDAP_ADMINS_GROUP');
$LDAP['admin_bind_dn'] = getenv('LDAP_ADMIN_BIND_DN'); $LDAP['admin_bind_dn'] = getenv('LDAP_ADMIN_BIND_DN');
$LDAP['admin_bind_pwd'] = getenv('LDAP_ADMIN_BIND_PWD'); $LDAP['admin_bind_pwd'] = getenv('LDAP_ADMIN_BIND_PWD');
$LDAP['connection_type'] = "plain";
#Optional #Optional
$LDAP['account_attribute'] = (getenv('LDAP_ACCOUNT_ATTRIBUTE') ? getenv('LDAP_ACCOUNT_ATTRIBUTE') : 'uid');
$LDAP['group_ou'] = (getenv('LDAP_GROUP_OU') ? getenv('LDAP_GROUP_OU') : 'groups'); $LDAP['group_ou'] = (getenv('LDAP_GROUP_OU') ? getenv('LDAP_GROUP_OU') : 'groups');
$LDAP['user_ou'] = (getenv('LDAP_USER_OU') ? getenv('LDAP_USER_OU') : 'people'); $LDAP['user_ou'] = (getenv('LDAP_USER_OU') ? getenv('LDAP_USER_OU') : 'people');
$LDAP['forced_rfc2307bis'] = ((strcasecmp(getenv('FORCE_RFC2307BIS'),'TRUE') == 0) ? TRUE : FALSE); $LDAP['forced_rfc2307bis'] = ((strcasecmp(getenv('FORCE_RFC2307BIS'),'TRUE') == 0) ? TRUE : FALSE);
if (getenv('LDAP_ACCOUNT_ADDITIONAL_OBJECTCLASSES')) { $LDAP['account_additional_objectclasses'] = strtolower(getenv('LDAP_ACCOUNT_ADDITIONAL_OBJECTCLASSES')); }
if (getenv('LDAP_ACCOUNT_ADDITIONAL_ATTRIBUTES')) { $LDAP['account_additional_attributes'] = getenv('LDAP_ACCOUNT_ADDITIONAL_ATTRIBUTES'); }
if (getenv('LDAP_GROUP_MEMBERSHIP_ATTRIBUTE')) { $LDAP['group_membership_attribute'] = getenv('LDAP_GROUP_MEMBERSHIP_ATTRIBUTE'); } if (getenv('LDAP_GROUP_MEMBERSHIP_ATTRIBUTE')) { $LDAP['group_membership_attribute'] = getenv('LDAP_GROUP_MEMBERSHIP_ATTRIBUTE'); }
if (getenv('LDAP_GROUP_MEMBERSHIP_USES_UID') and strtoupper(getenv('LDAP_GROUP_MEMBERSHIP_USES_UID')) == TRUE ) { $LDAP['group_membership_uses_uid'] = TRUE; } if (getenv('LDAP_GROUP_MEMBERSHIP_USES_UID') and strtoupper(getenv('LDAP_GROUP_MEMBERSHIP_USES_UID')) == TRUE ) { $LDAP['group_membership_uses_uid'] = TRUE; }
$LDAP['account_attribute'] = 'uid';
$LDAP['require_starttls'] = ((strcasecmp(getenv('LDAP_REQUIRE_STARTTLS'),'TRUE') == 0) ? TRUE : FALSE); $LDAP['require_starttls'] = ((strcasecmp(getenv('LDAP_REQUIRE_STARTTLS'),'TRUE') == 0) ? TRUE : FALSE);
$LDAP['ignore_cert_errors'] = ((strcasecmp(getenv('LDAP_IGNORE_CERT_ERRORS'),'TRUE') == 0) ? TRUE : FALSE); $LDAP['ignore_cert_errors'] = ((strcasecmp(getenv('LDAP_IGNORE_CERT_ERRORS'),'TRUE') == 0) ? TRUE : FALSE);
$LDAP['rfc2307bis_check_run'] = FALSE; $LDAP['rfc2307bis_check_run'] = FALSE;
@ -33,8 +46,9 @@
$SITE_NAME = (getenv('SITE_NAME') ? getenv('SITE_NAME') : "$ORGANISATION_NAME user manager"); $SITE_NAME = (getenv('SITE_NAME') ? getenv('SITE_NAME') : "$ORGANISATION_NAME user manager");
$SERVER_HOSTNAME = (getenv('SERVER_HOSTNAME') ? getenv('SERVER_HOSTNAME') : "ldapusermanager.org"); $SERVER_HOSTNAME = (getenv('SERVER_HOSTNAME') ? getenv('SERVER_HOSTNAME') : "ldapusermanager.org");
$USERNAME_FORMAT = (getenv('USERNAME_FORMAT') ? getenv('USERNAME_FORMAT') : '{first_name}-{last_name}'); $ENFORCE_SAFE_SYSTEM_NAMES = ((strcasecmp(getenv('ENFORCE_SAFE_SYSTEM_NAMES'),'FALSE') == 0) ? FALSE : TRUE);
$USERNAME_REGEX = (getenv('USERNAME_REGEX') ? getenv('USERNAME_REGEX') : '^[a-z][a-zA-Z0-9\._-]{3,32}$'); $POSIX_USERNAME_FORMAT = (getenv('USERNAME_FORMAT') ? getenv('USERNAME_FORMAT') : '{first_name}-{last_name}');
$POSIX_REGEX = (getenv('USERNAME_REGEX') ? getenv('USERNAME_REGEX') : '^[a-z][a-zA-Z0-9\._-]{3,32}$');
#We'll use the username regex for groups too. #We'll use the username regex for groups too.
if (getenv('PASSWORD_HASH')) { $PASSWORD_HASH = strtoupper(getenv('PASSWORD_HASH')); } if (getenv('PASSWORD_HASH')) { $PASSWORD_HASH = strtoupper(getenv('PASSWORD_HASH')); }
@ -76,7 +90,7 @@
### ###
$ACCOUNT_REQUESTS_ENABLED = ((strcasecmp(getenv('ACCOUNT_REQUESTS_ENABLED'),'TRUE') == 0) ? TRUE : FALSE); $ACCOUNT_REQUESTS_ENABLED = ((strcasecmp(getenv('ACCOUNT_REQUESTS_ENABLED'),'TRUE') == 0) ? TRUE : FALSE);
if (($EMAIL_SENDING_ENABLED == FALSE) && ($ACCOUNT_REQUESTS_ENABLED == TRUE)) { if (($EMAIL_SENDING_ENABLED == FALSE) && ($ACCOUNT_REQUESTS_ENABLED == TRUE)) {
$ACCOUNT_REQUESTS_ENABLED = FALSE; $ACCOUNT_REQUESTS_ENABLED = FALSE;
error_log("$log_prefix Config: ACCOUNT_REQUESTS_ENABLED was set to TRUE but SMTP_HOSTNAME wasn't set, so account requesting has been disabled as we can't send out the request email",0); error_log("$log_prefix Config: ACCOUNT_REQUESTS_ENABLED was set to TRUE but SMTP_HOSTNAME wasn't set, so account requesting has been disabled as we can't send out the request email",0);
} }
@ -108,7 +122,7 @@ if (($EMAIL_SENDING_ENABLED == FALSE) && ($ACCOUNT_REQUESTS_ENABLED == TRUE)) {
} }
if ($errors != "") { if ($errors != "") {
render_header(); render_header("Fatal errors",false);
print $errors; print $errors;
render_footer(); render_footer();
exit(1); exit(1);

View File

@ -1,12 +1,10 @@
<?php <?php
$LDAP_IS_SECURE = FALSE;
################################### ###################################
function open_ldap_connection() { function open_ldap_connection($ldap_bind=TRUE) {
global $log_prefix, $LDAP, $SENT_HEADERS, $LDAP_DEBUG, $LDAP_IS_SECURE, $LDAP_VERBOSE_CONNECTION_LOGS; global $log_prefix, $LDAP, $SENT_HEADERS, $LDAP_DEBUG, $LDAP_VERBOSE_CONNECTION_LOGS;
if ($LDAP['ignore_cert_errors'] == TRUE) { putenv('LDAPTLS_REQCERT=never'); } if ($LDAP['ignore_cert_errors'] == TRUE) { putenv('LDAPTLS_REQCERT=never'); }
$ldap_connection = @ ldap_connect($LDAP['uri']); $ldap_connection = @ ldap_connect($LDAP['uri']);
@ -33,7 +31,7 @@ function open_ldap_connection() {
exit(0); exit(0);
} }
else { else {
if ($SENT_HEADERS == TRUE) { if ($SENT_HEADERS == TRUE and !preg_match('/^ldap:\/\/localhost(:[0-9]+)?$', $LDAP['uri']) and !preg_match('/^ldap:\/\/127\.0\.0\.([0-9]+)(:[0-9]+)$', $LDAP['uri'])) {
print "<div style='position: fixed;bottom: 0px;width: 100%;height: 20px;border-bottom:solid 20px yellow;'>WARNING: Insecure LDAP connection to ${LDAP['uri']}</div>"; print "<div style='position: fixed;bottom: 0px;width: 100%;height: 20px;border-bottom:solid 20px yellow;'>WARNING: Insecure LDAP connection to ${LDAP['uri']}</div>";
} }
ldap_close($ldap_connection); ldap_close($ldap_connection);
@ -45,11 +43,20 @@ function open_ldap_connection() {
if ($LDAP_DEBUG == TRUE) { if ($LDAP_DEBUG == TRUE) {
error_log("$log_prefix Start STARTTLS connection to ${LDAP['uri']}",0); error_log("$log_prefix Start STARTTLS connection to ${LDAP['uri']}",0);
} }
$LDAP_IS_SECURE = TRUE; $LDAP['connection_type'] = "StartTLS";
} }
} }
else {
if ($LDAP_DEBUG == TRUE) {
error_log("$log_prefix Using an LDAPS encrypted connection to ${LDAP['uri']}",0);
}
$LDAP['connection_type'] = 'LDAPS';
}
if ($ldap_bind == TRUE) {
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Attempting to bind to ${LDAP['uri']} as ${LDAP['admin_bind_dn']}",0); }
$bind_result = @ ldap_bind( $ldap_connection, $LDAP['admin_bind_dn'], $LDAP['admin_bind_pwd']); $bind_result = @ ldap_bind( $ldap_connection, $LDAP['admin_bind_dn'], $LDAP['admin_bind_pwd']);
if ($bind_result != TRUE) { if ($bind_result != TRUE) {
@ -64,7 +71,9 @@ function open_ldap_connection() {
} }
elseif ($LDAP_DEBUG == TRUE) { elseif ($LDAP_DEBUG == TRUE) {
error_log("$log_prefix Bound to ${LDAP['uri']} as ${LDAP['admin_bind_dn']}",0); error_log("$log_prefix Bound successfully as ${LDAP['admin_bind_dn']}",0);
}
} }
return $ldap_connection; return $ldap_connection;
@ -82,37 +91,50 @@ function ldap_auth_username($ldap_connection,$username, $password) {
global $log_prefix, $LDAP, $LDAP_DEBUG; global $log_prefix, $LDAP, $LDAP_DEBUG;
$ldap_search_query="${LDAP['account_attribute']}=" . ldap_escape($username, "", LDAP_ESCAPE_FILTER); $ldap_search_query="${LDAP['account_attribute']}=" . ldap_escape($username, "", LDAP_ESCAPE_FILTER);
$ldap_search = @ ldap_search( $ldap_connection, $LDAP['base_dn'], $ldap_search_query ); if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Running LDAP search for: $ldap_search_query"); }
if ($LDAP_DEBUG == TRUE) { "$log_prefix Running LDAP search: $ldap_search_query"; } $ldap_search = @ ldap_search( $ldap_connection, $LDAP['user_dn'], $ldap_search_query );
if (!$ldap_search) { if (!$ldap_search) {
error_log("$log_prefix Couldn't search for ${username}: " . ldap_error($ldap_connection),0); error_log("$log_prefix Couldn't search for $ldap_search_query: " . ldap_error($ldap_connection),0);
return FALSE; return FALSE;
} }
$result = ldap_get_entries($ldap_connection, $ldap_search); $result = @ ldap_get_entries($ldap_connection, $ldap_search);
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix LDAP search returned ${result["count"]} records for $username",0); } if (!$result) {
error_log("$log_prefix Couldn't get LDAP entries for ${username}: " . ldap_error($ldap_connection),0);
return FALSE;
}
if ($LDAP_DEBUG == TRUE) {
error_log("$log_prefix LDAP search returned " . $result["count"] . " records for $ldap_search_query",0);
for ($i=1; $i==$result["count"]; $i++) {
error_log("$log_prefix ". "Entry ${i}: " . $result[$i-1]['dn'], 0);
}
}
if ($result["count"] == 1) { if ($result["count"] == 1) {
$auth_ldap_connection = open_ldap_connection(); $this_dn = $result[0]['dn'];
$can_bind = @ldap_bind( $auth_ldap_connection, $result[0]['dn'], $password); if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Attempting authenticate as $username by binding with ${this_dn} ",0); }
ldap_close($auth_ldap_connection); $auth_ldap_connection = open_ldap_connection(FALSE);
$can_bind = @ ldap_bind( $auth_ldap_connection, $result[0]['dn'], $password);
if ($can_bind) { if ($can_bind) {
preg_match("/{$LDAP['account_attribute']}=(.*?),/",$result[0]['dn'],$dn_match); preg_match("/{$LDAP['account_attribute']}=(.*?),/",$result[0]['dn'],$dn_match);
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Able to bind as ${username}",0); }
ldap_close($auth_ldap_connection);
return $dn_match[1]; return $dn_match[1];
ldap_unbind($auth_ldap_connection);
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Able to bind as $username",0); }
} }
else { else {
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Unable to bind as ${username}: " . ldap_error($ldap_connection),0); } if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Unable to bind as ${username}: " . ldap_error($auth_ldap_connection),0); }
ldap_close($auth_ldap_connection);
return FALSE; return FALSE;
} }
} }
elseif ($result["count"] > 1) {
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix There was more than one entry for ${ldap_search_query} so it wasn't possible to determine which user to log in as."); }
}
} }
@ -289,7 +311,7 @@ function ldap_get_user_list($ldap_connection,$start=0,$entries=NULL,$sort="asc",
$ldap_search = @ ldap_search($ldap_connection, "${LDAP['user_dn']}", $this_filter, $fields); $ldap_search = @ ldap_search($ldap_connection, "${LDAP['user_dn']}", $this_filter, $fields);
$result = @ ldap_get_entries($ldap_connection, $ldap_search); $result = @ ldap_get_entries($ldap_connection, $ldap_search);
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix: LDAP returned ${result['count']} users for ${LDAP['user_dn']} when using this filter: $this_filter",0); } if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix LDAP returned ${result['count']} users for ${LDAP['user_dn']} when using this filter: $this_filter",0); }
$records = array(); $records = array();
foreach ($result as $record) { foreach ($result as $record) {
@ -316,6 +338,29 @@ function ldap_get_user_list($ldap_connection,$start=0,$entries=NULL,$sort="asc",
################################## ##################################
function fetch_id_stored_in_ldap($ldap_connection,$type="uid") {
global $log_prefix, $LDAP, $LDAP_DEBUG;
$filter = "(&(objectclass=device)(cn=last${type}))";
$ldap_search = @ ldap_search($ldap_connection, "${LDAP['base_dn']}", $filter, array('serialNumber'));
$result = ldap_get_entries($ldap_connection, $ldap_search);
$fetched_id = $result[0]['serialnumber'][0];
if (isset($fetched_id) and is_numeric($fetched_id)){
return $fetched_id;
}
else {
return FALSE;
}
}
##################################
function ldap_get_highest_id($ldap_connection,$type="uid") { function ldap_get_highest_id($ldap_connection,$type="uid") {
global $log_prefix, $LDAP, $LDAP_DEBUG, $min_uid, $min_gid; global $log_prefix, $LDAP, $LDAP_DEBUG, $min_uid, $min_gid;
@ -324,30 +369,28 @@ function ldap_get_highest_id($ldap_connection,$type="uid") {
$this_id = $min_uid; $this_id = $min_uid;
$record_base_dn = $LDAP['user_dn']; $record_base_dn = $LDAP['user_dn'];
$record_filter = "(${LDAP['account_attribute']}=*)"; $record_filter = "(${LDAP['account_attribute']}=*)";
$record_attribute = array("uidNumber"); $record_attribute = "uidnumber";
} }
else { else {
$type = "gid"; $type = "gid";
$this_id = $min_gid; $this_id = $min_gid;
$record_base_dn = $LDAP['group_dn']; $record_base_dn = $LDAP['group_dn'];
$record_filter = "(objectClass=posixGroup)"; $record_filter = "(objectClass=posixGroup)";
$record_attribute = array("gidNumber"); $record_attribute = "gidnumber";
} }
$filter = "(&(objectclass=device)(cn=last${type}))"; $fetched_id = fetch_id_stored_in_ldap($ldap_connection,$type);
$ldap_search = ldap_search($ldap_connection, "${LDAP['base_dn']}", $filter, array('serialNumber'));
$result = ldap_get_entries($ldap_connection, $ldap_search);
$fetched_id = $result[0]['serialnumber'][0]; if ($fetched_id != FALSE) {
if (isset($fetched_id) and is_numeric($fetched_id)){ return($fetched_id);
$this_id = $fetched_id;
} }
else { else {
$ldap_search = ldap_search($ldap_connection, $record_base_dn, $record_filter, $record_attribute); error_log("$log_prefix cn=lastGID doesn't exist so the highest $type is determined by searching through all the LDAP records.",0);
$ldap_search = @ ldap_search($ldap_connection, $record_base_dn, $record_filter, array($record_attribute));
$result = ldap_get_entries($ldap_connection, $ldap_search); $result = ldap_get_entries($ldap_connection, $ldap_search);
foreach ($result as $record) { foreach ($result as $record) {
@ -371,7 +414,7 @@ function ldap_get_group_list($ldap_connection,$start=0,$entries=NULL,$sort="asc"
global $log_prefix, $LDAP, $LDAP_DEBUG; global $log_prefix, $LDAP, $LDAP_DEBUG;
$this_filter = "(&(objectclass=*)$filters)"; $this_filter = "(&(objectclass=*)$filters)";
$ldap_search = ldap_search($ldap_connection, "${LDAP['group_dn']}", $this_filter); $ldap_search = @ ldap_search($ldap_connection, "${LDAP['group_dn']}", $this_filter);
$result = @ ldap_get_entries($ldap_connection, $ldap_search); $result = @ ldap_get_entries($ldap_connection, $ldap_search);
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix: LDAP returned ${result['count']} groups for ${LDAP['group_dn']} when using this filter: $this_filter",0); } if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix: LDAP returned ${result['count']} groups for ${LDAP['group_dn']} when using this filter: $this_filter",0); }
@ -446,7 +489,7 @@ function ldap_get_group_members($ldap_connection,$group_name,$start=0,$entries=N
} }
$actual_result_count = count($records); $actual_result_count = count($records);
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix: LDAP returned $actual_result_count members of ${group_name} when using this search: $ldap_search_query and this filter: ${LDAP['group_membership_attribute']}",0); } if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix LDAP returned $actual_result_count members of ${group_name} when using this search: $ldap_search_query and this filter: ${LDAP['group_membership_attribute']}",0); }
if ($actual_result_count > 0) { if ($actual_result_count > 0) {
if ($sort == "asc") { sort($records); } else { rsort($records); } if ($sort == "asc") { sort($records); } else { rsort($records); }
@ -473,7 +516,7 @@ function ldap_is_group_member($ldap_connection,$group_name,$username) {
if ($LDAP['rfc2307bis_check_run'] != TRUE) { $rfc2307bis_available = ldap_detect_rfc2307bis($ldap_connection); } if ($LDAP['rfc2307bis_check_run'] != TRUE) { $rfc2307bis_available = ldap_detect_rfc2307bis($ldap_connection); }
$ldap_search_query = "(cn=" . ldap_escape($group_name, "", LDAP_ESCAPE_FILTER) . ")"; $ldap_search_query = "(cn=" . ldap_escape($group_name, "", LDAP_ESCAPE_FILTER) . ")";
$ldap_search = ldap_search($ldap_connection, "${LDAP['group_dn']}", $ldap_search_query); $ldap_search = @ ldap_search($ldap_connection, "${LDAP['group_dn']}", $ldap_search_query);
$result = ldap_get_entries($ldap_connection, $ldap_search); $result = ldap_get_entries($ldap_connection, $ldap_search);
if ($LDAP['group_membership_uses_uid'] == FALSE) { if ($LDAP['group_membership_uses_uid'] == FALSE) {
@ -503,7 +546,7 @@ function ldap_user_group_membership($ldap_connection,$username) {
} }
$ldap_search_query = "(&(objectClass=posixGroup)(${LDAP['group_membership_attribute']}=${username}))"; $ldap_search_query = "(&(objectClass=posixGroup)(${LDAP['group_membership_attribute']}=${username}))";
$ldap_search = ldap_search($ldap_connection, "${LDAP['group_dn']}", $ldap_search_query, array('cn')); $ldap_search = @ ldap_search($ldap_connection, "${LDAP['group_dn']}", $ldap_search_query, array('cn'));
$result = ldap_get_entries($ldap_connection, $ldap_search); $result = ldap_get_entries($ldap_connection, $ldap_search);
$groups = array(); $groups = array();
@ -562,15 +605,19 @@ function ldap_new_group($ldap_connection,$group_name) {
} }
else { else {
error_log("$log_prefix Added new group $group_name",0); error_log("$log_prefix Added new group $group_name",0);
$this_gid = fetch_id_stored_in_ldap($ldap_connection,"gid");
if ($this_gid != FALSE) {
$update_gid = @ ldap_mod_replace($ldap_connection, "cn=lastGID,${LDAP['base_dn']}", array( 'serialNumber' => $new_gid )); $update_gid = @ ldap_mod_replace($ldap_connection, "cn=lastGID,${LDAP['base_dn']}", array( 'serialNumber' => $new_gid ));
if ($update_gid) { if ($update_gid) {
error_log("$log_prefix Updated cn=lastGID with $new_gid",0); error_log("$log_prefix Updated cn=lastGID with $new_gid",0);
return TRUE;
} }
else { else {
error_log("$log_prefix Failed to update cn=lastGID: " . ldap_error($ldap_connection) ,0); error_log("$log_prefix Unable to update cn=lastGID to $new_gid - this could cause groups to share the same GID.",0);
} }
} }
return TRUE;
}
} }
else { else {
@ -636,13 +683,69 @@ function ldap_get_gid_of_group($ldap_connection,$group_name) {
################################## ##################################
function ldap_new_account($ldap_connection,$first_name,$last_name,$username,$password,$email) { function ldap_complete_account_attribute_array() {
global $LDAP;
$attribute_r = $LDAP['default_attribute_map'];
$additional_attributes_r = array();
if (isset($LDAP['account_additional_attributes'])) {
$user_attribute_r = explode(",", $LDAP['account_additional_attributes']);
foreach ($user_attribute_r as $this_attr) {
$this_r = array();
$kv = explode(":", $this_attr);
$attr_name = strtolower(filter_var($kv[0], FILTER_SANITIZE_STRING));
if (preg_match('/^[a-zA-Z0-9\-]+$/', $attr_name) == 1) {
if (isset($kv[1]) and $kv[1] != "") {
$this_r['label'] = filter_var($kv[1], FILTER_SANITIZE_STRING);
}
else {
$this_r['label'] = $attr_name;
}
if (isset($kv[2]) and $kv[2] != "") {
$this_r['default'] = filter_var($kv[2], FILTER_SANITIZE_STRING);
}
$additional_attributes_r[$attr_name] = $this_r;
}
}
$attribute_r = array_merge($attribute_r, $additional_attributes_r);
}
if (! array_key_exists($LDAP['account_attribute'], $attribute_r)) {
$attribute_r = array_merge($attribute_r, array($LDAP['account_attribute'] => array("label" => "Account UID")));
}
return($attribute_r);
}
##################################
function ldap_new_account($ldap_connection,$account_r) {
global $log_prefix, $LDAP, $LDAP_DEBUG, $DEFAULT_USER_SHELL, $DEFAULT_USER_GROUP; global $log_prefix, $LDAP, $LDAP_DEBUG, $DEFAULT_USER_SHELL, $DEFAULT_USER_GROUP;
if (isset($first_name) and isset($last_name) and isset($username) and isset($password)) { if ( isset($account_r['givenname'])
and isset($account_r['sn'])
and isset($account_r['cn'])
and isset($account_r['uid'])
and isset($account_r[$LDAP['account_attribute']])
and isset($account_r['password'])) {
$ldap_search_query = "(${LDAP['account_attribute']}=" . ldap_escape($username, "", LDAP_ESCAPE_FILTER) . ",${LDAP['user_dn']})"; $account_identifier = $account_r[$LDAP['account_attribute']];
$ldap_search_query = "(${LDAP['account_attribute']}=" . ldap_escape($account_identifier, "", LDAP_ESCAPE_FILTER) . ",${LDAP['user_dn']})";
$ldap_search = @ ldap_search($ldap_connection, "${LDAP['user_dn']}", $ldap_search_query); $ldap_search = @ ldap_search($ldap_connection, "${LDAP['user_dn']}", $ldap_search_query);
$result = @ ldap_get_entries($ldap_connection, $ldap_search); $result = @ ldap_get_entries($ldap_connection, $ldap_search);
@ -654,56 +757,64 @@ function ldap_new_account($ldap_connection,$first_name,$last_name,$username,$pas
$default_gid = ldap_get_gid_of_group($ldap_connection,$DEFAULT_USER_GROUP); $default_gid = ldap_get_gid_of_group($ldap_connection,$DEFAULT_USER_GROUP);
if (!is_numeric($default_gid)) { if (!is_numeric($default_gid)) {
$group_add = ldap_new_group($ldap_connection,$username); $group_add = ldap_new_group($ldap_connection,$account_identifier);
$gid = ldap_get_gid_of_group($ldap_connection,$username); $gid = ldap_get_gid_of_group($ldap_connection,$account_identifier);
$add_to_group = $username; $add_to_group = $account_identifier;
} }
else { else {
$gid = $default_gid; $gid = $default_gid;
$add_to_group = $DEFAULT_USER_GROUP; $add_to_group = $DEFAULT_USER_GROUP;
} }
$hashed_pass = ldap_hashed_password($password); $hashed_pass = ldap_hashed_password($account_r['password']);
$user_info = array( 'objectClass' => array( 'person', 'inetOrgPerson', 'posixAccount' ), $objectclasses = $LDAP['account_objectclasses'];
'uid' => $username, if (isset($LDAP['account_additional_objectclasses']) and $LDAP['account_additional_objectclasses'] != "") {
'givenName' => $first_name, $objectclasses = array_merge($objectclasses, explode(",", $LDAP['account_additional_objectclasses']));
'sn' => $last_name, }
'cn' => "$first_name $last_name",
'displayName' => "$first_name $last_name", $account_attributes = array('objectClass' => $objectclasses,
'displayName' => $account_r['givenname'] . " " . $account_r['sn'],
'uidNumber' => $new_uid, 'uidNumber' => $new_uid,
'gidNumber' => $gid, 'gidNumber' => $gid,
'loginShell' => $DEFAULT_USER_SHELL, 'loginShell' => $DEFAULT_USER_SHELL,
'homeDirectory' => "/home/$username", 'homeDirectory' => "/home/" . $account_r['uid'],
'userPassword' => $hashed_pass, 'userPassword' => $hashed_pass,
'mail' => $email
); );
unset($account_r['password']);
$account_attributes = array_merge($account_attributes, $account_r);
$add_account = @ ldap_add($ldap_connection, $add_account = @ ldap_add($ldap_connection,
"${LDAP['account_attribute']}=$username,${LDAP['user_dn']}", "${LDAP['account_attribute']}=$account_identifier,${LDAP['user_dn']}",
$user_info $account_attributes
); );
if ($add_account) { if ($add_account) {
error_log("$log_prefix Created new account: $username",0); error_log("$log_prefix Created new account: $account_identifier",0);
ldap_add_member_to_group($ldap_connection,$add_to_group,$username); ldap_add_member_to_group($ldap_connection,$add_to_group,$account_identifier);
$this_uid = fetch_id_stored_in_ldap($ldap_connection,"uid");
if ($this_uid != FALSE) {
$update_uid = @ ldap_mod_replace($ldap_connection, "cn=lastUID,${LDAP['base_dn']}", array( 'serialNumber' => $new_uid )); $update_uid = @ ldap_mod_replace($ldap_connection, "cn=lastUID,${LDAP['base_dn']}", array( 'serialNumber' => $new_uid ));
if ($update_uid) { if ($update_uid) {
error_log("$log_prefix Create account; Updated cn=lastUID with $new_uid",0); error_log("$log_prefix Create account; Updated cn=lastUID with $new_uid",0);
}
else {
error_log("$log_prefix Unable to update cn=lastUID to $new_uid - this could cause user accounts to share the same UID.",0);
}
}
return TRUE; return TRUE;
} }
else { else {
error_log("$log_prefix Create account; Failed to update cn=lastUID: " . ldap_error($ldap_connection),0); ldap_get_option($ldap_connection, LDAP_OPT_DIAGNOSTIC_MESSAGE, $detailed_err);
error_log("$log_prefix Create account; couldn't create the account for ${account_identifier}: " . ldap_error($ldap_connection) . " -- " . $detailed_err,0);
} }
} }
else { else {
error_log("$log_prefix Create account; couldn't create the account for ${username}: " . ldap_error($ldap_connection),0); error_log("$log_prefix Create account; Account for ${account_identifier} already exists",0);
}
}
else {
error_log("$log_prefix Create account; Account for $username already exists",0);
} }
} }
@ -711,7 +822,6 @@ function ldap_new_account($ldap_connection,$first_name,$last_name,$username,$pas
error_log("$log_prefix Create account; missing parameters",0); error_log("$log_prefix Create account; missing parameters",0);
} }
return FALSE; return FALSE;
} }
@ -760,11 +870,12 @@ function ldap_add_member_to_group($ldap_connection,$group_name,$username) {
$update = @ ldap_mod_add($ldap_connection,$group_dn,$group_update); $update = @ ldap_mod_add($ldap_connection,$group_dn,$group_update);
if ($update) { if ($update) {
error_log("$log_prefix Added $username to $group_name",0); error_log("$log_prefix Added $username to group '$group_name'",0);
return TRUE; return TRUE;
} }
else { else {
error_log("$log_prefix Couldn't add $username to ${group_name}: " . ldap_error($ldap_connection),0); ldap_get_option($ldap_connection, LDAP_OPT_DIAGNOSTIC_MESSAGE, $detailed_err);
error_log("$log_prefix Couldn't add $username to group '${group_name}': " . ldap_error($ldap_connection) . " -- " . $detailed_err,0);
return FALSE; return FALSE;
} }
@ -775,8 +886,13 @@ function ldap_add_member_to_group($ldap_connection,$group_name,$username) {
function ldap_delete_member_from_group($ldap_connection,$group_name,$username) { function ldap_delete_member_from_group($ldap_connection,$group_name,$username) {
global $log_prefix, $LDAP, $LDAP_DEBUG; global $log_prefix, $LDAP, $LDAP_DEBUG, $USER_ID;
if ($group_name == $LDAP['admins_group'] and $username == $USER_ID) {
error_log("$log_prefix Won't remove ${username} from ${group_name} because you're logged in as ${username} and ${group_name} is the admin group.",0);
return FALSE;
}
else {
if ($LDAP['rfc2307bis_check_run'] != TRUE) { $rfc2307bis_available = ldap_detect_rfc2307bis($ldap_connection); } if ($LDAP['rfc2307bis_check_run'] != TRUE) { $rfc2307bis_available = ldap_detect_rfc2307bis($ldap_connection); }
$group_dn = "cn=" . ldap_escape($group_name, "", LDAP_ESCAPE_FILTER) . ",${LDAP['group_dn']}"; $group_dn = "cn=" . ldap_escape($group_name, "", LDAP_ESCAPE_FILTER) . ",${LDAP['group_dn']}";
@ -796,7 +912,7 @@ function ldap_delete_member_from_group($ldap_connection,$group_name,$username) {
error_log("$log_prefix Couldn't remove $username from ${group_name}: " . ldap_error($ldap_connection),0); error_log("$log_prefix Couldn't remove $username from ${group_name}: " . ldap_error($ldap_connection),0);
return FALSE; return FALSE;
} }
}
} }
@ -809,7 +925,7 @@ function ldap_change_password($ldap_connection,$username,$new_password) {
#Find DN of user #Find DN of user
$ldap_search_query = "${LDAP['account_attribute']}=" . ldap_escape($username, "", LDAP_ESCAPE_FILTER); $ldap_search_query = "${LDAP['account_attribute']}=" . ldap_escape($username, "", LDAP_ESCAPE_FILTER);
$ldap_search = @ ldap_search( $ldap_connection, $LDAP['base_dn'], $ldap_search_query); $ldap_search = @ ldap_search( $ldap_connection, $LDAP['user_dn'], $ldap_search_query);
if ($ldap_search) { if ($ldap_search) {
$result = @ ldap_get_entries($ldap_connection, $ldap_search); $result = @ ldap_get_entries($ldap_connection, $ldap_search);
if ($result["count"] == 1) { if ($result["count"] == 1) {

View File

@ -244,7 +244,7 @@ function render_menu() {
#Render the navigation menu. #Render the navigation menu.
#The menu is dynamically rendered the $MODULES hash #The menu is dynamically rendered the $MODULES hash
global $SITE_NAME, $MODULES, $THIS_MODULE_PATH, $VALIDATED, $IS_ADMIN; global $SITE_NAME, $MODULES, $THIS_MODULE_PATH, $VALIDATED, $IS_ADMIN, $USER_ID;
?> ?>
<nav class="navbar navbar-default"> <nav class="navbar navbar-default">
@ -279,6 +279,9 @@ function render_menu() {
} }
?> ?>
</ul> </ul>
<div style="text-align: right;">
<?php if(isset($USER_ID)) { print $USER_ID; } ?>
</div>
</div> </div>
</nav> </nav>
<?php <?php
@ -361,15 +364,16 @@ function is_valid_email($email) {
function render_js_username_check(){ function render_js_username_check(){
global $USERNAME_REGEX; global $POSIX_REGEX, $ENFORCE_SAFE_SYSTEM_NAMES;
if ($ENFORCE_SAFE_SYSTEM_NAMES == TRUE) {
print <<<EoCheckJS print <<<EoCheckJS
<script> <script>
function check_entity_name_validity(name,div_id) { function check_entity_name_validity(name,div_id) {
var check_regex = /$USERNAME_REGEX/; var check_regex = /$POSIX_REGEX/;
if (! check_regex.test(name) ) { if (! check_regex.test(name) ) {
document.getElementById(div_id).classList.add("has-error"); document.getElementById(div_id).classList.add("has-error");
@ -381,7 +385,12 @@ function render_js_username_check(){
} }
</script> </script>
EoCheckJS; EoCheckJS;
}
else {
print "<script> function check_entity_name_validity(name,div_id) {} </script>";
}
} }
@ -389,9 +398,9 @@ EoCheckJS;
function generate_username($fn,$ln) { function generate_username($fn,$ln) {
global $USERNAME_FORMAT; global $POSIX_USERNAME_FORMAT;
$username = $USERNAME_FORMAT; $username = $POSIX_USERNAME_FORMAT;
$username = str_replace('{first_name}',strtolower($fn), $username); $username = str_replace('{first_name}',strtolower($fn), $username);
$username = str_replace('{first_name_initial}',strtolower($fn[0]), $username); $username = str_replace('{first_name_initial}',strtolower($fn[0]), $username);
$username = str_replace('{last_name}',strtolower($ln), $username); $username = str_replace('{last_name}',strtolower($ln), $username);
@ -408,36 +417,75 @@ function render_js_username_generator($firstname_field_id,$lastname_field_id,$us
#Parameters are the IDs of the input fields and username name div in the account creation form. #Parameters are the IDs of the input fields and username name div in the account creation form.
#The div will be set to warning if the username is invalid. #The div will be set to warning if the username is invalid.
global $USERNAME_FORMAT; global $POSIX_USERNAME_FORMAT, $ENFORCE_SAFE_SYSTEM_NAMES;
render_js_username_check(); $remove_accents="";
if ($ENFORCE_SAFE_SYSTEM_NAMES == TRUE) { $remove_accents = ".normalize('NFD').replace(/[\u0300-\u036f]/g, '')"; }
print <<<EoRenderJS print <<<EoRenderJS
<script>
<script>
function update_username() { function update_username() {
var first_name = document.getElementById('$firstname_field_id').value; var first_name = document.getElementById('$firstname_field_id').value;
var last_name = document.getElementById('$lastname_field_id').value; var last_name = document.getElementById('$lastname_field_id').value;
var template = '$USERNAME_FORMAT'; var template = '$POSIX_USERNAME_FORMAT';
var actual_username = template; var actual_username = template;
actual_username = actual_username.replace('{first_name}', first_name.toLowerCase() ); actual_username = actual_username.replace('{first_name}', first_name.toLowerCase()$remove_accents );
actual_username = actual_username.replace('{first_name_initial}', first_name.charAt(0).toLowerCase() ); actual_username = actual_username.replace('{first_name_initial}', first_name.charAt(0).toLowerCase()$remove_accents );
actual_username = actual_username.replace('{last_name}', last_name.toLowerCase() ); actual_username = actual_username.replace('{last_name}', last_name.toLowerCase()$remove_accents );
actual_username = actual_username.replace('{last_name_initial}', last_name.charAt(0).toLowerCase() ); actual_username = actual_username.replace('{last_name_initial}', last_name.charAt(0).toLowerCase()$remove_accents );
check_entity_name_validity(actual_username,'$username_div_id'); check_entity_name_validity(actual_username,'$username_div_id');
document.getElementById('$username_field_id').value = actual_username; document.getElementById('$username_field_id').value = actual_username;
} }
</script> </script>
EoRenderJS; EoRenderJS;
} }
######################################################
function render_js_cn_generator($firstname_field_id,$lastname_field_id,$cn_field_id,$cn_div_id) {
global $ENFORCE_SAFE_SYSTEM_NAMES;
if ($ENFORCE_SAFE_SYSTEM_NAMES == TRUE) {
$gen_js = "first_name.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '') + last_name.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '')";
}
else {
$gen_js = "first_name + ' ' + last_name";
}
print <<<EoRenderCNJS
<script>
var auto_cn_update = true;
function update_cn() {
if ( auto_cn_update == true ) {
var first_name = document.getElementById('$firstname_field_id').value;
var last_name = document.getElementById('$lastname_field_id').value;
this_cn = $gen_js;
check_entity_name_validity(this_cn,'$cn_div_id');
document.getElementById('$cn_field_id').value = this_cn;
}
}
</script>
EoRenderCNJS;
}
###################################################### ######################################################
@ -456,8 +504,10 @@ function render_js_email_generator($username_field_id,$email_field_id) {
var username = document.getElementById('$username_field_id').value; var username = document.getElementById('$username_field_id').value;
document.getElementById('$email_field_id').value = username + '@' + "$EMAIL_DOMAIN"; document.getElementById('$email_field_id').value = username + '@' + "$EMAIL_DOMAIN";
} }
} }
</script> </script>
EoRenderEmailJS; EoRenderEmailJS;
} }

View File

@ -38,12 +38,12 @@ $ldap_connection = open_ldap_connection();
print "$li_good Connected to ${LDAP['uri']}</li>\n"; print "$li_good Connected to ${LDAP['uri']}</li>\n";
#TLS? #TLS?
if ($LDAP_IS_SECURE == TRUE) { if ($LDAP['connection_type'] != "plain") {
print "$li_good Encrypted connection to ${LDAP['uri']} via STARTTLS</li>\n"; print "$li_good Encrypted connection to ${LDAP['uri']} via ${LDAP['connection_type']}</li>\n";
} }
else { else {
print "$li_warn Unable to connect to ${LDAP['uri']} via STARTTLS. "; print "$li_warn Unable to connect to ${LDAP['uri']} via StartTLS. ";
print "<a href='#' data-toggle='popover' title='STARTTLS' data-content='"; print "<a href='#' data-toggle='popover' title='StartTLS' data-content='";
print "The connection to the LDAP server works, but encrypted communication can&#39;t be enabled."; print "The connection to the LDAP server works, but encrypted communication can&#39;t be enabled.";
print "'>What's this?</a></li>\n"; print "'>What's this?</a></li>\n";
} }

View File

@ -35,7 +35,7 @@ if (isset($_POST['fix_problems'])) {
<?php <?php
if (isset($_POST['setup_group_ou'])) { if (isset($_POST['setup_group_ou'])) {
$ou_add = ldap_add($ldap_connection, $LDAP['group_dn'], array( 'objectClass' => 'organizationalUnit', 'ou' => $LDAP['group_ou'] )); $ou_add = @ ldap_add($ldap_connection, $LDAP['group_dn'], array( 'objectClass' => 'organizationalUnit', 'ou' => $LDAP['group_ou'] ));
if ($ou_add == TRUE) { if ($ou_add == TRUE) {
print "$li_good Created OU <strong>${LDAP['group_dn']}</strong></li>\n"; print "$li_good Created OU <strong>${LDAP['group_dn']}</strong></li>\n";
} }
@ -48,7 +48,7 @@ if (isset($_POST['fix_problems'])) {
if (isset($_POST['setup_user_ou'])) { if (isset($_POST['setup_user_ou'])) {
$ou_add = ldap_add($ldap_connection, $LDAP['user_dn'], array( 'objectClass' => 'organizationalUnit', 'ou' => $LDAP['user_ou'] )); $ou_add = @ ldap_add($ldap_connection, $LDAP['user_dn'], array( 'objectClass' => 'organizationalUnit', 'ou' => $LDAP['user_ou'] ));
if ($ou_add == TRUE) { if ($ou_add == TRUE) {
print "$li_good Created OU <strong>${LDAP['user_dn']}</strong></li>\n"; print "$li_good Created OU <strong>${LDAP['user_dn']}</strong></li>\n";
} }
@ -65,10 +65,11 @@ if (isset($_POST['fix_problems'])) {
$highest_gid = ldap_get_highest_id($ldap_connection,'gid'); $highest_gid = ldap_get_highest_id($ldap_connection,'gid');
$description = "Records the last GID used to create a Posix group. This prevents the re-use of a GID from a deleted group."; $description = "Records the last GID used to create a Posix group. This prevents the re-use of a GID from a deleted group.";
$gid_add = ldap_add($ldap_connection, "cn=lastGID,${LDAP['base_dn']}", array( 'objectClass' => array('device','top'), $add_lastgid_r = array( 'objectClass' => array('device','top'),
'serialnumber' => $highest_gid, 'serialnumber' => $highest_gid,
'description' => $description ) 'description' => $description );
);
$gid_add = @ ldap_add($ldap_connection, "cn=lastGID,${LDAP['base_dn']}", $add_lastgid_r);
if ($gid_add == TRUE) { if ($gid_add == TRUE) {
print "$li_good Created <strong>cn=lastGID,${LDAP['base_dn']}</strong></li>\n"; print "$li_good Created <strong>cn=lastGID,${LDAP['base_dn']}</strong></li>\n";
@ -86,10 +87,11 @@ if (isset($_POST['fix_problems'])) {
$highest_uid = ldap_get_highest_id($ldap_connection,'uid'); $highest_uid = ldap_get_highest_id($ldap_connection,'uid');
$description = "Records the last UID used to create a Posix account. This prevents the re-use of a UID from a deleted account."; $description = "Records the last UID used to create a Posix account. This prevents the re-use of a UID from a deleted account.";
$uid_add = ldap_add($ldap_connection, "cn=lastUID,${LDAP['base_dn']}", array( 'objectClass' => array('device','top'), $add_lastuid_r = array( 'objectClass' => array('device','top'),
'serialnumber' => $highest_uid, 'serialnumber' => $highest_uid,
'description' => $description ) 'description' => $description );
);
$uid_add = @ ldap_add($ldap_connection, "cn=lastUID,${LDAP['base_dn']}", $add_lastuid_r);
if ($uid_add == TRUE) { if ($uid_add == TRUE) {
print "$li_good Created <strong>cn=lastUID,${LDAP['base_dn']}</strong></li>\n"; print "$li_good Created <strong>cn=lastUID,${LDAP['base_dn']}</strong></li>\n";
@ -146,7 +148,6 @@ if (isset($_POST['fix_problems'])) {
print "<label class='pull-right'><input type='checkbox' name='setup_admin_account' class='pull-right' checked>Create a new account and add it to the admin group?&nbsp;</label>"; print "<label class='pull-right'><input type='checkbox' name='setup_admin_account' class='pull-right' checked>Create a new account and add it to the admin group?&nbsp;</label>";
print "</li>\n"; print "</li>\n";
$show_create_admin_button = TRUE; $show_create_admin_button = TRUE;
} }
else { else {
print "$li_good The LDAP account administrators group (<strong>${LDAP['admins_group']}</strong>) isn't empty.</li>"; print "$li_good The LDAP account administrators group (<strong>${LDAP['admins_group']}</strong>) isn't empty.</li>";
@ -164,6 +165,7 @@ if (isset($_POST['fix_problems'])) {
if ($no_errors == TRUE) { if ($no_errors == TRUE) {
if ($show_create_admin_button == FALSE) { if ($show_create_admin_button == FALSE) {
?> ?>
</form>
<div class='well'> <div class='well'>
<form action="/"> <form action="/">
<input type='submit' class="btn btn-success center-block" value='Finished' class='center-block'> <input type='submit' class="btn btn-success center-block" value='Finished' class='center-block'>
@ -182,6 +184,7 @@ if (isset($_POST['fix_problems'])) {
} }
else { else {
?> ?>
</form>
<div class='well'> <div class='well'>
<form action="/setup/run_checks.php"> <form action="/setup/run_checks.php">
<input type='submit' class="btn btn-danger center-block" value='< Re-run setup' class='center-block'> <input type='submit' class="btn btn-danger center-block" value='< Re-run setup' class='center-block'>