Package: ldap-hooks
ldap_hooksA Jupyter Spawner hook for creating LDAP DIT entries viapre_spawn_hookInstallationInstallation from pypi:pip install ldap-hooksInstallation from local git repository:cd ldap_hooks
pip install .ConfigurationYou should edit yourjupyterhub_config.pyconfig file to set a particular
pre_spawn_hook, E.g:from ldap_hooks import hello_hook

c.Spawner.pre_spawn_hook = hello_hookIn addition to specifying thepre_spawn_hook, a set of connection parameters must be set in order for
the JupyterHub server to be able to interact with the designated LDAP host:from ldap_hooks import LDAP

LDAP.url = "openldap"
LDAP.user = "cn=admin,dc=example,dc=org"
LDAP.password = "dummyldap_password"
LDAP.base_dn = "dc=example,dc=org"The user’s permissions here depend on whether the hook is just
extracting information, or is creating entries as well.The hooks that this library provides can be found below.By default, any of these hooks are called by the Spawner
with the following syntax:def hook(spawner):
    # Do stuff inside the hook
    return TrueThat is, the hook expects that the currentspawnerinstance
is passed to it, which it can subsequently use to access
properties of it, such as theuserinstance.setup_ldap_entry_hookThis hook enables that the Spawner will submit/create an LDAP entry
before the spawner starts the notebook. It is activated by setting the
following parameter in the JupyterHub config:from ldap_hooks import setup_ldap_entry_hook

c.Spawner.pre_spawn_hook = setup_ldap_entry_hookIn addition, the hook requires a number of a parameters to be configured
before it will work as intended.Basic ConfigurationFirst, to defined the following options, theLDAPclass
must be imported into thejupyterhub_config.pyfile:from ldap_hooks import LDAPWith this completed, thesubmit_spawner_attributemust be set,
this must point to the variable path in the spawner instance
where it can find theDistinguished Name String (DN)value.
This string value makes up the entry that is to be submitted to the LDAP DIT,
E.g:# Retrieve the Distinguished Name from the 'spawner.user.data' variable
LDAP.submit_spawner_attribute = 'user.data'In addition if this variable is of a dictionary structure,
a tuple row can be specified to define the set of keys that
should be used to extract the Distinguished Name value.
For instance, if the value is in the
spawner.user.data[‘User’][‘DN’] structure:# Extract the Distinguished Name string from the
# spawner.user.data['User']['DN'] path.
LDAP.submit_spawner_attribute = 'user.data'
LDAP.submit_spawner_attribute_keys = ('User', 'DN')If this extracted string is formatted in a way that is
incorrectly seperated, thereplace_object_withparameter can be
used to fix this, E.g.:# Prepare LDAP DN object entry
LDAP.replace_object_with = {'/': '+'}
# Does the following replacement
# /telephoneNumber=23012303403/SN=My Surname/CN=a-new-user
# +telephoneNumber=23012303403+SN=My Surname+CN=a-new-userBy default thename_strip_charsparameter is
defined to strip extra characters that are either
pre or postfixed to the DN:# Default value
LDAP.name_strip_chars = ['/', '+', '*', ',', '.', '!', ' ']Which means that it will automatically strip
the prefixed+from thereplace_object_withoutput.Before the hook can submit the prepared DN,
it first has to know whichStructural ObjectClassshould be used to create the entry with.
Beyond at least one required Structural ObjectClass,
a list of additionalAuxiliary ObjectClassescan be specified as well.
All of which must be set via theobject_classesparameter, E.g:# Structural 'Person'
LDAP.object_classes = ['Person']Any specified object class must be supported as
part of the specifiedLDAP.urlserver schema.Beyond theobject_classes, the hook also
provides a parameter to specify additional object
attributes to submittet DN entry:LDAP.object_attributes = {'description': 'A default person account',
                          'surname': 'MySurname'}Duplicate entries can be default not exist in the LDAP DIT,
therefore any duplicate DN submission will fail.
By default the hook will search the DIT for
an entry that matches every attribute of the DN string,
if such an entry exists, the hook will simply stop before
attempting to submit it. This behaviour can be customised
via theunique_object_attributesparameter as shown in
the “Extra Features” section.Extra Featuresunique_object_attributesIt is possible to specify special attributes
that the hook should use for this search via
theunique_object_attributesparameter:# Optional parameter
LDAP.unique_object_attributes = ['surname']Now the hook will search for if an entry withobject_classesexists, if so it will stop the submission.set_spawner_attributesUse this to set JupyterHub Spawner attributes.
For instance set an environment variable of the Spawned notebooks:# Set Spawned Notebook environment vars
LDAP.set_spawner_attributes = {
    'environment': {'ENV_VAR': 'Hello from LDAP Hook'}
}search_attribute_queriesUse this to define a list of LDAP search operations to extract a
list of attributes from the existing DIT which can subsequntly be used
to perform some subsequent operation on the extracted attributes,
or share them with theset_spawner_attributesorobject_attributesvia thedynamic_attributesdefinition.For instance, extract theuidNumberattribute from the LDAP DIT
which has thex-nextUserIdentifierobjectclass:LDAP.search_attribute_queries = [
    {'search_base': LDAP.base_dn,
    'search_filter': '(objectclass=X-nextUserIdentifier)',
    'attributes': ['uidNumber']}
]search_result_operationsUse this to perform an operation action on extracted attributes of thesearch_attribute_queries. The specific action must be defined
as a LDAP.SEARCH_RESULT_OPERATION_ACTIONS.
For instance, increment the value of the extracteduidNumberattribute by 1,
for this particular action, it is required that themodify_dnkey is also
provided since it defines the Distinguished Name that should be used to select that attribute to be incremented in the DIT:modify_dn = 'cn=uidNumber' + ',' + LDAP.base_dn
LDAP.search_result_operation = {'uidNumber': {'action': INCREMENT_ATTRIBUTE,
                                            'modify_dn': modify_dn}}This will produce an atomic modify-increment to the value of thecn=uidNumber,dc=example,dc=org.dynamic_attributesTo formatset_spawner_attributesandobject_attributeswith dynamic attributes,
such as the result of an LDAP.SEARCH_RESULT_OPERATION_ACTIONS or values provided
by asubmit_spawner_attributedictionary. Thedynamic_attributescan
be used to format such attributes. For instance, if theset_spawner_attributesdefines attributes that expects formatting of the ‘emailAddress’ and ‘uidNumber’:LDAP.set_spawner_attributes = {
    'environment': {'NB_USER': '{emailAddress}',
                    'NB_UID': '{uidNumber}'},
}Thedynamic_attributescan provide these as follows:LDAP.dynamic_attributes = {
    'emailAddress': SPAWNER_SUBMIT_DATA,
    'uidNumber': LDAP_SEARCH_ATTRIBUTE_QUERY
}Where the values of the keys define how and where the attribute values should be extracted.
The specified value must be defined as a LDAP.DYNAMIC_ATTRIBUTE_METHODS.In addition thesedynamic_attributesare made available to the definedobject_attributes.
For example:LDAP.object_attributes = {'uidNumber': '{uidNumber}',
                          'homeDirectory': '/home/{emailAddress}'}