Skip to content

rgergo67/openldap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Don't use this for production

Feel free to fork it and modify it as you wish, but don't use this for production. The version numbering does not follow any conventions, this exists only for test purposes.

Openldap-laravel

With this package you can add users to OpenLdap, edit and delete them, manage their attributes and add them to posix groups. The package is used to a specific project with specific needs, feel free to modify it.

Install

Install using composer:

composer require rgergo67/openldap

Run php artisan vendor:publish this will copy openldap.php config file to config directory. Add the following line to the config/app.php providers array:

/*
 * Package Service Providers...
 */
 \Rgergo67\Openldap\OpenldapServiceProvider::class,

Basic usage

To be able to use this package, your User model needs to have two things.

DN attribute

First it has to have a dn attribute, which you can create virtually or get from a mysql field. In our User.php model it looks like this:

/**
     * Gets the dn attribute.
     *
     * @return string The dn attribute.
     */
    public function getDnAttribute(){
        $baseUserDn = $this->isStudent()
            ? config('openldap.base_student_dn')
            : config('openldap.base_employee_dn');
        return config('openldap.login_attribute') . "=" . $this->uid . "," . $baseUserDn;
    }

We store employees and students in different organization units, therefor we need to be able to decide which one the given user is. (Students have a 6 char length uid, employees have 10 char length uid). An example value for this dn attribute is cn=rgergo6,ou=student,ou=people,dc=example,dc=com

ldap-format attribute

Second thing is an array called ldap-attribute. This array translates mysql fields to ldap fields. For example:

/**
 * Gets the ldap format attribute.
 *
 * @return     array  The ldap format attribute.
 */
public function getLdapFormatAttribute(){
    return [
        "objectClass" => config('openldap.user_object_class'),
        'cn' => $this->name,
        'sn' => $this->name,
        'mail' => $this->email,
        'gidNumber' => 1,
        'homeDirectory' => '/home/' . $this->username,
        'uid' => $this->uid,
        'uidNumber' => 67
    ];
}

If you do an addUser($user); the package will use this array to create a user in ldap.

Object class

The objectClass attribute tells for ldap what kind of object the user is (which will specify what kind of attributes you can give it). You can edit this value in the config file, we use this:

'user_object_class' => [
    "top",
    "person",
    "eduPerson",
    "posixAccount",
    "inetOrgPerson",
    "radiusprofile",
    "shadowAccount",
    "schacContactLocation",
    "organizationalPerson",
    "schacLinkageIdentifiers" ,
],

In most cases the top, person, posixAccount, InetorgPerson is enough, but we need the others too for our project.

Configuration

In the config file you can see admin_dn and admin_password these are used to connect to openldap, and should be defined in your .env file.

dn

There are 4 other dn keys in config: base_user_dn: if you have multiple user subtrees like we do (students, employees), then these should go below a ou=people node, so if you are looking for a user with [email protected] you don't have to filter twice (once in student tree, once in employee tree). base_student_dn and base_employee_dn: we need to know where these are, so when we create a new employee, we can put it to the right place bsae_group_dn: the node where your groups are.

Groups

We use posix groups. The base_group_dn is ou=sys,dc=example,dc=com but you can use anything. Below this node is a ou=joomla and a ou=moodle for grouping the similar systems together. If we create a new joomla site like hr.example.com, we create a new organization unit for it ou=hr.example.com,ou=joomla,ou=sys,dc=example,dc=com, and a posix group below it for every joomla group (editor, registered, administrator): cn=editor,ou=hr.example.com,ou=joomla,ou=sys,dc=example,dc=com

Usage

//create a new openldap object
$openldap = new Openldap();
//find a user in your mysql database
$user = User::findOrFail(1);

// Adding new user, where $user should have dn and ldap_format virtual fields
$openldap->addUser($user);

// Find this newly added user by its uid in ldap
$openldap->findUserByUid($user->uid);

// To add new password without checking the old one
$openldap->newPassword($user, "secret");

// To replace the old password, and checking if it's correct
$openldap->replacePassword($user, "oldSecret", "newSecret");

dump($group->dn);
//"cn=editor,ou=hr.example.com,ou=joomla,ou=sys,dc=example,dc=com";
dump($group->ldap_format);
/**
* [
*     "objectClass" => config('openldap.group_object_class'),
*     'cn' => "editor"
* ]
*/

//Adding a group
$openldap->addRecord($group->dn, $group->ldap_format);

// Adding user to a group
$openldap->addUserToGroup($user, $group_dn);

// Add attribute to dn. $record should be in format ['attribute' => 'value']
$record['mail' => '[email protected]']
$openldap->addAttribute($dn, $record);

/* List the users groups. It returns an array of group dns like this:
[
    0 => [
        'dn' => 'cn=group1,dc=example,dc=com'
    ],
    1 => [
        'dn' => 'cn=group2,dc=example,dc=com'
    ]
]
*/
$openldap->$openldap->getUserGroups($user);

// Delete user from group
$openldap->deleteUserFromGroup($user, $group_dn);

// Delete user from all groups
$openldap->deleteUserFromAllGroups($user);

Updating user

If you would like to update a user, first check if its uid (or the attribute that is part of the dn) is dirty (is changed). If so, first rename it, and update afterwards. The third parameter of rename should only be used if you move the record somewhere else. Note that second parameter is only RDN, not the full DN.

if($user->isDirty('uid')){
    if(!$openldap->rename($user->oldDn, 'uid='.$user->uid, null))
        return false;
}

$openldap->updateUser($user);

One more thing: if you rename something, the first parameter should be the old DN. If you for example hook into the users updating event, the $user objects $user->uid field (that is part of the DN) would contain the updated uid (if you modified it). To get the old dn, make use of Laravels $user->getOriginal() function.

public function getOldDnAttribute()
{
    return "uid={$this->getOriginal('uid')},{$this->baseEmployeeDn}";
}

###Sync groups Sometimes you just need to be sure the users groups are all synced. This function removes all groups from user, and adds them again.

$openldap->syncUserGroups($user);

###Sync groups on user save save Hook into the users saved event, and run group sync there. We have a series of checkboxes with group names that we can retrieve with request('groups').

// if all groups were deleted, return
if(!request('groups'))
    return true;

$this->openldap->deleteUserFromAllGroups($user);

foreach(request('groups') as $groupId){
    $group = Group::findOrFail($groupId);
    $this->openldap->addUserToGroup($user, $group->dn);
}

###Cleaning arrays If you get back the search results from LDAP it has an ugly format, it is hard to work with. If you use the cleanUpEntry($entry) function, it will return a beutified cleaned php array. Credit goes to Chl

Example for simple search result:

dump($this->openldap->search("ou=phonebook,ou=dev,dc=uni-pannon,dc=hu", "uid=ratting.gergo.mik-math"));

array:2 [▼
  "count" => 1
  0 => array:18 [▼
    "objectclass" => array:5 [▼
      "count" => 4
      0 => "top"
      1 => "person"
      2 => "organizationalPerson"
      3 => "inetOrgPerson"
    ]
    0 => "objectclass"
    "sn" => array:2 [▼
      "count" => 1
      0 => "Ratting"
    ]
    1 => "sn"
    "cn" => array:2 [▼
      "count" => 1
      0 => "Ratting Gergely"
    ]
    2 => "cn"
    "displayname" => array:2 [▼
      "count" => 1
      0 => "Ratting Gergely"
    ]
    3 => "displayname"
    "telephonenumber" => array:2 [▼
      "count" => 1
      0 => "4835"
    ]
    4 => "telephonenumber"
    "ou" => array:3 [▼
      "count" => 2
      0 => "MIK"
      1 => "MIK-MATH"
    ]
    5 => "ou"
    "roomnumber" => array:2 [▼
      "count" => 1
      0 => "B211"
    ]
    6 => "roomnumber"
    "uid" => array:2 [▼
      "count" => 1
      0 => "ratting.gergo.mik-math"
    ]
    7 => "uid"
    "count" => 8
    "dn" => "uid=ratting.gergo.mik-math,ou=phonebook,ou=dev,dc=uni-pannon,dc=hu"
  ]
]

If we clean the result:

dump($this->openldap->cleanUpEntry(
    $this->openldap->search("ou=phonebook,ou=dev,dc=uni-pannon,dc=hu", "uid=ratting.gergo.mik-math")
));

array:1 [▼
  "uid=ratting.gergo.mik-math,ou=phonebook,ou=dev,dc=uni-pannon,dc=hu" => array:8 [▼
    "objectclass" => array:4 [▼
      0 => "top"
      1 => "person"
      2 => "organizationalPerson"
      3 => "inetOrgPerson"
    ]
    "sn" => "Ratting"
    "cn" => "Ratting Gergely"
    "displayname" => "Ratting Gergely"
    "telephonenumber" => "4835"
    "ou" => array:2 [▼
      0 => "MIK"
      1 => "MIK-MATH"
    ]
    "roomnumber" => "B211"
    "uid" => "ratting.gergo.mik-math"
  ]
]