Closed matthenning closed 5 years ago
Weirdly despite being able to authenticate using tinker i can't sync that same user with the artisan command:
$ php7.2 artisan adldap:import ***
Adldap\Models\ModelNotFoundException : No LDAP query results for filter: [(&(|(name=***)(mail=***)(uid=***)(sn=***)(givenname=***)(cn=***)(displayname=***))(objectclass=inetorgperson)(objectclass=person)(!(objectclass=contact))(uid=*))] in: [ou=***]
at /usr/share/ebimonitoring/vendor/adldap2/adldap2/src/Query/Builder.php:572
568|
569| // Make sure we check if the result is an entry or an array before
570| // we throw an exception in case the user wants raw results.
571| if (!$entry instanceof Model && !is_array($entry)) {
> 572| throw (new ModelNotFoundException())
573| ->setQuery($this->getUnescapedQuery(), $this->getDn());
574| }
575|
576| return $entry;
Exception trace:
1 Adldap\Query\Builder::findOrFail("***")
/usr/share/ebimonitoring/vendor/adldap2/adldap2-laravel/src/Commands/Console/Import.php:207
2 Adldap\Laravel\Commands\Console\Import::getUsers()
/usr/share/ebimonitoring/vendor/adldap2/adldap2-laravel/src/Commands/Console/Import.php:47
I've narrowed it down to the filter grammar compiler of Adldap2 but I think the root cause comes from the configuration.
The Connections\Ldap search method seems to return a broken filter.
The returned filter looks like this:
[(&(|(name=myuser)(mail=myuser)(uid=myuser)(sn=myuser)(givenname=myuser)(cn=myuser)(displayname=myuser))(objectclass=inetorgperson)(objectclass=person)(!(objectclass=contact))(uid=*))] in: [ou=***]
When I overwrite the $filter with uid=myuser
as I would've expected from the configuration above I get a result:
public function search($dn, $filter, array $fields, $onlyAttributes = false, $size = 0, $time = 0)
{
$filter = 'uid=myuser';
return ldap_search($this->getConnection(), $dn, $filter, $fields, $onlyAttributes, $size, $time);
}
The login through the application is working fine now, too. Maybe there's something wrong with my configuration leading to an invalid filter string, but I haven't found it yet.
Hi @matthenning,
Weirdly despite being able to authenticate using tinker i can't sync that same user with the artisan command:
When you enter an value with the php artisan adldap:import
command (such as php artisan adldap:import jdoe
), ANR is used (when using ActiveDirectory). However, since you're using OpenLDAP, an ANR equivalent query is built to search for the first user with one of the following attributes:
name
mail
uid
sn
givenname
cn
displayname
See:
The filter is actually valid:
(&
(|
(name=myuser)
(mail=myuser)
(uid=myuser)
(sn=myuser)
(givenname=myuser)
(cn=myuser)
(displayname=myuser)
)
(objectclass=inetorgperson)
(objectclass=person)
(!
(objectclass=contact)
)
(uid=*)
)
And you would actually receive a PHP warning for a bad search filter:
Warning: ldap_search(): Search: Bad search filter
You mention you login is now working on your application, but your tinker example is using Adldap::auth()->attempt()
which is simply calling an ldap_bind
against your configured LDAP server, but calling Laravel's Auth::attempt()
method would actually authenticate you in your application and use the Adldap2-Laravel auth driver.
Looking at your ENV, you've set a base DN with some OU's inside (LDAP_BASE_DN="ou=***,ou=***"
). Is the user you're trying to authenticate against contained inside this OU?
To clarify: Only when modifying the filter I can login through the frontend.
I tried this because the filter returned by the library seems impossible to match as it's looking for objectclass=inetorgperson
AND objectclass=person
.
I'm not sure whether a person equals an inetorgperson as I'm no LDAP expert, it just looked fishy.
The bind user is located in the OU above the users like uid=binduser,ou=department,o=*,c=*
and the users are uid=myuser,ou=users,ou=department,o=*,c=*
Hi @matthenning,
I'm not sure whether a person equals an inetorgperson as I'm no LDAP expert, it just looked fishy.
The objectClass
attribute is multi-valued, so it should contain both inetorgperson
and person
, but I could definitely be mistaken for OpenLDAP. Are you able to browse the user attributes on the LDAP record and see what the user has for their objectClass
?
Also, can you try removing the default scope Adldap\Laravel\Scopes\UidScope::class
from your ldap_auth.php
configuration, then run php artisan config:clear
and try authenticating again?
The objectClass
is inetOrgPerson
.
Removing the scope didn't do the trick.
Weirdly enough after upgrading I don't get any log output from Adldap2 despite having it enabled in ldap_auth.php
:
'logging' => [
'enabled' => true,
'events' => [
\Adldap\Laravel\Events\Importing::class => \Adldap\Laravel\Listeners\LogImport::class,
\Adldap\Laravel\Events\Synchronized::class => \Adldap\Laravel\Listeners\LogSynchronized::class,
\Adldap\Laravel\Events\Synchronizing::class => \Adldap\Laravel\Listeners\LogSynchronizing::class,
\Adldap\Laravel\Events\Authenticated::class => \Adldap\Laravel\Listeners\LogAuthenticated::class,
\Adldap\Laravel\Events\Authenticating::class => \Adldap\Laravel\Listeners\LogAuthentication::class,
\Adldap\Laravel\Events\AuthenticationFailed::class => \Adldap\Laravel\Listeners\LogAuthenticationFailure::class,
\Adldap\Laravel\Events\AuthenticationRejected::class => \Adldap\Laravel\Listeners\LogAuthenticationRejection::class,
\Adldap\Laravel\Events\AuthenticationSuccessful::class => \Adldap\Laravel\Listeners\LogAuthenticationSuccess::class,
\Adldap\Laravel\Events\DiscoveredWithCredentials::class => \Adldap\Laravel\Listeners\LogDiscovery::class,
\Adldap\Laravel\Events\AuthenticatedWithWindows::class => \Adldap\Laravel\Listeners\LogWindowsAuth::class,
\Adldap\Laravel\Events\AuthenticatedModelTrashed::class => \Adldap\Laravel\Listeners\LogTrashedModel::class,
],
],
I'm flying blind right now, which hinders debugging this further.
Did you clear your config cache after upgrading using php artisan config:clear
?
I added a dd($query);
to Query\Grammar.php+56 and got the following result (username redacted):
(&(objectclass=\69\6e\65\74\6f\72\67\70\65\72\73\6f\6e)(objectclass=\70\65\72\73\6f\6e)(!(objectclass=\63\6f\6e\74\61\63\74))(uid=*)(uid=redacted))
When translating the hex this results in:
(&(objectclass=inetorgperson)(objectclass=person)(!(objectclass=contact))(uid=*)(uid=redacted))
When I cut this down by removing the objectclass contact filter I can successfully authenticate:
(&(objectclass=inetorgperson)(objectclass=person)(uid=*)(uid=redacted))
Could it be that my object class is not only inetorgperson
and person
but also contact
?
Edit: Yes I cleared the config.
Ok, thanks @matthenning, appreciate all the debugging you've been going through. There's definitely an issue with the query for OpenLDAP users. I'm going to install a server on my machine today and do some debugging as well.
Are you able to dump your users attributes and see if it contains the objectclass
of contact
? I'd be surprised if that was the case, but I don't have much experience with OpenLDAP to be honest, so I could definitely be wrong.
Weird, it doesn't contain contact:
"objectclass": [
"person",
"top",
"inetOrgPerson",
"organizationalPerson"
]
I double checked that removing (!(objectclass=contact))
fixes the problem though.
So strange... Okay, I'll put a patch out for this shortly. Thanks @matthenning!
Fixed in v9.1.4. Run a composer update
and you should be all set.
Thanks again!
Description:
After upgrading from 4.* to 5.0 I can only authenticate using
tinker
but not through the application itself.I have a copy of the application running on the exact same system with the previous version so I don't think this is related to the SELinux issues mentioned in #597. The only difference is a switch to 5.0.2 and
composer update
. After that I followed the upgrade guide.Edit: ldap_auth.php:
ldap.php:
.env: