LDAP inappropriate authentication

Hello,
i use X-Pack 6.1 and configure a LDAP access, but i get: LDAPException(resultCode=48 (inappropriate authentication), but a ldapsearch with same config works fine.
Does elasticsearch requests the ldap server in a different manner like ldapsearch?

ldapsearch request:

[elasticsearch@server ~]$ ldapsearch -h host -p port -x -s sub -D "cn=binduser,ou=yyy,o=zzz" -w password -b "ou=www,ou=yyy,o=zzz" "uid=myuser"
# extended LDIF
#
# LDAPv3
# base <ou=www,ou=yyy,o=zzz> with scope subtree
# filter: uid=myuser
# requesting: ALL
#

# myuser, www, yyy, zzz
dn: uid=myuser,ou=www,ou=yyy,o=zzz
...

my role mapping:

[elasticsearch@server ~]$ vi config/x-pack/role_mapping.yml
superuser:
  - "uid=myuser,ou=www,ou=yyy,o=zzz"

ldap config:

[elasticsearch@server ~]$ vi config/elasticsearch.yml  
xpack.security.authc.realms:
  native:
    type: native
    order: 0
  ldap_test:
    type: ldap
    order: 1
    url: "ldap://host:port"
    bind_dn: "cn=binduser,ou=yyy,o=zzz"
    bind_password: "password"
    user_search:
      base_dn: "ou=www,ou=yyy,o=zzz"
xpack.security.audit:
  enabled: true
  index.events.exclude:
  - access_granted
  logfile.events.exclude:
  - access_granted
  outputs:
  - index
  - logfile

try to access with ldap user:

[elasticsearch@server ~]$ curl -u myuser 'http://localhost:9201/_xpack/security/_authenticate?pretty'
Enter host password for user 'myuser':
{
  "error" : {
    "root_cause" : [
      {
        "type" : "security_exception",
        "reason" : "unable to authenticate user [myuser] for REST request [/_xpack/security/_authenticate?pretty]",
        "header" : {
          "WWW-Authenticate" : "Basic realm=\"security\" charset=\"UTF-8\""
        }
      }
    ],
    "type" : "security_exception",
    "reason" : "unable to authenticate user [myuser] for REST request [/_xpack/security/_authenticate?pretty]",
    "header" : {
      "WWW-Authenticate" : "Basic realm=\"security\" charset=\"UTF-8\""
    }
  },
  "status" : 401
}

logs:

[elasticsearch@server ~]$ less logs/elasticsearch.log
[2018-05-17T13:22:50,163][DEBUG][o.e.x.s.a.l.LdapRealm    ] [server] Exception occurred during authenticate for ldap/ldap_test
com.unboundid.ldap.sdk.LDAPBindException: inappropriate authentication
    at com.unboundid.ldap.sdk.LDAPConnection.bind(LDAPConnection.java:2171) ~[unboundid-ldapsdk-3.2.0.jar:3.2.0]
    at com.unboundid.ldap.sdk.LDAPConnectionPool.bindAndRevertAuthentication(LDAPConnectionPool.java:1535) ~[unboundid-ldapsdk-3.2.0.jar:3.2.0]
    at org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils$1.lambda$doRun$0(LdapUtils.java:135) ~[x-pack-6.1.1.jar:6.1.1]
    at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_131]
    at org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils.privilegedConnect(LdapUtils.java:86) ~[x-pack-6.1.1.jar:6.1.1]
    at org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils$1.doRun(LdapUtils.java:135) [x-pack-6.1.1.jar:6.1.1]
    at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun(ThreadContext.java:637) [elasticsearch-6.1.1.jar:6.1.1]
    at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:37) [elasticsearch-6.1.1.jar:6.1.1]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_131]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_131]
    at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]
[2018-05-17T13:22:50,164][WARN ][o.e.x.s.a.AuthenticationService] [server] Authentication to realm ldap_test failed - authenticate failed (Caused by LDAPException(resultCode=48 (inappropriate authentication), errorMessage='inappropriate authentication'))

It looks like the problem is occurring when authenticating myuser.
Are you able to do that with ldapsearch? It may be that the server does not permit the user to authenticate.

Try turning on LDAP trace logging with the following (adjusting as necessary for host/port)

curl -H "Content-Type: application/json" -XPUT -uelastic 'http://localhost:9200/_cluster/settings' -d'
{
 "transient" : {
     "logger.org.elasticsearch.xpack.security.authc.ldap" : "DEBUG"
 }
}'

That will provide more logging, and should show more about what's going on under the covers.

Hi Tim, thanks for reply. I already tried it with ldapsearch and set loglevel to DEBUG...pls see the log and console snippets in my post.

Hi Thomas,

As @TimV menitioned above, it looks like the server doesn't permit your user to authenticate, so the credentials cannot be verified.
The console snippet you share shows that you can bind as cn=binduser,ou=yyy,o=zzz and search for the user with the filter uid=myuser, but not that you can bind to ldap with that user.

Can you try ldap seach with uid=myuser,ou=www,ou=yyy,o=zzz as your bind DN (-D) ?

Now i got the same error message:

[elasticsearch@server ~]$ ldapsearch -h host -p port -x -s sub -D "uid=myuser,ou=www,ou=yyy,o=zzz" -W -b "ou=www,ou=yyy,o=zzz" "uid=myuser"
Enter LDAP Password:
ldap_bind: Inappropriate authentication (48)

...but this was to be expected, because myuser has no permission to request the ldap. Only binduser has it. I thought elasticsearch use the bind user for ldap request, get informations from ldap and use these informations for authentication?

Please note that this is the bind that fails, not the search.

Yes, but the

use the bind user for ldap request

means that Elasticsearch binds as the bind user in order to search for the authenticating user and get their DN and

use these informations for authentication?

happens as a new bind to ldap with the identified user DN and the password they provide.
This is documented in LDAP User Authentication | X-Pack for the Elastic Stack [6.2] | Elastic

You need to enable your users to bind/authenticate in your LDAP server.

Ok..it seems that i not fully understand this functioning, thanks for clarifying. But we have more than hundred users which should not have access to ldap. Is there a chance to work with only one bind user?

No, we need to bind as the user who is logging in, in order to verify their password.
If you want to use LDAP for authentication then you need to let your users bind to the directory.

Hmm, can i use ldap only for autorization, not for authentication? Means, that the binduser asks ldap for the ldap groups of myuser, which will then be mapped with ES roles?

@tommer Yes! Take a look at the run_as functionality. I think that's exactly what you need. In this case actions will be authorized using the roles ES maps to myuser by searching for the LDAP groups. Authentication can be handled by the LDAP realm as well as any other realm.

Thanks Albert. If i understant this correctly, i have to grant the "permission to submit request on behalf" of all our hundreds of users to binduser, e.g.

PUT /_xpack/security/user/binduser
{
  "run_as" : [ "myuser1", "myuser2",..., "myuser250" ]
}

Is this correct?

The run_as field accepts wildcards, so it is possible to do

"run_as" : [ "*" ]

That assumes that you want to authenticate to Elasticsearch using a single generic user, and then authorize the request using privileges derived from the LDAP user.

OK, does this mean i have to create a role with run_as functionality?

PUT /_xpack/security/role/ldap
{
  "run_as" : [ "myuser" ]
}

and create a user in native realm with same name and password as binduser in LDAP and assign the role to him?

POST /_xpack/security/user/binduser
{
  "password" : "password",
  "roles" : [ "ldap" ]
}

But after that i get an error:

curl -H "es-security-runas-user: myuser" -XGET 'localhost:9201/_xpack/security/user?pretty' -u binduser
Enter host password for user 'binduser':
{
  "error" : {
    "root_cause" : [
      {
        "type" : "security_exception",
        "reason" : "unable to authenticate user [binduser] for REST request [/_xpack/security/user?pretty]",
        "header" : {
          "WWW-Authenticate" : "Basic realm=\"security\" charset=\"UTF-8\""
        }
      }
    ],
    "type" : "security_exception",
    "reason" : "unable to authenticate user [binduser] for REST request [/_xpack/security/user?pretty]",
    "header" : {
      "WWW-Authenticate" : "Basic realm=\"security\" charset=\"UTF-8\""
    }
  },
  "status" : 401
}

OK, does this mean i have to create a role with run_as functionality?

Sorry, I didn't notice this in your previous post.
Privileges (including run_as) are always set on roles, not users.

Just to check, you're entering the "binduser" password here, correct? (not "myuser")

Is the native realm enabled? It was in your original elasticsearch.yml, but this error suggests maybe it isn't.

Yes, i entered the bindusers password and the elasticsearch.yml is the same as above.
Is it correctly, that the binduser now has to be defined twice, in native realm and in ldap? I created the binduser in native realm with same password as in ldap.

No, it only needs to be define once, in a realm that allows it to authenticate. That can be native or LDAP, as long as it has a password that you can use to login.

If you use LDAP then you will need to use a Role Mapping to grant the ldap role you created.

unable to authenticate user [binduser] for REST request

This is definitely a password problem, and it's hard to offer much advice in a forum like this.
Can you triple-check that you created the user with the same password as you are entering into curl?

If that's not the problem, then we'll need to turn on debug logging for the native realm.

curl -H "Content-Type: application/json" -XPUT -uelastic 'http://localhost:9200/_cluster/settings' -d'
{
 "transient" : {
     "logger.org.elasticsearch.xpack.security.authc.esnative" : "DEBUG"
 }
}'

I mapped the ldap role to the binduser in role_mapping.yml:

ldap:
  - "cn=binduser,ou=yyy,o=zzz"

Then i deleted the binduser from native realm. Now he is defined in ldap only. Additionally i sent the curl with his password:

curl -H "es-security-runas-user: myuser" -XGET 'localhost:9201/_xpack/security/user?pretty' -u binduser:password

and get the same error:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "security_exception",
        "reason" : "unable to authenticate user [binduser] for REST request [/_xpack/security/user?pretty]",
        "header" : {
          "WWW-Authenticate" : "Basic realm=\"security\" charset=\"UTF-8\""
        }
      }
    ],
    "type" : "security_exception",
    "reason" : "unable to authenticate user [binduser] for REST request [/_xpack/security/user?pretty]",
    "header" : {
      "WWW-Authenticate" : "Basic realm=\"security\" charset=\"UTF-8\""
    }
  },
  "status" : 401
}

I turned on debug logging, but the logs shows only:

[2018-05-29T13:05:41,369] [rest] [authentication_failed]        origin_address=[127.0.0.1], principal=[binduser], uri=[/_xpack/security/user?pretty]"

Does elasticsearch do the ldap bind in another way like ldapsearch?
Does elasticsearch support a bind with a bind_dn "cn=binduser,..." or only with "uid=binduser,..."?
How can i direct check if the bind to ldap with the binduser works?

@tommer I think you're on the right path. I still think the current obstacle is about LDAP authn. Use this to debug all LDAP stuff:

curl -H “Content-Type: application/json” -XPUT -uelastic ‘http://localhost:9200/_cluster/settings' -d’
{
“transient” : {
    “logger.org.elasticsearch.xpack.security.authc.ldap” : “DEBUG”
}
}'

How can i direct check if the bind to ldap with the binduser works?

Use:

ldapsearch -h host -p port -x -s sub -D “cn=binduser,ou=yyy,o=zzz” -w password -b “ou=www,ou=yyy,o=zzz” “uid=myuser” 

and correlate with the logs after turning logging to DEBUG.

Cheers!

Thanks, but I have already done both things, see above. I mean, how can i direct check with ES if the bind to ldap with the binduser works?