3 Replies
      Latest reply: Dec 23, 2016 1:44 AM by eskimo RSS
      ninad.apple Level 1 Level 1 (0 points)

        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

        • Re: How to bind and query LDAP server without specifying user credentials
          eskimo Apple Staff Apple Staff (7,005 points)

          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);
              }
          }
          
            • Re: How to bind and query LDAP server without specifying user credentials
              ninad.apple Level 1 Level 1 (0 points)

              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

                • Re: How to bind and query LDAP server without specifying user credentials
                  eskimo Apple Staff Apple Staff (7,005 points)

                  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"