2
votes

I'm working with Symfony 2.8.2, Doctrine.

I need to create users in my app data base, but first I need to check if those users exist on a external Active Directory database. Only if the user exist it will possible to create the user on the app data base. My code works for creat users, but now I'm trying to implementate the "check if the user exist first" section, I'm following some examples but I'm not sure if the way I'm doing it goes well. I've read that the usual sequence with LDAP is connect, bind, search, interpret search result, close connection. Could someone give me a hint on what should I do with my code, where should I do the search first, before or after the bind? and why.

public function createAction(Request $request){
    $em = $this->getDoctrine()->getManager();
    $post_send = $request->request->get('userbundle_user');

    if (array_key_exists('id', $post_send)) {
        $ldap_success = true;
        $entity = $em->getRepository('UserBundle:User')->find($post_send['id']);
    }else{
        $ldapconn = ldap_connect("10.0.0.230");
        $Pass= "XXXXXX";
        $searchUser = "YYYYYY";
        $ldap_success = false;
        if (@ldap_bind($ldapconn, $searchUser, $Pass)) {
            try{
                $post_send['password'] = $Pass;
                $attributes = ['cn'];
                $filter = "(&(objectClass=user)(objectCategory=person)(userPrincipalName=".ldap_escape($post_send['username'], null, LDAP_ESCAPE_FILTER)."))";
                $baseDn = "DC=XXX,DC=XX,DC=cl";
                $results = @ldap_search($ldapconn, $baseDn, $filter);
                //$info = @ldap_get_entries($ldapconn, $results);
                if ( $results ) {
                    $ldap_success = true;
                } else {
                    $ldap_success = false;//false, lo deje en true para que pudiera avanzar
                }
            }
            catch(\Exception $e){
                $ldap_success = false;
            }
        }
        $entity = new User();
    }

    if( $ldap_success ){
        $entity->setUsername($post_send['username']);
        $entity->setRut($post_send['rut']);
        //$entity->setSalt("ssss");
        if (array_key_exists('password', $post_send)) {
            if ( $post_send['password'] != "" ) {
                $entity->setPassword($post_send['password']);
                $this->setSecurePassword($entity);
            }
        }
        $entity->setEmail($post_send['email']);
        $entity->setDateAdded(new \DateTime());
        $entity->setIsActive(true);
        $entity->setIsAdmin(true);
        $entity->setUserRoles($em->getRepository('UserBundle:Role')->find( $post_send['admin_roles_id'] ));
        $entity->setWizardCompleted(true);
        $entity->setPath("s");
        $em->persist($entity);
        $em->flush();
        $json = new JsonUtils();
        return $json->arrayToJson(array("id"=>$entity->getId()));
    }
    return $json->arrayToJson( array("sueccess"=>false ) );
}

There's a question here How do I make a ldap search with anonymous binding? related yo my problem, with no answers at all.

1
Are the $post_send['username'] and $post_send['password'] credentials for the user that is logging into the site? If that case all you really need to do is verify if a ldap_bind() works. You could also use the builtin LDAP component or a bundle like LdapTools. - ChadSikorra
No, are new parameters, they are from a "Create new User" form. But the binding is working ok. Till now I wasn't verificating if the user that I want to create exist in AD, but I was using the bind while login to the system. - pmiranda
Ok, I understand it now. I didn't realize this was in the controller. Whoops. I think what you really need is a LDAP service account that is only a member of the "Domain Users" group (thus having read-only access). Then you could use that account's username/password to bind and query to see if the username they're attempting to create in the form actually exists in AD. - ChadSikorra

1 Answers

2
votes

Regarding your AD query to check if the user exists (starting at the beginning of your else statement), I would make the logic something like this:

$ldapconn = ldap_connect("10.0.0.230");
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0)
// Use a LDAP service account with only read access...
$searchUser = '[email protected]';
$searchPass = '12345';

$ldap_success = false;
if (@ldap_bind($ldapconn, $searchUser, $searchPass)) {
    $attributes = ['cn'];
    $filter = "(&(objectClass=user)(objectCategory=person)(userPrincipalName=".ldap_escape($post_send['username'], null, LDAP_ESCAPE_FILTER)."))";
    $baseDn = "DC=myDomain,DC=com";
    $results = @ldap_search($ldapconn, $baseDn, $filter, $attributes);
    $info = @ldap_get_entries($ldapconn, $results);

    $ldap_success = ($info && $info['count'] === 1);
}

In that case $ldap_success would only be true if a user exists in AD with the UPN specified.

However, if you are requiring the user's password and binding to AD, then there is no reason to also verify that the user can be found via a query after binding. In that case simply binding to AD is evidence enough that they exist in AD.