Search code examples
authenticationzend-frameworkldap

Zend Ldap allow only if user has a certain Group


What I want to achieve:

  • there are two different group
  • administration
  • readonly

I want to be able to authenticate a user and assign a role depending on which group he belongs to.

What I've tried:

Given the official docs I've set up two "servers" with different group options to authenticate:

ldap.admin.host = myhost
ldap.admin.port = myport
ldap.admin.useStartTls = true
ldap.admin.useSsl = true
ldap.admin.username = "cn=ama,ou=LDAPAuth,dc=mydc,dc=de"
ldap.admin.password = "mypass"
ldap.admin.accountFilterFormat = "cn=%s"
ldap.admin.baseDn = "dc=mydc,dc=de"
ldap.admin.bindRequiresDn = true
ldap.admin.group = "ama"
ldap.admin.groupDn = "cn=ama,ou=groups,dc=mydc,dc=de"
ldap.admin.groupAttr = "cn"
ldap.admin.groupFilter = "objectClass=groupOfNames"
ldap.admin.memberAttr = "member"

ldap.readonly.host = myhost
ldap.readonly.port = myport
ldap.readonly.useStartTls = true
ldap.readonly.useSsl = true
ldap.readonly.username = "cn=ama,ou=LDAPAuth,dc=mydc,dc=de"
ldap.readonly.password = "mypass"
ldap.readonly.accountFilterFormat = "cn=%s"
ldap.readonly.baseDn = "dc=mydc,dc=de"
ldap.readonly.bindRequiresDn = true
ldap.readonly.group = "ama_ro"
ldap.readonly.groupDn = "cn=ama_ro,ou=groups,dc=mydc,dc=de"
ldap.readonly.groupAttr = "cn"
ldap.readonly.groupFilter = "objectClass=groupOfNames"
ldap.readonly.memberAttr = "member"

Now the official docs say, that if the authentication against the first server fails, it will try to do so against the second one. However, That doesn't seem to be the case with my authentication script.

I got three test accounts, one without group, two with each one of them. If I use only one of the options, it works for the user it should, all others get access denied, just as I want.

But I just can't seem to be able to implement the "fluid check".

Furthermore: even if the 'fluid check' would work, I don't really understand how I would find out, against which group the user was able to authenticate.

To my understanding I would need to manually query against the server after I get a positive authentication to read the groups of the user - is this correct? If so, I have found the following question here on this site: Query all groups of a user using Zend_Ldap That however doesn't seem to work for me, because I only get empty arrays or errors, depending on what I try :(


Solution

  • Now the official docs say, that if the authentication against the first server fails, it will try to do so against the second one. However, That doesn't seem to be the case with my authentication script.

    The behaviour you describe was introduced as a solution to bug ZF-409. In order to get it to work as you want just set different accountDomainName (or accountDomainNameShort) in your 2 LDAP server options:

    ldap.admin.accountDomainName      = admin.domain
    ldap.admin.accountDomainNameShort = admin
    
    ldap.readonly.accountDomainName      = readonly.domain
    ldap.readonly.accountDomainNameShort = readonly
    

    If you login using a "readonly" valid user, it will fail to login in as admin but it will login in as readonly. The Zend_Auth_Result will be something like:

    object(Zend_Auth_Result)#159 (3) {
      ["_code":protected] => int(1)
      ["_identity":protected] => string(26) "readonly\username"
      ["_messages":protected] => array(6) {
        [0] => string(0) ""
        [1] => string(0) ""
        [2] => string(312) "host=host,useSsl=1,accountDomainName=admin.domain,accountDomainNameShort=admin,accountCanonicalForm=3,baseDn=dc=mydc,dc=de,bindRequiresDn=1,useStartTls=1,group=ama_ro,groupDn=cn=ama_ro,ou=groups,dc=mydc,dc=de,groupAttr=cn,groupFilter=objectClass=groupOfNames,memberAttr=member"
        [3] => string(142) "Failed to verify group membership with (&(&(cn=admin)(member=youruserDN))(yourfilter))"
        [4] => string(310) "host=host,useSsl=1,accountDomainName=readonly.domain,accountDomainNameShort=readonly,accountCanonicalForm=3,baseDn=dc=mydc,dc=de,bindRequiresDn=1,useStartTls=1,group=ama_ro,groupDn=cn=ama_ro,ou=groups,dc=mydc,dc=de,groupAttr=cn,groupFilter=objectClass=groupOfNames,memberAttr=member"
        [5] => string(52) "readonly\username authentication successful"
      }
    }
    

    After you get a $login->isValid() just perform $login->getIdentity() and you'll get the accountDomainNameShort value along with username provided.