2

So I am trying to modify a user in my active directory. As of now I can log in as an AD-user but when I try to edit my profile, it does not implement in the AD.

I use django-auth-ldap for AD backend.

I made a connection with a user that has reading and writing permissions.

AUTH_LDAP_SERVER_URI = "ldap://192.168.1.12"

AUTH_LDAP_BIND_DN = "user"
AUTH_LDAP_BIND_PASSWORD = "password"
AUTH_LDAP_CONNECTION_OPTIONS = {
    ldap.OPT_DEBUG_LEVEL: 1,
    ldap.OPT_REFERRALS: 0
}
AUTH_LDAP_USER_SEARCH = LDAPSearch("DC=sb,DC=ch", ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)")

# Set up the basic group parameters.
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("DC=sb,DC=ch", ldap.SCOPE_SUBTREE, "(objectClass=group)")
AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType()


# What to do once the user is authenticated
AUTH_LDAP_USER_ATTR_MAP = {
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail"
}

AUTH_LDAP_USER_FLAGS_BY_GROUP = {
    "is_active": "CN=ipa-users,cn=users,DC=sb,DC=ch",
    "is_staff": "CN=ipa-users,cn=users,DC=sb,DC=ch",
    "is_superuser": "CN=ipa-users,cn=users,DC=sb,DC=ch"
}

# This is the default, but be explicit.
AUTH_LDAP_ALWAYS_UPDATE_USER = True

# Use LDAP group membership to calculate group permissions.
AUTH_LDAP_FIND_GROUP_PERMS = True

# Cache settings
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600

AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.LDAPBackend',
    'django.contrib.auth.backends.ModelBackend',
)

So what and where do I have to set or get anything?

This is my edit_profile.html:

<form method="post">
        {% csrf_token %}

        <label for="first_name">Vorname </label>
        <input style="margin-bottom: 1em;" id="first_name" class="form-control" type="text" name="first_name" value="{{ user.first_name }}"><br>
        <label for="last_name">Nachname </label>
        <input style=" margin-bottom: 1em;" id="last_name" class="form-control" type="text" name="last_name" value="{{ user.last_name }}"><br>
        <label for="email">E-Mail </label>
        <input style="margin-bottom: 1em;" id="email" class="form-control" type="email" required=True unique=True name="email" value="{{ user.email }}"><br>

        <button class="btn btn-success btn-sm" type="submit">Bestätigen</button>
halfer
  • 19,824
  • 17
  • 99
  • 186
GeniusBehind
  • 89
  • 12

2 Answers2

4

It is impossible with only django-auth-ldap

Rough guesstimation shows that you're using django-auth-ldap (I updated your question). A glance on it shows that it only has a backend, and cannot do anything else.

If you actually want to update some data in AD, you will need to do it yourself. I'm using python-ldap3 which I can recommend for this purpose. It also includes some helpers specifically for AD.


Upd: as requested, an example using python-ldap3

Something like that, not sure whether the code below works (it's a mashup of bits of existing code). But it should give you an idea on what you should do. Welcome to the hell of LDAP.

import ldap3

conn = ldap3.Connection(
    server="ldaps://foobar",
    user="username@domain",  # normally full DN, but AD supports this format as well
    password="password",
    auto_bind=ldap3.AUTO_BIND_NONE,
    authentication=ldap3.SIMPLE,
    raise_exceptions=True,
    auto_referrals=False,  # 90% you want it set to False
    receive_timeout=10,  # seconds, exception afterwards
)

conn.start_tls()
conn.bind()

search = conn.extend.standard.paged_search(
    search_base="dc=domain",
    search_filter="(userPrincipalName=username@domain)",  # or (cn=username) or (sAMAccountName=username) or whatever
    search_scope=ldap3.SUBTREE,
    attributes=ldap3.ALL_ATTRIBUTES,
    dereference_aliases=ldap3.DEREF_NEVER,
    generator=True,
)

entries = [entry for entry in search if entry["type"] == "searchResEntry"]  # not sure how to get rid of all the aliases otherwise

assert len(entries) is 1, "got {0} entries".format(len(entries))
entry = entries[0]

dn = entry["dn"]

changes = {
    "attributeName": [
        [ldap3.MODIFY_DELETE, ["old value 1", "old value 2",]],
        [ldap3.MODIFY_ADD, ["a new value"]],
    ]
}

conn.modify(dn, changes)

conn.unbind()
Art
  • 2,235
  • 18
  • 34
  • Thank you so much!! Do you have an example for this? – GeniusBehind Dec 28 '17 at 12:29
  • is this code in the setting.py file or do I have to bind it somwhere. If yes, can you tell me how? – GeniusBehind Jan 18 '18 at 10:23
  • @ZeraICT No, it will not help to put this into settings >.< If you want to use this snippet, you will have to run it every time user data should be updated in AD. You will need to figure out yourself where from and when exactly it should be executed. – Art Jan 18 '18 at 13:30
  • If I have a GUI and I want to run this code, is it even possible to bind it, so that I can change i.e. the first_name of the logged in user and it will automatically update the user in the LDAP after I press the submit-button? – GeniusBehind Jan 18 '18 at 14:32
  • Run this code when users presses the submit button. If you don't know how to run python code when user submits the form, [check django documentation](https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/). – Art Jan 18 '18 at 15:24
0

Not impossible, but not easy.

First of all, you need to authenticate the user or to find him in LDAP. Example:

user = authenticate(
    username=request.user.username,
    password=request.POST['password']
)

Now, the user has some properties that the request.user object has not, like ldap_user. This property can be used to modify the password, for example:

# remember to add: import ldap.modlist as modlist

pwd = "new password"
ldif = modlist.modifyModlist(
    {'userpassword': user.ldap_user.attrs['userpassword']},
    {'userpassword': [pwd.encode()]}
)
user.ldap_user.connection.modify_s(user.ldap_user.dn, ldif)

And that's it.

MagMax
  • 1,645
  • 2
  • 17
  • 26
  • Quite nice your solution, but `ldif` gave me some troubles in django 1.8. For the future people: `ldif = modlist.modifyModlist( {u'userpassword': [password_old.encode('utf-8')]}, {u'userpassword': [password_hashed.encode('utf-8')]} )` – Serk Jun 18 '20 at 09:01
  • I suggest you not to mess up and manage the LDAP from other tool, maybe Keycloak or similar if possible, and use the django-ldap just for querying. – MagMax Jun 19 '20 at 12:06