How to bind and query LDAP server without specifying user credentials

Currently my Mac has been successfully configured to be in Active Directory Domain. (System Preferences -> Users & Groups -> Login Options -> Network Account Server)


We are developing a Mac application that has following requirements:

  1. It should communicate with the LDAP server in Active Directory Domain and retrieve users & their attributes from LDAP server.
  2. While communicating (bind or search) with the LDAP server, we are not allowed to explicitly specify logged-in user's credentials. (e.g. we should not prompt username / password screen to the user)

If we explicitly specify logged-in user's credentials,

  • we are able to bind to the LDAP server
  • we are able to search the users & their attributes in LDAP server

If we do not specify logged-in user's credentials,

  • we are able to bind to the LDAP server
  • but it does not allow us to search the users & their attributes in LDAP server

Is there a way with which we can use logged-in user's credentials implicitly while communicating with the LDAP server?

Can you please guide us how we can query LDAP server (search users & their attributes in LDAP server) without specifying logged-in user's credentials explicitly.


Any kind of help is highly appreciable.


Thanks

Replies

Currently my Mac has been successfully configured to be in Active Directory Domain. (System Preferences -> Users & Groups -> Login Options -> Network Account Server)

If your Mac is bound to the Active Directory server then you shouldn’t need LDAP to search for users and their attributes. Rather, you can get this information using the Open Directory framework. Pasted in below is some code I had lying around that searches for a user and prints their attributes.

IMPORTANT You have to pass in an ODNode here; in this case you should create one by calling

+nodeWithSession:type:error:
, with the node type being
kODNodeTypeAuthentication
.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
static NSString * RecordAttributeValueString(id<NSObject> value) {
    NSString *  result;

    if ([value isKindOfClass:[NSString class]]) {
        result = [NSString stringWithFormat:@"'%@'", value];    // +++ should escape quotes
    } else if ([value isKindOfClass:[NSData class]]) {
        result = value.description;                            // +++ should use QHex
    } else {
        result = value.description;
    }
    return result;
}

static void PrintRecordAttribute(ODRecord * record, ODAttributeType attribute) {
    NSError *  error;
    NSArray *  values;

    values = [record valuesForAttribute:attribute error:&error];
    if (values == nil) {
        fprintf(stderr, "  %s: %s / %d\n", attribute.UTF8String, error.domain.UTF8String, (int) error.code);
    } else if (values.count == 0) {
        fprintf(stderr, "  %s: []\n", attribute.UTF8String);
    } else if (values.count == 1) {
        fprintf(stderr, "  %s: %s\n", attribute.UTF8String, RecordAttributeValueString(values[0]).UTF8String);
    } else {
        NSMutableArray *  valueStrings;

        valueStrings = [[NSMutableArray alloc] init];
        for (id<NSObject> value in values) {
            [valueStrings addObject:RecordAttributeValueString(value)];
        }
        fprintf(stderr, "  %s: [%s]\n", attribute.UTF8String, [valueStrings componentsJoinedByString:@","].UTF8String);
    }
}

static void PrintRecords(NSArray * records) {
    [records enumerateObjectsUsingBlock:^(ODRecord * record, NSUInteger idx, BOOL *stop) {
        #pragma unused(stop)
        assert([record isKindOfClass:[ODRecord class]]);
        fprintf(stderr, "%zu:\n", (size_t) idx);
        PrintRecordAttribute(record, kODAttributeTypeMetaNodeLocation);
        PrintRecordAttribute(record, kODAttributeTypeFullName);
        PrintRecordAttribute(record, kODAttributeTypeRecordName);
        PrintRecordAttribute(record, kODAttributeTypeUniqueID);
    }];
}

static void PrintUserListInNode(ODNode * node, NSString * userName) {
    NSError *  error;
    ODQuery *  query;
    NSArray *  desiredAttributes;
    NSArray *  records;

    desiredAttributes = @[
        kODAttributeTypeMetaNodeLocation,
        kODAttributeTypeFullName,
        kODAttributeTypeRecordName,
        kODAttributeTypeUniqueID
    ];

    query = [ODQuery queryWithNode:node
        forRecordTypes:    kODRecordTypeUsers
        attribute:          kODAttributeTypeMetaAmbiguousName
        matchType:          kODMatchEqualTo
        queryValues:        userName
        returnAttributes:  desiredAttributes
        maximumResults:    0
        error:              NULL
    ];
    assert(query != nil);

    records = [query resultsAllowingPartial:NO error:&error];
    if (records == nil) {
        fprintf(stderr, "%s: query failed: %s / %d\n", userName.UTF8String, error.domain.UTF8String, (int) error.code);
    } else {
        PrintRecords(records);
    }
}

Thanks Eskimo for the detailed information.


We are currently using OpenLDAP framework for LDAP operations.

Do you have any idea how we can achieve this in OpenLDAP framework?


Thanks

We are currently using OpenLDAP framework for LDAP operations.

Why? It seems like you’re using a low-level API when it would be easier to achieve your goạl using a high-level one.

Do you have any idea how we can achieve this in OpenLDAP framework?

No. To start, OpenLDAP is not an API that DTS supports, so I don’t have a lot of experience with it. More to the point, however, it sounds like this is an actual security restriction on the Active Directory server itself; that is, it gives less access to LDAP clients than it does to the AD client on machines that are bound to the AD server. If that’s the case no amount of tweaking on the client is going to help.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"