Node-ldapjs: Issue reading thumbnailPhoto from LDAP

Created on 8 Jun 2013  路  5Comments  路  Source: ldapjs/node-ldapjs

Hi,

I am using the following code to extract the thumbnail photo of a user from LDAP:

var ldap = require('ldapjs');
var fs = require('fs');

var client = ldap.createClient({
url: 'ldap://someip:389'
});

var user = "someuser"

var opts = {
filter: '(sAMAccountName='+user+')',
scope: 'sub'
};

client.search('OU=someou,DC=somedc,DC=com', opts, function(err, res) {
//assert.ifError(err);

res.on('searchEntry', function(entry) {
var info = entry.object;
console.log('entry: ' + info.dn);
console.log('entry: ' + info.sn);
console.log('entry: ' + info.givenName);
console.log('entry: ' + info.title);
console.log('entry: ' + info.memberOf);
console.log('entry: ' + info.co);
console.log('entry: ' + info.manager);
console.log('entry: ' + info.mail);
fs.writeFile("./public/images/photos/"+user+"Thumb.jpg", info.thumbnailPhoto, function(err) {
if(err) {
console.log("errror writing thumbnail: "+err);
} else {
console.log("thumbnail was saved!");
}
});
//...

As it is it fails to write a proper image as it transforms some of the bytes to something else. Can someone help?
For example, the first 4 bytes get transform from:
ffd8 ffe0
to
efbf bdef bfbd efbf bdef bfbd

Thanks.

Most helpful comment

The problem is that the attribute values are converted from buffers to strings, and ldapjs does not know that the thumbnail is really binary.
Here is a function which works similar as entry.object in the example above, but returns the original buffers instead of the strings for all attributes except for dn and controls (the code is adapted from lib/messages/search_entry.js from the getter of object)

function _convert(entry) {
    var obj = {
      dn: entry.dn.toString(),
      controls: []
    };
    entry.attributes.forEach(function (a) {
      var item = a.buffers;
      if (item && item.length) {
        if (item.length > 1) {
          obj[a.type] = item.slice();
        } else {
          obj[a.type] = item[0];
        }
      } else {
        obj[a.type] = [];
      }
    });
    entry.controls.forEach(function (element, index, array) {
      obj.controls.push(element.json);
    });
    return obj;
  }

You can use entry.object for the non-binary properties and the result of this function for the binary properties. I hope this helps.

All 5 comments

The problem is that the attribute values are converted from buffers to strings, and ldapjs does not know that the thumbnail is really binary.
Here is a function which works similar as entry.object in the example above, but returns the original buffers instead of the strings for all attributes except for dn and controls (the code is adapted from lib/messages/search_entry.js from the getter of object)

function _convert(entry) {
    var obj = {
      dn: entry.dn.toString(),
      controls: []
    };
    entry.attributes.forEach(function (a) {
      var item = a.buffers;
      if (item && item.length) {
        if (item.length > 1) {
          obj[a.type] = item.slice();
        } else {
          obj[a.type] = item[0];
        }
      } else {
        obj[a.type] = [];
      }
    });
    entry.controls.forEach(function (element, index, array) {
      obj.controls.push(element.json);
    });
    return obj;
  }

You can use entry.object for the non-binary properties and the result of this function for the binary properties. I hope this helps.

Thanks a lot! It worked.
I changed a bit the function you provided as I saw that the SearchEntry.object getter was almost the same, only using vals instead of buffers. My version only checks for thumbnailPhoto field to be object, not string:

function getProperObject(entry) {
  var obj = {
    dn: entry.dn.toString(),
    controls: []
  };
  entry.attributes.forEach(function (a) {
    var buf = a.buffers;
    var val = a.vals;
    var item;
    if ( a.type == 'thumbnailPhoto' )
      item = buf;
    else
      item = val;
    if (item && item.length) {
      if (item.length > 1) {
        obj[a.type] = item.slice();
      } else {
        obj[a.type] = item[0];
      }
    } else {
      obj[a.type] = [];
    }
  });
  entry.controls.forEach(function (element, index, array) {
    obj.controls.push(element.json);
  });
  return obj;
}

Thanks again!

Searched for a good deal of time on how to solve this before I found this which worked. Thanks!

Why is this issue closed but not resolved? I struggled with the same issue. Thanks @emueller-sage and @lmusat for a solution.

That issue should really be reopend until its resolved.

Out of Curiosity tho

how could you access _vals via buffers?

As I see, the attribute value a is this

Attribute { type: 'displayName', _vals: [ ] }
[ ]

Was this page helpful?
0 / 5 - 0 ratings

Related issues

phi1ipp picture phi1ipp  路  4Comments

regulatre picture regulatre  路  9Comments

JohnPolansky picture JohnPolansky  路  3Comments

jjayaraman picture jjayaraman  路  5Comments

jvanalst picture jvanalst  路  6Comments