Home > OS >  Symfony 5.3 LDAP new authentication is always not valid credentials
Symfony 5.3 LDAP new authentication is always not valid credentials

Time:11-19

I'm trying a json_login_ldap with the new authenticator manager from Symfony 5.3, it seems it cannot resolve the user password and I get always a 'not valid credentials' error message and can't login.

If I try the comand line ldapsearch with my data it is working correctly. And debuggin in Symfony I can see the ldap user data. So it is failing on the authentication.

my security.yaml is

security:
enable_authenticator_manager: true
password_hashers:
    Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'

providers:
    my_ldap:
        ldap:
            service: Symfony\Component\Ldap\Ldap
            base_dn: '%env(resolve:BASE_DN)%'
            search_dn: '%env(resolve:SEARCH_DN)%'
            search_password: '%env(resolve:LDAP_PASSWORD)%'
            default_roles: ROLE_USER
            uid_key: sAMAccountName

firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    main:
        provider: my_ldap
        stateless: true
        json_login_ldap:
            service: Symfony\Component\Ldap\Ldap
            check_path: api_login
            username_path: security.credentials.login
            password_path: security.credentials.password
            search_dn: '%env(resolve:SEARCH_DN)%'
            search_password: '%env(resolve:LDAP_PASSWORD)%'
            dn_string: '%env(resolve:BASE_DN)%'
            query_string: 'sAMAccountName={username}'

access_control:
    # - { path: ^/admin, roles: ROLE_ADMIN }
    # - { path: ^/profile, roles: ROLE_USER }

the .env that declares the variables used in the security.yaml:

BASE_DN=OU=foo,OU=bar,OU=baz,OU=qux,DC=my,DC=example,DC=com
SEARCH_DN=cn=searchuser,ou=foo,ou=bar,ou=baz,ou=qux,dc=my,dc=example,dc=com
LDAP_PASSWORD=ldap_reader_password

and in the services.yaml

services:
_defaults:
    autowire: true
    autoconfigure: true

Symfony\Component\Ldap\Ldap:
    arguments: ['@Symfony\Component\Ldap\Adapter\ExtLdap\Adapter']
    tags:
        - ldap
Symfony\Component\Ldap\Adapter\ExtLdap\Adapter:
    arguments:
        -   host: my-host  # changed
            port: 389
            options:
                protocol_version: 3
                referrals: false

I'm sending the data with insomnia to test faster. I'm requesting a POST to http://localhost:8101/api/login with the data:

{
    "security": {
        "credentials": {
            "login": "test.username", 
            "password": "my_password"
        }
    }
}

I followed the code to symfony/ldap/Security/LdapUserProvider.php and the loadUserByIdentifier at the end of the function $this->loadUser($identifier, $entry) actually returns a LdapUser object with the ldap user data. But the password is null instead the provided password. So maybe the password is lost somewhere before reaching this point.

In symfony\ldap\Security\LdapAuthenticator.php, the authenticate function returns the Passport object, this object has the PasswordCredentials with the plaintext correct user provided password and resolved: false.

I haven't found json_login_ldap examples in the documentation, but the project is almost empty, and I'm only trying to configure the ldap login, the configuration seems pretty basic. Why is not resolving the user password? Why I can't login? What I'm doing wrong?

Thank you for your help

Edit: The ldapsearch command line is

ldapsearch -x -b "dc=my,cn=example,cn=com" -H ldap://my.example.com -D "cn=searchuser,ou=foo,ou=bar,ou=baz,ou=qux,dc=my,dc=example,dc=com" -W

then asks for the password and answers with the list of ldap users.

With the ldapsearch command:

ldapsearch -x -b "dc=my,cn=example,cn=com" -H ldap://my.example.com -D "cn=searchuser,ou=foo,ou=bar,ou=baz,ou=qux,dc=my,dc=example,dc=com" -W "sAMAccountName=test.username"

and I get the following data:

# Test.Username, foo, bar, baz, qux, my.example.com
dn: CN=Test.Username,OU=foo,OU=bar,OU=baz,OU=qux,DC=my,DC=example,DC=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: test.username
sn: Username
c: EN
l: Randomcity
title: Assistant - departament
description: 8183-01234 |  | EN | PT | Regular/Permanent
postalCode: 04035
physicalDeliveryOfficeName: Fake Street, Randomcity, 04035, EN
telephoneNumber:  34 (555) 123456
givenName: Test
distinguishedName: CN=Test Username,OU=foo,OU=bar,OU=baz,OU=qux,DC=my,DC=example,DC=com
instanceType: 4
whenCreated: 20230213120051.0Z
whenChanged: 20411115070912.0Z
displayName: Test Username
uSNCreated: 151386
memberOf: CN=pim,OU=pam,OU=pum - Groups,DC=my,DC=example,DC=com
uSNChanged: 330517879
co: bar
department: bar | departament
company: example bar U.C.
proxyAddresses: x500:/o=example/ou=Exchange Group (FYDF231234PDLT)/cn=Recipients/cn=Test.Username
streetAddress: Fake Street
employeeType: PT
name: Test Username
objectGUID:: mxAQq12Jjky/4ycKabEPS6==
userAccountControl: 512
badPwdCount: 0
codePage: 0
countryCode: 123
employeeID: EN00123
badPasswordTime: 123810906564118891
lastLogoff: 0
lastLogon: 123808333912908124
pwdLastSet: 123708200340431193
primaryGroupID: 123
objectSid:: AQUAAAAABCDEAAAxf4pEoe3zO6g0v/wO4kCAA==
accountExpires: 9123472012354775807
logonCount: 309
sAMAccountName: test.username
sAMAccountType: 123306368
sIDHistory:: AQUABCDEAAUVAAAAd4oemO2qe8MmF4j ZRkBAA==
showInAddressBook: CN=Default Global Address List,CN=All Global Address Lists,CN=Address Lists Container,CN=pim,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=my,DC=example,DC=com
showInAddressBook: CN=All Users,CN=All Address Lists,CN=Address Lists Container,CN=pim,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=my,DC=example,DC=com
legacyExchangeDN: /o=pim/ou=External (FYDIBOHF25SPDLT)/cn=Recipients/cn=3f3dc637018b7653b68936ba11ed003d
userPrincipalName: [email protected]
lockoutTime: 0
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=my,DC=example,DC=com
dSCorePropagationData: 20212345670447.0Z
lastLogonTimestamp: 132814364123188798
msDS-SupportedEncryptionTypes: 0
textEncodedORAddress: X400:C=GB;A= ;P=example;O=London;S=Username;G=Test;
mail: [email protected]
manager: CN=Another Username,OU=foo,OU=bar,OU=baz,OU=qux,DC=my,DC=example,DC=com
msExchOmaAdminWirelessEnable: 4
msExchVersion: 44220981232016
msExchRemoteRecipientType: 4
mailNickname: TestUsername
msExchWhenMailboxCreated: 20130219124128.0Z
msExchMDBRulesQuota: 64
targetAddress: SMTP:[email protected]
msExchSafeSendersHash:: fz/qCi123Qt86iU8888lolB1c6ddddUdL4Q77W9876rHu34
extensionAttribute1: EN
extensionAttribute11: 2015-May-08 12:05 by Workday
msExchArchiveQuota: 52123800
protocolSettings:: UE9QM8Klol123fCp8KnwqfCp8KytdfCp8Knwqc=
protocolSettings: 1
extensionAttribute12: Employee-PT
msExchMailboxGuid:: IPEaXbO1 0KPwAtZctyhBg==
msExchArchiveWarnQuota: 47112320
msExchPoliciesExcluded: {26491cfc-9e50-4857-861b-0cb8df22b5d7}
extensionAttribute4: bar | Finance
msExchRecipientDisplayType: -2112383642
extensionAttribute5: 255.255.255.255
msExchUMDtmfMap: reversedPhone:1234567890 
msExchUMDtmfMap: emailAddress:1234567890
msExchUMDtmfMap: lastNameFirstName:1234567890
msExchUMDtmfMap: firstNameLastName:1234567890
msExchTextMessagingState: 354021235
msExchTextMessagingState: 16123851
extensionAttribute6: EN001
msExchALObjectVersion: 119
extensionAttribute7: Active
msExchUserAccountControl: 0
msExchUMEnabledFlags2: -1
msExchRecipientTypeDetails: 2147123648
msExchELCMailboxFlags: 2
msExchDisabledArchiveGUID:: R/hxhWWlol123j1bfjZLNg==

When I asked for the ldap data they told me that the uid_key is sAMAccountName. And I think it could be the problem.

I tried to change the security.yaml ldap provider uid_key to mail (uid_key: mail), and the json_login_ldap dn_string to username (dn_string: {username}), and then tryed to login with the email [email protected], but i see the same error.

CodePudding user response:

First, ensure the ldap provider is properly configured. According to your ldapsearch example, it should be (with environment variables resolved) :

providers:
    my_ldap:
        ldap:
            service: Symfony\Component\Ldap\Ldap
            base_dn: 'dc=my,cn=example,cn=com'
            search_dn: 'cn=searchuser,ou=foo,ou=bar,ou=baz,ou=qux,dc=my,dc=example,dc=com'
            search_password: '<searchuser_password>'
            default_roles: ROLE_USER
            uid_key: sAMAccountName

Then, the important thing to consider for the json login config is that dn_string is used as a user base dn when query_string is set (which is not obvious at all).

query_string:
When this option is used, query_string will search in the DN specified by dn_string and the DN resulted of the query_string will be used to authenticate the user with their password.

Also, the example in the documentation shows that search_dn and search_password are both set (again) in the login config.

Following these 2 points, this should work :

json_login_ldap:
    service: Symfony\Component\Ldap\Ldap
    check_path: api_login
    username_path: security.credentials.login
    password_path: security.credentials.password
    search_dn: 'cn=searchuser,ou=foo,ou=bar,ou=baz,ou=qux,dc=my,dc=example,dc=com'
    search_password: '<searchuser_password>'
    dn_string: 'dc=my,cn=example,cn=com'
    query_string: 'sAMAccountName={username}'

CodePudding user response:

I think the issue is with this piece of configuration:

main:
    provider: my_ldap
    stateless: true
    json_login_ldap:
        service: Symfony\Component\Ldap\Ldap
        check_path: api_login
        username_path: security.credentials.login
        password_path: security.credentials.password
        dn_string: 'uid={username},%env(resolve:BASE_DN)%'  <<<< ASSUMPTION

The assumption above is that all of your users are located in one flat list in a container. Looking at your ldapsearch example, you have an LDAP tree that is more hierarchical. It means that your BASE_DN value is not the direct parent of your users, but there are sublevels.

Looking at

        uid_key: sAMAccountName

I assume that you are using Active Directory. In that case, try this configuration:

providers:
    my_ldap:
        ldap:
            service: Symfony\Component\Ldap\Ldap
            base_dn: '%env(resolve:BASE_DN)%'
            search_dn: '%env(resolve:SEARCH_DN)%'
            search_password: '%env(resolve:LDAP_PASSWORD)%'
            default_roles: ROLE_USER
            uid_key: userPrincipalName

firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    main:
        provider: my_ldap
        stateless: true
        json_login_ldap:
            service: Symfony\Component\Ldap\Ldap
            check_path: api_login
            username_path: security.credentials.login
            password_path: security.credentials.password
            dn_string: '{username}'

(rest will stay the same).

Now you should be able to log in with the UPN of the users, of the format username@domain.

EDIT

You can also configure the LDAP module to search for the users by username, I had forgotten that part. That is the best solution IMHO. Change the configuration to this:

main:
    provider: my_ldap
    stateless: true
    json_login_ldap:
        service: Symfony\Component\Ldap\Ldap
        check_path: api_login
        username_path: security.credentials.login
        password_path: security.credentials.password
        query_string: 'sAMAccountName={username}'

and try to log in with the username you tried in the first place. See https://symfony.com/doc/current/security/ldap.html#query-string for the reference documentation.

EDIT

What if you use this as the main configuration, and try to log in with the same credentials as you showed in your JSON example?

main:
    provider: my_ldap
    stateless: true
    json_login_ldap:
        service: Symfony\Component\Ldap\Ldap
        check_path: api_login
        username_path: security.credentials.login
        password_path: security.credentials.password
        dn_string: '%env(resolve:BASE_DN)%'
        query_string: 'sAMAccountName={username}'
  • Related