Jump to content

LDAP for ProcessWire


Marvin Scharle
 Share

Recommended Posts

Hi everybody,

I'd like to share a new module with you. Its purpose is to let users sign in with their Active Directory accounts using LDAP.

ldap-settings-english5nc2i.png

It works similar to the module jimyost released in 2012, but adds some new features to it.

  • You can define specific roles that are applied to new LDAP users
  • Passwords are automatically updated by LDAP
  • Local users still work like a charm
  • You can translate it in the language you want to deploy your ProcessWire site
  • New: Connect to a LDAP server via SSL
  • New: Debug Mode
  • New: Your configuration will be validated on save

In my opinion, LDAP authentication is a must-have for ProcessWire being successful in the enterprise.

What do you think? Is there a feature you miss? 

You can find the repository here: https://github.com/conclurer/LdapSignIn

You can find the module in the ProcessWire module directory.

Thanks in advance!

Marvin

Edit: Updated to Version 0.5.1 Beta including some minor fixes

Edited by Marvin Scharle
  • Like 14
Link to comment
Share on other sites

Thanks for this, Marvin!

To answer your question, proper LDAP module is definitely something we need. Taking a quick look at your code, this seems like a reasonable tool for simple use cases, which brings me to my question: do you have any plans for incorporating slightly more advanced features, such as defining roles based on AD groups (including nested groups, which is surprisingly often missed altogether), automatically closing sessions for users no longer found from AD, etc.?

In my opinion those are (some of the) must-have features in order for this module to answer those "enterprise use cases" you've mentioned :)

Also, as a minor (?) detail, ability to specifically define search base would be great (and, again, a must-have feature in certain setups).

  • Like 2
Link to comment
Share on other sites

I think the last time this came up someone mentioned there is a unique user ID in Active Directory that would be worth storing (objectGUID).

My scenario is if someone gets married and you remember to change it in AD you might not remember to change it in other places. Therefore they would be treated as a new user in this module. It would be amazing if when it can't find the user it checks details via LDAP but then also checks the objectGUID against the PW database and update name and other details accordingly.

Just a thought, but I know how annoying it can be the more pieces of software you have to remember to change logins across. Even armed with a checklist it can take more time than it needs to :)


EDIT: This comment on PHP.net might be of interest: http://php.net/manual/en/function.ldap-get-values-len.php#111899

  • Like 1
Link to comment
Share on other sites

Hello everyone,

Thank you for your fast answers. Looks like there's definitely a need for an extended LDAP module. 

@teppo: Yes, I'll enhance the module's functionality over time. For ideas and feature wishes, you can just open up tickets on GitHub. Furthermore, if you can extend the module's functionality, you can open up a pull request on GitHub at any time.

@horst: Thank you for finding the spelling mistake. I'll fix that one in the next update.

@Pete: This is heading in the same direction as teppo's thoughts. Maybe in addition to mapping the groups into different ProcessWire roles, mapping some user-defined Active Directory attributes to ProcessWire user variables could be a nice extension. I'd be glad if we could talk about this in a separat GitHub thread so that this does not interrupt this one.

The idea with the GUID is nice, although it needs an additional field in the user model and I'm not sure if that is a proper way to solve this issue. 

@Nico Knoll: Of course I'm German. How could you be unable to see that. ;-) I work together with @phil at Conclurer.

  • Like 4
Link to comment
Share on other sites

Thanks for this, Marvin!

To answer your question, proper LDAP module is definitely something we need. Taking a quick look at your code, this seems like a reasonable tool for simple use cases, which brings me to my question: do you have any plans for incorporating slightly more advanced features, such as defining roles based on AD groups (including nested groups, which is surprisingly often missed altogether), automatically closing sessions for users no longer found from AD, etc.?

In my opinion those are (some of the) must-have features in order for this module to answer those "enterprise use cases" you've mentioned :)

Also, as a minor (?) detail, ability to specifically define search base would be great (and, again, a must-have feature in certain setups).

We have created an LDAP module for PW that supports mapping groups, setting the base dn and storing the e-mail address of the user (for an example). It also has an "Active Directory" -mode. I don't think Marvin's current code works with every AD-instance since it's missing a couple of ldap_set_option() calls that are needed for some. The only reason we haven't released it earlier is that we wouldn't have the time to maintain it.

@Marvin: If you want to take a look at the code I can post it on Github and throw you a link. You could always implement all the stuff by yourself as well, I would understand ;)

  • Like 9
Link to comment
Share on other sites

I don't think Marvin's current code works with every AD-instance since it's missing a couple of ldap_set_option() calls that are needed for some.

@Marvin: If you want to take a look at the code I can post it on Github and throw you a link. You could always implement all the stuff by yourself as well, I would understand ;)

Thank you for your feedback and your commitment. I already guessed that it won't work with every AD. So far, the few ADs I have for testing seem to work. 

Written before, I try to enhance the module over time and add more features and compatibilities to it. Therefore, I'd be pleased if you can share the code with me, so I can enhance this module and make it better. Of course, you will be given credits in the source code for this. 

What connects us is that we all love ProcessWire and want to see it grow in every environment. So if we pull together, we can achieve this.  :)

  • Like 7
Link to comment
Share on other sites

I've updated the module to version 0.5.1 including some minor fixes.

New features are the ability to use SSL (LDAPS), turn on Debug Mode and the validation of the configuration file on save.

@horst: the typo is also fixed :-)

@sforsman: when can I expect your repository? I'd really like to see it.

  • Like 4
Link to comment
Share on other sites

@sforsman: you should never not post a module only because you can't maintain it. Just do it like me: release it and then declare it as "proof of concept" ;)

That's the exact thing I try to avoid ;)

@Marvin: Here goes: https://github.com/sforsman/SessionLdapAuth

I even added an example for the group mapper and did a modification to the code (well, I fixed a spelling error in the description of the module)!

If you have any questions about some parts of it, just ask away.

I've published it as a Proof of Concept.

(see Nico, I'm learning!)

No but really, the main point here is to give you something to think against regarding your own implementation. The group mapper configuration string for an example is parsed in a very quick and dirty (=error prone) way and shouldn't be given directly to clients.

  • Like 4
Link to comment
Share on other sites

  • 1 year later...

Hi Marvin,

i have problems to install this module on my Processwire Projekt. I have install php-ldap extension and activade ldap.so in my php.ini but after upload the ldap-sign-in folder to my Processwire modules folder, i can't see the module in the Processwire modules list. What is the Problem?

Link to comment
Share on other sites

Thanks Mats, that's work fine. I must change Something in the Module for using the LDAP v3 Protocol. Now i found a problem in this module by changing password in ldap. When the user change his Password he can login with the old password on processwire. But when he login with his new password the login hangs in a loop. Processwire ask the ldap again and again and ldap answer true again and again. after this loop i can login with the new password. i can't find the part who loops the login!

Thats the part who i change:

public function ___login(HookEvent $event)
    {
        if ($event->return)
            return; // Skip if already logged in

        $username = $event->arguments [0];
        $password = $event->arguments [1];

        // skip if user already exists locally
        //if (!$this->users->get("name=$username") instanceof NullPage)
        //   	 return;

        // Set default user domain name if not given
        //$username = str_replace('@', '', $username) == $username ? "$username@{$this->defaultLoginDomain}" : $username;
      	// Workaround
      	$ldapusername = "uid=$username,ou=People,dc=ffmyk,dc=de";
      	
          if ($this->ldapUserLogin($ldapusername, $password)) {
              $wireUserName = $this->sanitizer->pageName($username);

              $user = $this->users->get("name=$wireUserName");
              if ($user instanceof NullPage) {
                  $usersPath = $this->users->getGuestUser()->parent;

                  $user = new User ();
                  $user->parent = $usersPath;
                  $user->name = $wireUserName;
                  $user->pass = $password;
                  foreach ($this->userDefaultRoles as $role)
                      $user->addRole($role);
                  $user->save();
            } else {          
          		$user->setOutputFormatting(false);
          		$user->pass = $password;
          		$user->save();
            }

            // Reset given LDAP-Username to WireUsername
            $user = $this->session->login($wireUserName, $password);
            $event->return = $user;

            $this->message($this->_('Logged in via LDAP'));

            return;
        }

and

public function ldapUserLogin($user, $password)
    {
        $connection = $this->connectLdap();
        if (!$connection)
            return false;

	ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 3);

        $bind = @ldap_bind($connection, $user, $password);

        return ($bind !== false);
    }
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...