|
| 1 | +# project_openldap - A plugin to push project information to an OpenLDAP instance |
| 2 | + |
| 3 | +Coldfront django plugin providing capability to push project information to OpenLDAP. |
| 4 | + |
| 5 | +OpenLDAP is a commonly deployed Identity Provider (IdP) - see https://www.openldap.org/ |
| 6 | + |
| 7 | +This plugin makes use of django signals within Coldfront to push project information to OpenLDAP. The main motivation for this is so projects and their members can be represented inside a _PosixGroup_, with usage of _memberUid_ (for members). Having this information in OpenLDAP facilitates the usage of filesystem quotas and other activities on a project basis. |
| 8 | + |
| 9 | +**The motivation for using this plugin, is that you want Coldfront and it's WebUI to be the source of truth**. This might be in contrast to another operating modality where information is [generally] imported from another system or IdP into Coldfront. |
| 10 | +- You will still need some means of creating/registering users in your OpenLDAP, e.g. a user registration portal - that is not covered/provided here. If you are just testing, you might add these to the DIT with ldifs. |
| 11 | + |
| 12 | +- **NOTE: The plugin doesn't write a Coldfront project's allocation(s) into OpenLDAP. It is expected a separate plugin will do this.** |
| 13 | + |
| 14 | + |
| 15 | +## Design |
| 16 | + |
| 17 | +The plugin results in each Coldfront project being created in OpenLDAP with an associated OU and a posixgroup with synchronized membership. |
| 18 | + |
| 19 | +- **NOTE:** Each project gets a **<ins>per project group _OU_</ins>** AND **<ins>a per project group _posixgroup_</ins>** written. |
| 20 | + |
| 21 | +To do this django signals are used, which fire upon actions in the Coldfront WebUI. E.g. project creation. |
| 22 | + |
| 23 | +The plugin uses a bind user (which the site has to setup with appropriate write access) and _python ldap3_ to write changes to OpenLDAP. |
| 24 | + |
| 25 | +The **bind user** will **write to a project project OU** and **potentially an archive OU** (if defined by the site admin). |
| 26 | + |
| 27 | +The OpenLDAP server (slapd) must be operational and ready to accept changes via the configured bind user. |
| 28 | + |
| 29 | +Variables to use to configure the plugin are detailed further down in this ``README.md`` |
| 30 | + |
| 31 | +### Design - signals and actions |
| 32 | + |
| 33 | +#### signals |
| 34 | + |
| 35 | +The following five Coldfront django signals are used by this plugin, upon Coldfront WebUI actions: |
| 36 | + |
| 37 | +- project new |
| 38 | +- project archive |
| 39 | +- project update (e.g. update title) |
| 40 | +- add project member(s) |
| 41 | +- remove project member(s) |
| 42 | + |
| 43 | +To see the exact receiver definitions look at the ``signals.py`` within the plugin directory. |
| 44 | + |
| 45 | +#### actions |
| 46 | + |
| 47 | +The aforementioned signals trigger functions in tasks.py, these in turn use functions in ``utils.py`` to accomplish the action required. Examples are: |
| 48 | + |
| 49 | +- create a per project OU and per project posixgroup within a Projects OU - **new project** |
| 50 | +- move a per project OU (and per project posixgroup) to an Archive OU or simply delete it - **archive project** - which action depends on environment variable setup |
| 51 | +- add members to the per project posixgroup - **project add members** |
| 52 | +- remove members from the per project posixgroup - **project remove members** |
| 53 | +- update title - **project update** |
| 54 | + |
| 55 | +The next section shows the representation in OpenLDAP. |
| 56 | + |
| 57 | +### DIT Diagram |
| 58 | + |
| 59 | +DIT Mermaid diagram. |
| 60 | + |
| 61 | +- Projects get created in the Projects OU. A per project OU and a per project posixgroup is created. |
| 62 | +- Per project OU's get moved to Archive OU or deleted on Coldfront WebUI archive action. |
| 63 | +- **If no Archive OU** is setup by the site administrator, then **projects** (per project OUs) are **deleted on archival**. |
| 64 | + |
| 65 | + |
| 66 | +```mermaid |
| 67 | +%%{init: {'theme': 'forest', 'themeVariables': { 'fontSize': '20px', 'fontFamily': 'Inter'}}}%% |
| 68 | +classDiagram |
| 69 | + OPENLDAP_DIT <-- projects_OU |
| 70 | + OPENLDAP_DIT <-- archive_OU |
| 71 | + projects_OU <-- per_project_OU |
| 72 | + per_project_OU <-- per_project_posixgroup |
| 73 | + class OPENLDAP_DIT { |
| 74 | + } |
| 75 | + class projects_OU { |
| 76 | + objectClass: organizationalUnit |
| 77 | + objectClass: top |
| 78 | + } |
| 79 | + class archive_OU { |
| 80 | + objectClass: organizationalUnit |
| 81 | + objectClass: top |
| 82 | + } |
| 83 | + class per_project_OU { |
| 84 | + ou: project_code |
| 85 | + objectClass: organizationalUnit |
| 86 | + objectClass: top |
| 87 | + description: OU for project: project_code |
| 88 | + } |
| 89 | + class per_project_posixgroup { |
| 90 | + cn: project_code |
| 91 | + gidNumber: GID_START+PK |
| 92 | + objectClass: posixgroup |
| 93 | + description: institution, pi, title |
| 94 | + -------------------------------------------------- |
| 95 | + memberUid: ldapuser1 |
| 96 | + memberUid: ldapuser2 |
| 97 | + } |
| 98 | +``` |
| 99 | + |
| 100 | + |
| 101 | + |
| 102 | +### Syncronization and management command usage |
| 103 | + |
| 104 | +Should Coldfront continue creating or modifying projects whilst the OpenLDAP server is unavailable, corrective action will likely be needed. A management command is provided to perform checks and synchronize changes required. This should only be used when Coldfront and OpenLDAP are (or are suspected) to be out of sync. |
| 105 | + |
| 106 | +From within the Coldfront user's venv environment, the management command help can be seen: |
| 107 | + |
| 108 | +``coldfront project_openldap_sync --help`` |
| 109 | + |
| 110 | +Further detail on the management command can be seen in the directory ``README.md`` |
| 111 | + |
| 112 | +Also included within that directory is a Mermaid diagram (``Mermaid.md``) of the main function of the sync management command. |
| 113 | + |
| 114 | +### Optional setup checker |
| 115 | + |
| 116 | +Another management command is present to aid setup checks for this plugin, before entering production. See command's help and/or ``README.md`` in management command directory. |
| 117 | + |
| 118 | +``coldfront project_openldap_check_setup --help`` |
| 119 | + |
| 120 | + |
| 121 | +## Requirements - general |
| 122 | + |
| 123 | +The plugin makes extensive use of the _python ldap3_ library - https://ldap3.readthedocs.io/ |
| 124 | + |
| 125 | +### Requirements - OpenLDAP |
| 126 | + |
| 127 | +- A working OpenLDAP master instance is required. |
| 128 | +- This plugin requires a bind user to make changes. It's recommended that a dedicated bind user is setup for this purpose and this purpose only. |
| 129 | +- You will also need to supply an OU to store projects in and optionally an OU to store (move) archived projects to. You should create this in the normal way e.g. ldif. |
| 130 | + |
| 131 | +#### GID: |
| 132 | + |
| 133 | +- **NOTE: A starting GID number to increment posixgroup GIDs is required. Consider this carefully before going into project to avoid clashes or problems.** |
| 134 | + |
| 135 | +#### Security: |
| 136 | + |
| 137 | +- **NOTE: OpenLDAP security and general site security is the responsibility of site administrators.** |
| 138 | + |
| 139 | + |
| 140 | +## Usage |
| 141 | + |
| 142 | +The plugin requires that various environment variables are defined in the Coldfront django settings - e.g. coldfront.env |
| 143 | + |
| 144 | +Example pre-requisites - we require `project_code` to be enabled, here is an example |
| 145 | + |
| 146 | +**Example Required project_code:** |
| 147 | +``` |
| 148 | +PROJECT_CODE="CDF" |
| 149 | +``` |
| 150 | +Example Optional project_code padding: |
| 151 | +``` |
| 152 | +PROJECT_CODE_PADDING=4 |
| 153 | +``` |
| 154 | + |
| 155 | +### Usage - Example setup |
| 156 | + |
| 157 | +An example setup might look something like this. |
| 158 | +- The institution feature usage is not required or mandated. |
| 159 | +- Here we are setup to use the Archive OU and not delete per project OUs upon Coldfront archive action in WebUI |
| 160 | + |
| 161 | +**NOTE:** Security (e.g. SSL + TLS) configuration is the responsibility of the site administrator - these aren't production settings below, only a starting point. |
| 162 | + |
| 163 | +``` |
| 164 | +PROJECT_CODE="CDF" |
| 165 | +PROJECT_CODE_PADDING=4 |
| 166 | +
|
| 167 | +PLUGIN_PROJECT_OPENLDAP=True |
| 168 | +PROJECT_OPENLDAP_GID_START=8000 |
| 169 | +PROJECT_OPENLDAP_SERVER_URI='ldaps://openldap.coldfront.ac.uk' |
| 170 | +PROJECT_OPENLDAP_OU='ou=projects,dc=coldfront,dc=ac,dc=uk' |
| 171 | +PROJECT_OPENLDAP_BIND_USER='my_bind_user_dn' |
| 172 | +PROJECT_OPENLDAP_BIND_PASSWORD='some_secure_password' |
| 173 | +PROJECT_OPENLDAP_CACERT_FILE='/etc/path/to/CAcert' |
| 174 | +PROJECT_OPENLDAP_USE_TLS=False |
| 175 | +
|
| 176 | +# archive settings |
| 177 | +PROJECT_OPENLDAP_REMOVE_PROJECT=True #default is true |
| 178 | +PROJECT_OPENLDAP_ARCHIVE_OU='ou=archive_projects,dc=coldfront,dc=ac,dc=uk' |
| 179 | +
|
| 180 | +#institution |
| 181 | +PROJECT_INSTITUTION_EMAIL_MAP=coldfront.ac.uk=ColdfrontUniversity |
| 182 | +
|
| 183 | +``` |
| 184 | + |
| 185 | + |
| 186 | +### Usage - Variable descriptions |
| 187 | + |
| 188 | +**Required Plugin load:** |
| 189 | + |
| 190 | +| Option | Type | Default | Description | |
| 191 | +|--- | --- | --- | --- | |
| 192 | +| `PLUGIN_PROJECT_OPENLDAP` | Bool | True | Enable the plugin, required to be set as True (bool). | |
| 193 | + |
| 194 | +**Required:** |
| 195 | +| Option | Type | Default | Description | |
| 196 | +|--- | --- | --- | --- | |
| 197 | +| `PROJECT_OPENLDAP_GID_START` | int | N/A | Starting value for project gidNumbers, requires an integer. | |
| 198 | +| `PROJECT_OPENLDAP_SERVER_URI` | str | empty str | The URI of the OpenLDAP instance, requires a string URI. | |
| 199 | +| `PROJECT_OPENLDAP_OU` | str | empty str |The OU where projects will be written, requires a string DN of OU. | |
| 200 | +| `PROJECT_OPENLDAP_BIND_USER` | str | empty str |The bind user, that can write to the `PROJECT_OPENLDAP_OU`, requires a string DN of bind user. | |
| 201 | +| `PROJECT_OPENLDAP_BIND_PASSWORD` | str | empty str |The password for the bind user, requires a string. | |
| 202 | +| `PROJECT_OPENLDAP_REMOVE_PROJECT` | Bool |True | Required to take action upon archive (action) of a project. Default True (bool). | |
| 203 | + |
| 204 | +**OpenLDAP specific:** |
| 205 | +| Option | Type | Default | Description | |
| 206 | +|--- | --- | --- | --- | |
| 207 | +| `PROJECT_OPENLDAP_CONNECT_TIMEOUT` | int |2.5 | Connection timeout. | |
| 208 | +| `PROJECT_OPENLDAP_USE_SSL` | Bool | True | Use SSL. | |
| 209 | +| `PROJECT_OPENLDAP_USE_TLS` | Bool | False | Enable Tls. | |
| 210 | +| `PROJECT_OPENLDAP_PRIV_KEY_FILE` | str | None | Tls Private key. | |
| 211 | +| `PROJECT_OPENLDAP_CERT_FILE` | str | None | Tls Certificate file. | |
| 212 | +| `PROJECT_OPENLDAP_CACERT_FILE` | str | None | Tls CA certificate file. | |
| 213 | + |
| 214 | +**Optional:** |
| 215 | + |
| 216 | +| Option | Type | Default | Description | |
| 217 | +|--- | --- | --- | --- | |
| 218 | +| `PROJECT_OPENLDAP_ARCHIVE_OU` | str | empty str | Optional, if this string is defined, then move upon archival action move the project object in OpenLDAP here. Supply a string DN of the desired OU. | |
| 219 | +| `PROJECT_OPENLDAP_DESCRIPTION_TITLE_LENGTH` | int | 100 | Optional, this integer will constrain the length of the Coldfront project title, within the OpenLDAP project description field. | |
| 220 | + |
| 221 | + |
| 222 | +<br> |
| 223 | + |
| 224 | +**Optional, management [sync] command related:** |
| 225 | + |
| 226 | +| Option | Type | Default | Description | |
| 227 | +|--- | --- | --- | --- | |
| 228 | +| `PROJECT_OPENLDAP_EXCLUDE_USERS` | tuple | ('coldfront',) | Tuple which by default is a single element tuple that will exclude the "coldfront" username from operations in the Syncer script - e.g. to avoid attempted add to OpenLDAP. | |
| 229 | + |
| 230 | + |
| 231 | + |
| 232 | +## Example per project prosixgroup and OU container |
| 233 | + |
| 234 | +An example of a project posixgroup and OU (see further down for OU). |
| 235 | + |
| 236 | +- Using 8000 as the start GID, this is project 11 (pk=11), so 8000+11 is the resultant gidNumber. |
| 237 | +- Within the OpenLDAP description _INSTITUTE_ gets populated if possible, the plugin doesn't require the institution feature is enabled though. _INSTITUTE: NotDefined_ will be seen if not enabled. |
| 238 | +<br> |
| 239 | + |
| 240 | +``` |
| 241 | +dn: cn=CDF0011,ou=CDF0011,ou=projects,dc=coldfront,dc=ac,dc=uk |
| 242 | +description: INSTITUTE: ColdfrontUniversity | PI: ldapuser1 | TITLE: cf project |
| 243 | + 11 |
| 244 | +gidNumber: 8011 |
| 245 | +objectClass: posixGroup |
| 246 | +cn: CDF0011 |
| 247 | +memberUid: ldapuser1 |
| 248 | +memberUid: ldapuser2 |
| 249 | +memberUid: ldapuser3 |
| 250 | +``` |
| 251 | + |
| 252 | +The per project OU containing the posixgroup looks like this: |
| 253 | + |
| 254 | +``` |
| 255 | +dn: ou=CDF0011,ou=projects,dc=coldfront,dc=ac,dc=uk |
| 256 | +ou: CDF0011 |
| 257 | +description: OU for project CDF0011 |
| 258 | +objectClass: top |
| 259 | +objectClass: organizationalUnit |
| 260 | +``` |
| 261 | + |
| 262 | + |
| 263 | + |
| 264 | + |
| 265 | + |
| 266 | +## Future work |
| 267 | + |
| 268 | +Future work could include: |
| 269 | + |
| 270 | +Plugin and integration - ``allocation_openldap``: |
| 271 | +- writing allocations (not just projects) to OpenLDAP, these could potentially be identified using the _project_code_ and a combination of other parameters to ensure unique. An ``allocation_openldap`` plugin is likely to be worked on soon. |
| 272 | +- currently the project removal (deletion) deletes the project group's _posixgroup_ then the project group's _OU_. This may need changed in future, such that multiple subordinates under the project group's _OU_ are deleted - this will depend on how the ``allocation_openldap`` feature is developed. For now though, the approach is simple and safe. |
| 273 | +- the sync management command may also see changes to push a couple of methods in ``utils.py`` - e.g. fetch membership. |
| 274 | + |
| 275 | +SASL: |
| 276 | +- SASL is not currently supported, all operations currently take place via the bind user and URI. SASL is currently considered low-priority. |
| 277 | + |
| 278 | +### Future considerations |
| 279 | + |
| 280 | +Some sites may want per-institution project OUs (which then contain the relevant project group OUs). Currently this is out-of-scope. The single projects OU is currently provided/favoured for simplicity. |
0 commit comments