2

I've set up local LDAP server Created user and group. Configured LDAP in AEM config manager and synchronized the users and group.

Using, ExternalIdentityProvider as a service reference, I'm able to get list of LDAP users I.e. I am able to validate if the user is present in LDAP or not.

But, I'm not able to validate user credentials using authentic method of the above mentioned API.

Am I missing any configuration specifics or the approach that I'm using is wrong ?

Updated:

Authentication code:

@Reference
private ExternalIdentityProviderManager externalIdentityProviderManager;

final String externalId = request.getParameter("externalId");
final String externalPassword = request.getParameter("externalPassword");

final ExternalIdentityProvider idap = externalIdentityProviderManager.getProvider("ldap");
final SimpleCredentials credentials = new SimpleCredentials(externalId, externalPassword.toCharArray());
final ExternalUser externalUser = idap.authenticate(credentials);

Error thrown -

javax.security.auth.login.LoginException: Unable to authenticate against LDAP server: INVALID_CREDENTIALS: Bind failed: Attempt to lookup non-existant entry: cn=steve+uid=steve+sn=jobs,dc=example,dc=com

Update: Identity provider config

# Configuration created by Apache Sling JCR Installer
userPool.maxActive=L"8"
searchTimeout="60s"
host.name="localhost"
customattributes=[""]
adminPool.maxActive=L"8"
group.makeDnPath=B"false"
user.baseDN="ou\=Users,dc\=example,dc\=com"
group.objectclass=["groupOfNames"]
user.objectclass=["person"]
userPool.lookupOnValidate=B"true"
host.noCertCheck=B"false"
user.makeDnPath=B"true"
bind.dn="uid\=admin,ou\=system"
group.baseDN="ou\=Groups,dc\=example,dc\=com"
group.extraFilter=""
user.extraFilter=""
host.port=I"10389"
bind.password="secret"
adminPool.lookupOnValidate=B"true"
useUidForExtId=B"false"
group.nameAttribute="cn"
provider.name="ldap"
host.ssl=B"false"
host.tls=B"false"
user.idAttribute="uid"
group.memberAttribute="member"

Sync Handler

# Configuration created by Apache Sling JCR Installer
group.pathPrefix=""
user.dynamicMembership=B"false"
group.expirationTime="1d"
user.membershipExpTime="1h"
user.pathPrefix=""
user.propertyMapping=["profile/nt:primaryType\=\"nt:unstructured\"","profile/givenName\=cn","profile/rep:password\=userPassword"]
handler.name="syncHandlerDefault"
enableRFC7613UsercaseMappedProfile=B"false"
user.autoMembership=[""]
user.expirationTime="1h"
group.propertyMapping=[""]
group.autoMembership=[""]
user.disableMissing=B"false"
user.membershipNestingDepth=I"3"

External login

# Configuration created by Apache Sling JCR Installer
jaas.controlFlag="SUFFICIENT"
jaas.ranking=I"50"
sync.handlerName="syncHandlerDefault"
jaas.realmName=""
idp.name="ldap"

LDIF file for users

version: 1

dn: ou=Users,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
ou: Users

dn: cn=eden+sn=hazard+uid=eden,ou=Users,dc=example,dc=com
objectClass: uidObject
objectClass: person
objectClass: top
cn: eden
sn: hazard
uid: eden
userPassword: {SSHA}O/t6ZRnWZTLhHla106Hp5nIWy85b0kgwNmeY3w==

dn: cn=rohit+sn=sharma+uid=rohit,ou=Users,dc=example,dc=com
objectClass: uidObject
objectClass: person
objectClass: top
cn: rohit
sn: sharma
uid: rohit
userPassword: {SSHA}9fzIkizxYg3LGG8n0jf/tnpv//qiNlxtS6mnWg==

dn: cn=harry+uid=harry+sn=kane,ou=Users,dc=example,dc=com
objectClass: uidObject
objectClass: person
objectClass: top
cn: harry
sn: kane
uid: harry
userPassword: {SSHA}WjNxB0ZDsmKfpjN0zwgsvDtZ4c/lHrIZXb7T2g==

dn: cn=cristiano+uid=cristiano+sn=ronaldo,ou=Users,dc=example,dc=com
objectClass: uidObject
objectClass: person
objectClass: top
cn: cristiano
sn: ronaldo
uid: cristiano
userPassword: {SSHA}ykzpMLVAbK99hfbCwwGgmgcDVzDV/Kfl0TlA8Q==

1 Answers1

1

For LDAP Login you need 3 OSGi configs. The most difficult one, you already have.

  • External Login Module (containing a reference to the next two)
  • LDAP Identity Provider (how to access the LDAP)
  • Sync Handler (mapping the LDAP data to AEM user data)

Here an example:

org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalLoginModuleFactory-emea

"jcr:primaryType": "sling:OsgiConfig",
"jaas.ranking": "50",
"jaas.controlFlag": "SUFFICIENT",
"jaas.realmName": "",
"idp.name": "ldap-emea",
"sync.handlerName": "sync-emea"

org.apache.jackrabbit.oak.security.authentication.ldap.impl.LdapIdentityProvider-emea

"jcr:primaryType": "sling:OsgiConfig",
"provider.name": "ldap-emea",
"host.name": "ldap-emea.emea.mycompany.internal",
"host.port": "3269",
"host.ssl": true,
"host.tls": true,
"host.noCertCheck": false,
"bind.dn": "CN=xxxx,OU=xxxx,OU=xxxx,OU=xxxx,DC=emea,DC=dir",
"bind.password": "very secret",
"searchTimeout": "60s",
"adminPool.maxActive": "8",
"adminPool.lookupOnValidate": true,
"userPool.maxActive": "8",
"userPool.lookupOnValidate": true,
"user.baseDN": "DC=emea,DC=dir",
"user.objectclass": "user",
"user.idAttribute": "sAMAccountName",
"user.extraFilter": "xxx very specific LDAP query xxxxx",
"user.makeDnPath": false,
"group.baseDN": "OU=Groups,OU=Common,DC=emea,DC=dir",
"group.objectclass": "group",
"group.nameAttribute": "cn",
"group.extraFilter": "xxx very specific LDAP query xxxxx",
"group.makeDnPath": false,
"group.memberAttribute": "member",
"customattributes": []

org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncHandler-emea

"jcr:primaryType": "sling:OsgiConfig",
"handler.name": "sync-emea",
"user.expirationTime": "1h",
"user.autoMembership": [],
"user.propertyMapping": [
   "rep:fullname=cn",
   "profile/email=mail",
   "profile/familyName=sn",
   "profile/givenName=givenName",
   "profile/aboutMe=description",
   "profile/country=co",
   "profile/jobTitle=department",
   "profile/phoneNumber=telephoneNumber",
   "profile/mobile=mobile",
   "profile/postalCode=postalCode",
   "profile/street=streetAddress",
   "preferences/language=\"en\""
],
"user.pathPrefix": "my-company/emea",
"user.membershipExpTime": "1h",
"user.membershipNestingDepth": "3",
"group.expirationTime": "1d",
"group.autoMembership": [],
"group.propertyMapping": [
   "profile/givenName=name",
   "profile/aboutMe=description"
],
"group.pathPrefix": "my-company/nested/emea",
"user.dynamicMembership": false,
"user.disableMissing": false,
"enableRFC7613UsercaseMappedProfile": false

kind regards, Alex


I additionally setup an Apache Directory Server and filled it with the sample data (Sailors of the seven seas) http://directory.apache.org/apacheds/basic-ug/1.5-sample-configuration.html

The following configuration worked for me (synced users and groups via JMX, successful login of a user, including auto sync):

http://localhost:4502/apps/ldap-test.9.json

  {
  "jcr:primaryType": "nt:folder",
  "config": {
    "jcr:primaryType": "sling:Folder",
    "org.apache.jackrabbit.oak.security.authentication.ldap.impl.LdapIdentityProvider-test": {
      "jcr:primaryType": "sling:OsgiConfig",
      "provider.name": "ldap-test-alex",
      "host.name": "localhost",
      "host.port": "10389",
      "host.ssl": false,
      "host.tls": false,
      "bind.dn": "uid=admin,ou=system",
      "bind.password": "secret",
      "user.objectclass": "person",
      "user.baseDN": "ou=people,o=sevenSeas",
      "user.idAttribute": "uid",
      "group.objectclass": "groupOfUniqueNames",
      "group.baseDN": "ou=groups,o=sevenSeas",
      "group.nameAttribute": "cn",
      "group.memberAttribute": "uniquemember",
    },
    "org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncHandler-test": {
      "jcr:primaryType": "sling:OsgiConfig",
      "handler.name": "ldap-sync-test-alex",
      "user.pathPrefix": "ldap-test",
      "group.pathPrefix": "ldap-test",
      "user.membershipNestingDepth": 1,
      "user.autoMembership": [
        "contributor"
      ],
      "user.propertyMapping": [
        "profile/email=mail",
        "profile/familyName=sn",
        "profile/givenName=givenName",
        "profile/aboutMe=description"
      ]
    },
    "org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalLoginModuleFactory-test": {
      "jcr:primaryType": "sling:OsgiConfig",
      "idp.name": "ldap-test-alex",
      "sync.handlerName": "ldap-sync-test-alex",
      "jaas.controlFlag": "SUFFICIENT",
      "jaas.ranking": "50"
    }
  }
}

Check, to have the following

  • know or set the password for the test user
  • set user.autoMembership to contributor (to see more than a white screen after a successful login)
  • check the OSGi config in the Felix console, maybe you missed the type or mispelled a config option
  • Check the log-file for hints

Alex

Alexander Berndt
  • 1,628
  • 9
  • 17
  • Hi Alex - I've configured the 3 osgi configs and I'm able to retrieve and display all LDAP users. But I'm not able to authenticate user-id/password to create a logon module. – Abhishek Sinha Jul 01 '19 at 10:12
  • I will check this tonight, and test it with Apache Directory Studio. But the difficult part is the connection with the LDAP. Retrieving the users already is great. – Alexander Berndt Jul 02 '19 at 07:15
  • Have you adapted the names? They are some kind of id, to connect everything. In my example ldap-emea and sync-emea. – Alexander Berndt Jul 02 '19 at 07:16
  • Maybe you post your configuration, and tell us which LDAP server you use? – Alexander Berndt Jul 02 '19 at 21:15
  • Btw. your code sample works great for me, so I can authenticate: except that I named the provider differently `externalIdentityProviderManager.getProvider("ldap-test-alex");` – Alexander Berndt Jul 02 '19 at 21:22
  • Did you used any encryption/hashing method before passing as credentials? If not what LDAP server instance are you using? As Apache directory service is by default storing all password as SSHA hashed value. I fear that may be the reason as well. Just need to confirm other wise. – Abhishek Sinha Jul 03 '19 at 01:55
  • No, I just used it as is. And I used your code example as is. And in the past I used it for at least 3 different LDAP server. But as you can sync the users via JMX (as I understood), the login via the Bind-DN is working. So it is not the password. I would say it is the user name, which is specified in `user.idAttribute`. This differs with each LDAP. Or you need a prefix (e.g. emea/myuser) - which happens often in large companies (if user id's are not unique across all regions or merged companies). What LDAP server you use? What is your OSGi configuration? – Alexander Berndt Jul 03 '19 at 04:49
  • I've updated with configs. Also, I meant hashing of userPassword and not the bind.password. I'm using Apache Directory studio for local setup and to create users manually – Abhishek Sinha Jul 03 '19 at 05:30
  • I just can wildly guess. 1st) Have you tried to set the password for your test user manually? Maybe the import fails. 2nd) Have you tried it with another LDAP client? 3rd) Change the bind-dn to one of your users, and try to connect. If this works, it means at least your password is set correctly. – Alexander Berndt Jul 03 '19 at 09:15
  • Can you add the following user to your ldap? It works for me. I can login in AEM, and I can authenticate with your code. # userpassword is "pass" # version: 1 dn: cn=Alexander Berndt,ou=Users,dc=example,dc=com objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson objectclass: top cn: Alexander Berndt description: This is a test givenname: Alexander sn: Berndt uid: aberndt mail: aberndt@example.com userpassword: {SHA}nU4eI71bcnBGqeO0t9tXvY1u5oQ= – Alexander Berndt Jul 03 '19 at 09:16
  • The above should be an ldif file, but the comments destroy the formatting. I think you will get it. – Alexander Berndt Jul 03 '19 at 09:17
  • Btw. I imported you LDIF file, and I cannot authenticate these users too. So the error is the strange user. If I create one manually, it works. – Alexander Berndt Jul 03 '19 at 10:19
  • This one works (reformat the file to an ldif again, password = "pass") – Alexander Berndt Jul 03 '19 at 10:21
  • version: 1 dn: cn=Ronaldo2,ou=Users,dc=example,dc=com objectClass: uidObject objectClass: person objectClass: top cn: Ronaldo2 sn: Ronaldo uid: christiano2 userPassword: {SHA256}10/w7o2juYBrGMh32/KbveULW9jk2tejpyUAD+uC6PE= – Alexander Berndt Jul 03 '19 at 10:21
  • RESOLVED!! Issue was regarding the user creation method in Apache directory studio. If we create a user and provide any attribute in addition to 'cn', dn is created as - dn: cn=eden+sn=hazard+uid=eden,ou=Users,dc=example,dc=com i.e. '+' separated attributes but if we create user with just 'cn' and add other attibutes later, it works. That's why you were able to authenticate your users and mine users were failing authentication. https://helpx.adobe.com/experience-manager/using/configuring-aem6-apache-directory-service.html - AEM documentaion that I used is NOT helpful – Abhishek Sinha Jul 03 '19 at 12:23
  • IMPORTANT for future references- Another sample user:- dn: cn=cristian,ou=Users,dc=example,dc=com objectClass: uidObject objectClass: person objectClass: top cn: cristian sn: bale uid: cristian userPassword: {SSHA}QSOFZWViatL5u5gT8vFCw1zIrWkRHJgrZ8BiEw== Thanks Alex for your help. – Abhishek Sinha Jul 03 '19 at 12:24
  • Actually I read your question wrongly in the beginning. If you only want to authenticate programmatically, you don't need the ExternalLoginModuleFactory and the DefaultSyncHandler. You need that only if the users shall be imported as AEM users (e.g. for closed-user-groups or user-generated-content) or to log-in in AEM (e.g. as content-authors). A pure authenticate works without, and it is a security issue, if you don't need it. – Alexander Berndt Jul 03 '19 at 12:34
  • I've refered [https://helpx.adobe.com/experience-manager/using/oak-login.html] . Please check 'login()' method line 198 'externalUser = idp.authenticate(credentials); ' – Abhishek Sinha Jul 03 '19 at 12:48