Skip to content

Instantly share code, notes, and snippets.

@t2ym
Last active June 15, 2021 07:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save t2ym/9b80d6c41a99f3dee6136751b463e90d to your computer and use it in GitHub Desktop.
Save t2ym/9b80d6c41a99f3dee6136751b463e90d to your computer and use it in GitHub Desktop.
Git patch to nghttp2-v1.43.0 to add const SSL *nghttp2::asio_http2::server::request::ssl() to associate client certificates with requests
diff --git a/src/asio_server.cc b/src/asio_server.cc
index 74c92276..5a79061e 100644
--- a/src/asio_server.cc
+++ b/src/asio_server.cc
@@ -154,7 +154,7 @@ void server::start_accept(boost::asio::ssl::context &tls_context,
return;
}
- new_connection->start();
+ new_connection->start(new_connection->socket().native_handle());
});
}
diff --git a/src/asio_server_connection.h b/src/asio_server_connection.h
index daf9a664..c9570c04 100644
--- a/src/asio_server_connection.h
+++ b/src/asio_server_connection.h
@@ -85,12 +85,15 @@ public:
stopped_(false) {}
/// Start the first asynchronous operation for the connection.
- void start() {
+ void start(SSL *ssl = nullptr) {
boost::system::error_code ec;
handler_ = std::make_shared<http2_handler>(
GET_IO_SERVICE(socket_), socket_.lowest_layer().remote_endpoint(ec),
[this]() { do_write(); }, mux_);
+ if (ssl) {
+ handler_->ssl(ssl);
+ }
if (handler_->start() != 0) {
stop();
return;
diff --git a/src/asio_server_http2_handler.cc b/src/asio_server_http2_handler.cc
index c1fc195f..78186bd7 100644
--- a/src/asio_server_http2_handler.cc
+++ b/src/asio_server_http2_handler.cc
@@ -241,6 +241,7 @@ http2_handler::http2_handler(boost::asio::io_service &io_service,
mux_(mux),
io_service_(io_service),
remote_ep_(ep),
+ ssl_(nullptr),
session_(nullptr),
buf_(nullptr),
buflen_(0),
@@ -484,6 +485,14 @@ const boost::asio::ip::tcp::endpoint &http2_handler::remote_endpoint() {
return remote_ep_;
}
+const SSL *http2_handler::ssl() const {
+ return ssl_;
+}
+
+void http2_handler::ssl(SSL *ssl) {
+ ssl_ = ssl;
+}
+
callback_guard::callback_guard(http2_handler &h) : handler(h) {
handler.enter_callback();
}
diff --git a/src/asio_server_http2_handler.h b/src/asio_server_http2_handler.h
index 12064499..7bf5cf43 100644
--- a/src/asio_server_http2_handler.h
+++ b/src/asio_server_http2_handler.h
@@ -92,6 +92,9 @@ public:
const boost::asio::ip::tcp::endpoint &remote_endpoint();
+ const SSL *ssl() const;
+ void ssl(SSL *ssl);
+
const std::string &http_date();
template <size_t N>
@@ -156,6 +159,7 @@ private:
serve_mux &mux_;
boost::asio::io_service &io_service_;
boost::asio::ip::tcp::endpoint remote_ep_;
+ SSL *ssl_;
nghttp2_session *session_;
const uint8_t *buf_;
std::size_t buflen_;
diff --git a/src/asio_server_request.cc b/src/asio_server_request.cc
index 36669a52..8083a516 100644
--- a/src/asio_server_request.cc
+++ b/src/asio_server_request.cc
@@ -54,6 +54,10 @@ const boost::asio::ip::tcp::endpoint &request::remote_endpoint() const {
return impl_->remote_endpoint();
}
+const SSL *request::ssl() const {
+ return impl_->ssl();
+}
+
} // namespace server
} // namespace asio_http2
} // namespace nghttp2
diff --git a/src/asio_server_request_impl.cc b/src/asio_server_request_impl.cc
index 8442ad05..5cc6ab78 100644
--- a/src/asio_server_request_impl.cc
+++ b/src/asio_server_request_impl.cc
@@ -62,6 +62,14 @@ void request_impl::remote_endpoint(boost::asio::ip::tcp::endpoint ep) {
remote_ep_ = std::move(ep);
}
+const SSL *request_impl::ssl() const {
+ return ssl_;
+}
+
+void request_impl::ssl(const SSL *ssl) {
+ ssl_ = ssl;
+}
+
size_t request_impl::header_buffer_size() const { return header_buffer_size_; }
void request_impl::update_header_buffer_size(size_t len) {
diff --git a/src/asio_server_request_impl.h b/src/asio_server_request_impl.h
index 05de98a8..3f29299d 100644
--- a/src/asio_server_request_impl.h
+++ b/src/asio_server_request_impl.h
@@ -58,6 +58,9 @@ public:
const boost::asio::ip::tcp::endpoint &remote_endpoint() const;
void remote_endpoint(boost::asio::ip::tcp::endpoint ep);
+ const SSL *ssl() const;
+ void ssl(const SSL *ssl);
+
size_t header_buffer_size() const;
void update_header_buffer_size(size_t len);
@@ -68,6 +71,7 @@ private:
uri_ref uri_;
data_cb on_data_cb_;
boost::asio::ip::tcp::endpoint remote_ep_;
+ const SSL *ssl_;
size_t header_buffer_size_;
};
diff --git a/src/asio_server_stream.cc b/src/asio_server_stream.cc
index f763c1e0..05ba88e5 100644
--- a/src/asio_server_stream.cc
+++ b/src/asio_server_stream.cc
@@ -35,6 +35,7 @@ namespace server {
stream::stream(http2_handler *h, int32_t stream_id)
: handler_(h), stream_id_(stream_id) {
request_.impl().stream(this);
+ request_.impl().ssl(h->ssl());
response_.impl().stream(this);
}
diff --git a/src/includes/nghttp2/asio_http2_server.h b/src/includes/nghttp2/asio_http2_server.h
index d4ec489a..ae6cb65d 100644
--- a/src/includes/nghttp2/asio_http2_server.h
+++ b/src/includes/nghttp2/asio_http2_server.h
@@ -62,6 +62,8 @@ public:
// Returns the remote endpoint of the request
const boost::asio::ip::tcp::endpoint &remote_endpoint() const;
+ const SSL *ssl() const;
+
private:
std::unique_ptr<request_impl> impl_;
};
@t2ym
Copy link
Author

t2ym commented May 2, 2021

How to apply the patch to GitHub workspace

curl -L -O https://gist.githubusercontent.com/t2ym/9b80d6c41a99f3dee6136751b463e90d/raw/fbcec89ff54f911a9f8fc7e0bbb1d0b5463ecc38/nghttp2-v1.43.0-ssl.patch
git clone -b v1.43.0 https://github.com/nghttp2/nghttp2
cd nghttp2
git apply ../nghttp2-v1.43.0-ssl.patch
git diff

@t2ym
Copy link
Author

t2ym commented May 2, 2021

How to notify clients of client certificate requests in SSL/TLS handshaking

boost::system::error_code ec;
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
tls.use_private_key_file(path_to_private_key_pem, boost::asio::ssl::context::pem);
tls.use_certificate_chain_file(path_to_certificate_chain_file);

nghttp2::asio_http2::server::configure_tls_context_easy(ec, tls);

// enable client certificate authentication
tls.set_verify_mode(
  boost::asio::ssl::verify_peer |
  boost::asio::ssl::verify_client_once |
  boost::asio::ssl::verify_fail_if_no_peer_cert
);

// before server.listen_and_serve(ec, tls, addr, port, true)

@t2ym
Copy link
Author

t2ym commented May 2, 2021

How to configure client certificate verification

These APIs do not require the patch themselves

Load trusted CA

  • Unlike openssl s_client, major browsers do NOT send intermediate CA certificates and an issuer certificate with a client certificate. Therefore, the server must be configured with a trusted chain of CA certificates including the direct issuer certificate. If only client certificates issued by a specific issuer must be authenticated, configuring all the chained certificates may have an unexpected side-effect that client certificates issued directly by another intermediate CA certificate in the chain can be authenticated as well while such a twisted issueing scheme is not recommended. In addition, if a customized browser or any custom client sends the whole chain like openssl s_client, the client will be naturally authenticated. Such behaviors do not breach any chain of trust. To restrict direct issuers, DIRECT ISSUERS (=depth 1) MUST BE AUTHENTICATED in the verification callback. Please wait for updates.
    • Option to be verified # 1: Trust ONLY direct issuers and omit intermediate and root CA certificates, which may be rejected by openssl because issuers of the direct issuers are missing.
tls.add_certificate_authority(const boost::asio::const_buffer& ca);
tls.add_verify_path(const std::string& path, boost::system::error_code& ec);
tls.load_verify_file(const std::string& filename, boost::system::error_code& ec);

Register a certificate verification callback

Note: This verification CANNOT associate certificates with HTTPS requests, which is the motivation of the patch

WARNING: This callback is still in progress and has a serious issue that preverified is interpreted in an opposite meaning and a chain of trust is not handled. Please wait for updates.

tls.set_verify_callback([](bool preverified, boost::asio::ssl::verify_context &ctx)->bool {
  // just dumping certificate information and pass all the verification but the default one performed before the call
  std::cerr << "verify_callback: " << "preverified = " << preverified << std::endl;
  uint8_t digest[EVP_MAX_MD_SIZE];
  unsigned int digest_length;

  X509 *certificate = X509_STORE_CTX_get_current_cert(ctx.native_handle());
  if (!certificate) {
    std::cerr << "verify_callback: " << "failed to get certificate from X509_STORE_CTX" << std::endl;
    return false;
  }

  BIO *out;
  char *subject_ptr;
  out = BIO_new(BIO_s_mem());
  X509_NAME_print_ex(out, X509_get_subject_name(certificate), 0, XN_FLAG_RFC2253);
  int n = BIO_get_mem_data(out, &subject_ptr);
  std::string subject(subject_ptr, n);
  subject_ptr = nullptr;
  BIO_free(out);
  out = nullptr;

  std::cerr << "verify_callback: X509_get_subject_name() = " << subject << std::endl;

  int error_depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());
  std::cerr << "verify_callback: X509_STORE_CTX_get_error_depth() = " << error_depth << std::endl;

  bool success = X509_digest(certificate, EVP_sha256(), digest, &digest_length);

  std::ostringstream oss;

  for (unsigned int i = 0; i < digest_length; i++) {
    if (i > 0) {
      oss << ":";
    }
    oss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex << (unsigned int)digest[i];
  }

  std::string fingerprint = oss.str();

  // openssl pkcs12 -in path/to/client_cert.(pfx|p12) -nodes -passin pass:<cert password> | openssl x509 -sha256 -noout -fingerprint
  // SHA256 Fingerprint=12:34:56:XX:...:XX
  std::cerr << "SHA256 Fingerprint=" << fingerprint << std::endl;
  return !preverified; // THIS IS A SERIOUS BUG!!! PLEASE WAIT FOR UPDATES.
});

@t2ym
Copy link
Author

t2ym commented May 2, 2021

Sample nicexprs.h middleware for the patch

HTTPS requests are associated to client certificates for authentication and/or authorization

Notes:

  • Never manipulate nor free the SSL object
  • In production, converting fingerprints to hex strings is not required on authentication. Binary fingerprints can be used directly as keys.
  • Getting Subject Name of a certificate is relatively a heavy operation, which should be avoided unless it is required for display.
  • Getting SHA1 fingerprint of a certificate is more than 1,000 times faster than SHA256 fingerprint because SHA1 fingerprint is precalculated and stored in X509 object as binary data.
  • Is it safe to use SHA1 fingerprints for small size of data such as certificates?
  • The SSL object should be valid as long as request and response objects are valid
  • It is a design issue how often client certificate authentication should be performed on requests
    • Potential option # 1:
      • Verify client certificates on verify_callback with fingerprints and issuers (once per SSL/TLS connection)
      • AND
      • Obtain associated certificates via client_certificate_handler middleware on specific request paths which need user authentication information (only for specific URL paths like API or server-rendered HTML that include user-specific information to a client web app)
middleware_cb client_certificate_handler = [](request &req, response &res){
  // require patch to add SSL *nghttp2::asio_http2::server::request::ssl() for client certificate authention
  // Note: The patch is still in preliminary research and not recommended.
  const SSL *ssl = req.req.ssl();
  if (ssl) { // always true
    X509 *certificate = SSL_get_peer_certificate(ssl);
    if (!certificate) {
      std::cerr << "client_certificate_handler: " << "failed to get certificate from SSL" << std::endl;
      req.next(NGHTTP2_ERR_CANCEL);
      return;
    }
    else {
      uint8_t digest[EVP_MAX_MD_SIZE];
      unsigned int digest_length;
      BIO *out;
      char *subject_ptr;
      out = BIO_new(BIO_s_mem());
      X509_NAME_print_ex(out, X509_get_subject_name(certificate), 0, XN_FLAG_RFC2253);
      int n = BIO_get_mem_data(out, &subject_ptr);
      std::string subject(subject_ptr, n);
      subject_ptr = nullptr;
      BIO_free(out);
      out = nullptr;

      bool success = X509_digest(certificate, EVP_sha256(), digest, &digest_length);

      std::ostringstream oss;

      for (unsigned int i = 0; i < digest_length; i++) {
        if (i > 0) {
          oss << ":";
        }
        oss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex << (unsigned int)digest[i];
      }

      std::string fingerprint_str = oss.str();

      // openssl pkcs12 -in path/to/client_cert.(pfx|p12) -nodes -passin pass:<cert password> | openssl x509 -sha256 -noout -fingerprint
      // SHA256 Fingerprint=12:34:56:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
      std::cerr << "client_certificate_handler: SHA256 Fingerprint=" << fingerprint_str << std::endl;
      std::cerr << "client_certificate_handler: " << "subject name=" << subject << std::endl;
      // TODO: authentication such as trusted_fingerprint_map.find(std::string(digest, digest_length)) != trusted_fingerprint_map.end()
      // req.next(NGHTTP2_ERR_CANCEL); return; // if not authenticated
      // store authentication results to req.helper
    }
  }
  req.next();
};

@t2ym
Copy link
Author

t2ym commented May 21, 2021

Example client certificate chain

  • With a user certificate actually distributed from Windows Server 2019 Active Directory Certificate Services with autoenrollment Group Policy Object
  • By the default user certificate template of AD CS, emailAddress=user.name@domain.name precedes CN, which should be preferable to show in Web UI than the corresponding full subject name
verify_callback: preverified = 1
verify_callback: X509_STORE_CTX_get_error() = ok(0)
verify_callback: X509_get_issuer_name() = CN=example-WINSERVER-CA,DC=example,DC=local
verify_callback: X509_get_subject_name() = CN=example-WINSERVER-CA,DC=example,DC=local
verify_callback: X509_STORE_CTX_get_error_depth() = 1
verify_callback: verified CA CN=example-WINSERVER-CA,DC=example,DC=local
verify_callback: preverified = 1
verify_callback: X509_STORE_CTX_get_error() = ok(0)
verify_callback: X509_get_issuer_name() = CN=example-WINSERVER-CA,DC=example,DC=local
verify_callback: X509_get_subject_name() = emailAddress=seca.user1@example.local,CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local
verify_callback: X509_STORE_CTX_get_error_depth() = 0

Example LDAP search result in LDIF format including user certificates in Base64 from Active Directory

  • All users of specific target groups can be extracted with appropriate search parameters to list "authorized user certificates"
  • 2 step auth (tentative plan)
    • Authentication in verify_callback by specified issuer CA certificates
      • With trusted CA list (CAFile) and expected issuer CA certificates
    • Authorization in middleware callback by authorized fingerprints
      • Expected authorization parameters associated to fingerprints
        • Roles: Admin Role, User Role, Content Creator/Consumer, etc. depending on target web applications
          • Roles can be mapped from Active Directory Groups
          • Access Active Directory via LDAPS on demand should be slow but may be acceptable in some cases
          • Some caching (subset replication?) and/or synchronization mechanism should be expected
ldapsearch  -H ldaps://winserver.example.local -x -W -D "seca.user2@example.local" -b "ou=SectionA,ou=DevDepartment,dc=example,dc=local" "(sAMAccountName=*)"
Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <ou=SectionA,ou=DevDepartment,dc=example,dc=local> with scope subtree
# filter: (sAMAccountName=*)
# requesting: ALL
#

# SecA User1, SectionA, DevDepartment, example.local
dn: CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: SecA User1
sn: User1
userCertificate:: MIIGpjCCBY6gAwIBAgITFQAAAAT63YlDOuQFSwAAAAAABDANBgkqhkiG9w0B
 AQsFADBPMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMR0wG
 wYDVQQDExRleGFtcGxlLVdJTlNFUlZFUi1DQTAeFw0yMTA1MjExMDAzMTBaFw0yMzA1MjExMDEzMT
 BaMIGZMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRYwFAY
 DVQQLEw1EZXZEZXBhcnRtZW50MREwDwYDVQQLEwhTZWN0aW9uQTETMBEGA1UEAxMKU2VjQSBVc2Vy
 MTEnMCUGCSqGSIb3DQEJARYYc2VjYS51c2VyMUBleGFtcGxlLmxvY2FsMIIBIjANBgkqhkiG9w0BA
 QEFAAOCAQ8AMIIBCgKCAQEAwBya1UzAF2+vHMjaJUZCLCit5r+IJSL7JjGmqZGy0CUZSKoMK5MGN6
 chYHLK8LiucEpk0K3zHvN0wuI/zzUZN6EwT9Ifwjjo81IKoAaJVJpreaeO2pWsW5sfa6GzC6BvTii
 pPRdeACWqlTAs2l84EaqZ9Y85foRKvpNTx8hgDGD0DcwBe02wHVahSTPYgTaHt+0n7+oZOdDIeBKR
 1CtVq7muAnvq0TErnCU4Of8YmL7gIzJllHqgy8mHao7oyUGSa4mUxv8rFw/3OGkFWPtadoA7QbAz4
 kJzUtCL7Dyp5MLLcuG70uioS9Jemgd26r3zeTJ8xqw82cFqwLCjh1IyQQIDAQABo4IDLjCCAyowPQ
 YJKwYBBAGCNxUHBDAwLgYmKwYBBAGCNxUIhaHRcJyWU4OliTqC0cgbgsjNe4FHhP2vL4TQozQCAWQ
 CAQswKQYDVR0lBCIwIAYKKwYBBAGCNwoDBAYIKwYBBQUHAwQGCCsGAQUFBwMCMA4GA1UdDwEB/wQE
 AwIFoDA1BgkrBgEEAYI3FQoEKDAmMAwGCisGAQQBgjcKAwQwCgYIKwYBBQUHAwQwCgYIKwYBBQUHA
 wIwRAYJKoZIhvcNAQkPBDcwNTAOBggqhkiG9w0DAgICAIAwDgYIKoZIhvcNAwQCAgCAMAcGBSsOAw
 IHMAoGCCqGSIb3DQMHMB0GA1UdDgQWBBQLInXDI+bR5qUxlTPz/1TzOe7AczAfBgNVHSMEGDAWgBS
 npbLvTqLDUIf4MS5Q1iNhwEVrRDCB1gYDVR0fBIHOMIHLMIHIoIHFoIHChoG/bGRhcDovLy9DTj1l
 eGFtcGxlLVdJTlNFUlZFUi1DQSxDTj13aW5zZXJ2ZXIsQ049Q0RQLENOPVB1YmxpYyUyMEtleSUyM
 FNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9ZXhhbXBsZSxEQz1sb2NhbD
 9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9
 uUG9pbnQwgcgGCCsGAQUFBwEBBIG7MIG4MIG1BggrBgEFBQcwAoaBqGxkYXA6Ly8vQ049ZXhhbXBs
 ZS1XSU5TRVJWRVItQ0EsQ049QUlBLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY
 2VzLENOPUNvbmZpZ3VyYXRpb24sREM9ZXhhbXBsZSxEQz1sb2NhbD9jQUNlcnRpZmljYXRlP2Jhc2
 U/b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlvbkF1dGhvcml0eTBNBgNVHREERjBEoCgGCisGAQQBgjc
 UAgOgGgwYc2VjYS51c2VyMUBleGFtcGxlLmxvY2FsgRhzZWNhLnVzZXIxQGV4YW1wbGUubG9jYWww
 DQYJKoZIhvcNAQELBQADggEBAHly0lGUHbmv2y/ne0SQrg/aH94d5fEZXz7ay6bsrPw1YHvKGt1a7
 m4yRSNeHqRFc1UZNQoH1yV5ENrg+5GMa/8d5NoP3XjB+A+Qn4rJ5VbiR9zwpW1+2xIB1t/bCViZWz
 BWzeXY0Vnm+dNvhCanVoYfE5BT7JzWR3yADqCzgrXHG0r/58xp0Kn2ycOq0aU5Uc03DiGWbDGdwIW
 gtxJ+oqJ/ocDsubwdSgFuaxu53HKH7aG0lC44zS8ON5xI2yVTHVil1ps6knDYRdZRoBz7Ft/64XUn
 FAZEhz2i7GM9zNFcEBUxmOk5HSSTUonihX9nhjS2CklzTe51fgvWweoelAw=
givenName: SecA
distinguishedName: CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=lo
 cal
instanceType: 4
whenCreated: 20210521081918.0Z
whenChanged: 20210521101310.0Z
displayName: SecA User1
uSNCreated: 12944
memberOf: CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local
uSNChanged: 13121
name: SecA User1
objectGUID:: XuStHu2P70+fcnh44Pq+Nw==
userAccountControl: 66048
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 132660664823454762
lastLogoff: 0
lastLogon: 132660743569982995
pwdLastSet: 132660623821814800
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+UQQAAA==
accountExpires: 9223372036854775807
logonCount: 20
sAMAccountName: seca.user1
sAMAccountType: 805306368
userPrincipalName: seca.user1@example.local
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local
dSCorePropagationData: 16010101000000.0Z
lastLogonTimestamp: 132660624203584561
msDS-SupportedEncryptionTypes: 0
mail: seca.user1@example.local

# SecA User2, SectionA, DevDepartment, example.local
dn: CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: SecA User2
sn: User2
userCertificate:: MIIGpjCCBY6gAwIBAgITFQAAAAX8Wtciz2jN9QAAAAAABTANBgkqhkiG9w0B
 AQsFADBPMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMR0wG
 wYDVQQDExRleGFtcGxlLVdJTlNFUlZFUi1DQTAeFw0yMTA1MjExMjIzMzVaFw0yMzA1MjExMjMzMz
 VaMIGZMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRYwFAY
 DVQQLEw1EZXZEZXBhcnRtZW50MREwDwYDVQQLEwhTZWN0aW9uQTETMBEGA1UEAxMKU2VjQSBVc2Vy
 MjEnMCUGCSqGSIb3DQEJARYYc2VjYS51c2VyMkBleGFtcGxlLmxvY2FsMIIBIjANBgkqhkiG9w0BA
 QEFAAOCAQ8AMIIBCgKCAQEA4maIpXAubIguK6H5VWnUWzlUSIfIuGtRhd4wG++arlwtWE9nUJLdBM
 IRdwp+FzkTIeh19U/QA7gV10AD8F3VtlGSzPgFBjf7LjOGYsFovoyNGnAnTtEXlBQpFDVs+tgqp9V
 FypHZoRy/cA7MSC3W0tonBie1nw30OV1FO0RALsKkRXucULxa1XHmr6nrRQuLY1xg2h0s/Z+RLcwM
 l8p4+ctXEGMed0mgSPnuQ9Yoox00KPkvMFuLJZPrRk9aiOLdqmWZi/8ye55SVyiD+CeKXqf13T+Q7
 8gCLDPzGV112Jw+WfxchdmuahCs9Kw97KkoUaQYDySbx2/HqGJzDMSk7QIDAQABo4IDLjCCAyowPQ
 YJKwYBBAGCNxUHBDAwLgYmKwYBBAGCNxUIhaHRcJyWU4OliTqC0cgbgsjNe4FHhP2vL4TQozQCAWQ
 CAQswKQYDVR0lBCIwIAYKKwYBBAGCNwoDBAYIKwYBBQUHAwQGCCsGAQUFBwMCMA4GA1UdDwEB/wQE
 AwIFoDA1BgkrBgEEAYI3FQoEKDAmMAwGCisGAQQBgjcKAwQwCgYIKwYBBQUHAwQwCgYIKwYBBQUHA
 wIwRAYJKoZIhvcNAQkPBDcwNTAOBggqhkiG9w0DAgICAIAwDgYIKoZIhvcNAwQCAgCAMAcGBSsOAw
 IHMAoGCCqGSIb3DQMHMB0GA1UdDgQWBBRcoZQRWZR9TUM/qSUnc/cCQNRtiTAfBgNVHSMEGDAWgBS
 npbLvTqLDUIf4MS5Q1iNhwEVrRDCB1gYDVR0fBIHOMIHLMIHIoIHFoIHChoG/bGRhcDovLy9DTj1l
 eGFtcGxlLVdJTlNFUlZFUi1DQSxDTj13aW5zZXJ2ZXIsQ049Q0RQLENOPVB1YmxpYyUyMEtleSUyM
 FNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9ZXhhbXBsZSxEQz1sb2NhbD
 9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9
 uUG9pbnQwgcgGCCsGAQUFBwEBBIG7MIG4MIG1BggrBgEFBQcwAoaBqGxkYXA6Ly8vQ049ZXhhbXBs
 ZS1XSU5TRVJWRVItQ0EsQ049QUlBLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY
 2VzLENOPUNvbmZpZ3VyYXRpb24sREM9ZXhhbXBsZSxEQz1sb2NhbD9jQUNlcnRpZmljYXRlP2Jhc2
 U/b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlvbkF1dGhvcml0eTBNBgNVHREERjBEoCgGCisGAQQBgjc
 UAgOgGgwYc2VjYS51c2VyMkBleGFtcGxlLmxvY2FsgRhzZWNhLnVzZXIyQGV4YW1wbGUubG9jYWww
 DQYJKoZIhvcNAQELBQADggEBALPz8RRsxvOhT5EZ/I0g75MgIM9w1817NxPYX/ZXAcdDnV6pMZ5dq
 fgArK3AAyzpHGz4uQ7XFuSsqULhly2I/1SQbusF6CFKqPkD9OAikH04ScQ15iyI1u7qyPrdgM1HdX
 6KZj8p40P6W3A2QPwnbqohdJVhvLoJTmR9lS2Yrssbucm5CdmwwPD2rFSTZ/VnKFjZJp6oyN/eww9
 rftrjbCakfHfVuxSmMezACI1Be2PUz9M0tjFxzfL88Y1pS6uQgzK9oF6DXEx+vsMQ6kNvhJbOdH77
 vcA1Pd9vNlvVfTMRHgfRYxo8+OexVg755HqRH4j1W45wwJuRVv91r8PA5oM=
givenName: SecA
distinguishedName: CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=lo
 cal
instanceType: 4
whenCreated: 20210521081940.0Z
whenChanged: 20210521123335.0Z
displayName: SecA User2
uSNCreated: 12952
memberOf: CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local
uSNChanged: 16456
name: SecA User2
objectGUID:: AGu4pg7vbkasCne5z9zkdQ==
userAccountControl: 66048
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 0
lastLogoff: 0
lastLogon: 132660740111077438
pwdLastSet: 132660623908534692
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+UgQAAA==
accountExpires: 9223372036854775807
logonCount: 1
sAMAccountName: seca.user2
sAMAccountType: 805306368
userPrincipalName: seca.user2@example.local
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local
dSCorePropagationData: 16010101000000.0Z
lastLogonTimestamp: 132660739714671261
msDS-SupportedEncryptionTypes: 0
mail: seca.user2@example.local

# SecA_Users, SectionA, DevDepartment, example.local
dn: CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local
objectClass: top
objectClass: group
cn: SecA_Users
member: CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local
member: CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local
distinguishedName: CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=lo
 cal
instanceType: 4
whenCreated: 20210521082210.0Z
whenChanged: 20210521082705.0Z
uSNCreated: 12961
uSNChanged: 12969
name: SecA_Users
objectGUID:: NutkeiKM4ECR05cfQ+PieQ==
objectSid:: AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+UwQAAA==
sAMAccountName: SecA_Users
sAMAccountType: 268435456
groupType: -2147483646
objectCategory: CN=Group,CN=Schema,CN=Configuration,DC=example,DC=local
dSCorePropagationData: 16010101000000.0Z

# search result
search: 2
result: 0 Success

# numResponses: 4
# numEntries: 3

@t2ym
Copy link
Author

t2ym commented May 22, 2021

Example LDAP search result in LDIF format for all groups (including nested) that have a specified member

Most methods do not reveal membership in the "primary" group. For most users, the "primary" group would be "Domain Users". Specifically, the memberOf attribute of user objects, and the member attribute of group objects, never reveals "primary" group membership. In most domains, the member attribute of the "Domain Users" group is empty, and it is safe to assume that all users belong to this group.

ldapsearch  -H ldaps://winserver.example.local -x -W -D "bind.user@example.local" -y passwdfile \
-b "dc=example,dc=local" \
'(&(objectClass=group)(member:1.2.840.113556.1.4.1941:=CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=local))'
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=local> with scope subtree
# filter: (&(objectClass=group)(member:1.2.840.113556.1.4.1941:=CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=local))
# requesting: ALL
#

# WebAppX_Users, SectionA, DevDepartment, example.local
dn: CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local
objectClass: top
objectClass: group
cn: WebAppX_Users
member: CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=local
member: CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local
member: CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local
member: CN=Domain Users,CN=Users,DC=example,DC=local
distinguishedName: CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC
 =local
instanceType: 4
whenCreated: 20210522061722.0Z
whenChanged: 20210522071009.0Z
uSNCreated: 16540
uSNChanged: 16589
name: WebAppX_Users
objectGUID:: JC+AWCra3UOxYONWadLXUQ==
objectSid:: AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+VgQAAA==
sAMAccountName: WebAppX_Users
sAMAccountType: 268435456
groupType: -2147483646
objectCategory: CN=Group,CN=Schema,CN=Configuration,DC=example,DC=local
dSCorePropagationData: 16010101000000.0Z

# SecB_Users, SectionB, DevDepartment, example.local
dn: CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=local
objectClass: top
objectClass: group
cn: SecB_Users
member: CN=SecB User2,OU=SectionB,OU=DevDepartment,DC=example,DC=local
member: CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=local
distinguishedName: CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=lo
 cal
instanceType: 4
whenCreated: 20210522070933.0Z
whenChanged: 20210522071234.0Z
uSNCreated: 16582
memberOf: CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local
uSNChanged: 16600
name: SecB_Users
objectGUID:: dmLVVn2hS0icUPQ/MoxrSQ==
objectSid:: AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+WQQAAA==
sAMAccountName: SecB_Users
sAMAccountType: 268435456
groupType: -2147483646
objectCategory: CN=Group,CN=Schema,CN=Configuration,DC=example,DC=local
dSCorePropagationData: 16010101000000.0Z

# search reference
ref: ldaps://ForestDnsZones.example.local/DC=ForestDnsZones,DC=example,DC=loca
 l

# search reference
ref: ldaps://DomainDnsZones.example.local/DC=DomainDnsZones,DC=example,DC=loca
 l

# search reference
ref: ldaps://example.local/CN=Configuration,DC=example,DC=local

# search result
search: 2
result: 0 Success

# numResponses: 6
# numEntries: 2
# numReferences: 3

Example LDAP search result in LDIF format for Administrator user

  • Note that "Domain Users" group does not exist in the result although it is obviously listed in Windows AD console
ldapsearch  -H ldaps://winserver.example.local -x -W -D "bind.user@example.local" -y passwdfile -b "dc=example,dc=local" 'distinguishedName=CN=Administrator,CN=Users,DC=example,DC=local'
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=local> with scope subtree
# filter: distinguishedName=CN=Administrator,CN=Users,DC=example,DC=local
# requesting: ALL
#

# Administrator, Users, example.local
dn: CN=Administrator,CN=Users,DC=example,DC=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: Administrator
description: Built-in account for administering the computer/domain
distinguishedName: CN=Administrator,CN=Users,DC=example,DC=local
instanceType: 4
whenCreated: 20210521071514.0Z
whenChanged: 20210521073103.0Z
uSNCreated: 8196
memberOf: CN=Group Policy Creator Owners,CN=Users,DC=example,DC=local
memberOf: CN=Domain Admins,CN=Users,DC=example,DC=local
memberOf: CN=Enterprise Admins,CN=Users,DC=example,DC=local
memberOf: CN=Schema Admins,CN=Users,DC=example,DC=local
memberOf: CN=Administrators,CN=Builtin,DC=example,DC=local
uSNChanged: 12791
name: Administrator
objectGUID:: wiWnhB9+D0WPNpHbqNrkvw==
userAccountControl: 66048
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 0
lastLogoff: 0
lastLogon: 132661457012483363
pwdLastSet: 132660540836559961
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+9AEAAA==
adminCount: 1
accountExpires: 9223372036854775807
logonCount: 20
sAMAccountName: Administrator
sAMAccountType: 805306368
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local
isCriticalSystemObject: TRUE
dSCorePropagationData: 20210521073103.0Z
dSCorePropagationData: 20210521073103.0Z
dSCorePropagationData: 20210521071553.0Z
dSCorePropagationData: 16010101181216.0Z
lastLogonTimestamp: 132660551565417503

# search reference
ref: ldaps://ForestDnsZones.example.local/DC=ForestDnsZones,DC=example,DC=loca
 l

# search reference
ref: ldaps://DomainDnsZones.example.local/DC=DomainDnsZones,DC=example,DC=loca
 l

# search reference
ref: ldaps://example.local/CN=Configuration,DC=example,DC=local

# search result
search: 2
result: 0 Success

# numResponses: 5
# numEntries: 1
# numReferences: 3

In contrast, the following PowerShell script show "Domain Users" group for a user

  • The group list is not including nested ones
PS C:\> Get-ADPrincipalGroupMembership -Identity "CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=local"


distinguishedName : CN=Domain Users,CN=Users,DC=example,DC=local
GroupCategory     : Security
GroupScope        : Global
name              : Domain Users
objectClass       : group
objectGUID        : a6bef6c4-9b44-4f6f-a2af-75c5ef8443e8
SamAccountName    : Domain Users
SID               : S-1-5-21-506189923-3732335159-4265370833-513

distinguishedName : CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=local
GroupCategory     : Security
GroupScope        : Global
name              : SecB_Users
objectClass       : group
objectGUID        : 56d56276-a17d-484b-9c50-f43f328c6b49
SamAccountName    : SecB_Users
SID               : S-1-5-21-506189923-3732335159-4265370833-1113

@t2ym
Copy link
Author

t2ym commented May 22, 2021

Example LDAP search result in LDIF format for all users (including nested) of a specified group

  • This LDAP query is exhaustive and slow
  • Members of "Domain Users" group, which is included in the target group, is not included in the list except for those who are included via other groups
  • "Domain Users" group is purposely excluded from search results unless explicitly specified directly

Most methods do not reveal membership in the "primary" group. For most users, the "primary" group would be "Domain Users". Specifically, the memberOf attribute of user objects, and the member attribute of group objects, never reveals "primary" group membership. In most domains, the member attribute of the "Domain Users" group is empty, and it is safe to assume that all users belong to this group.

ldapsearch -H ldaps://winserver.example.local -x -W -D "bind.user@example.local" -y passwdfile \
-b "dc=example,dc=local" \
'(&(objectCategory=person)(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local))'
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=local> with scope subtree
# filter: (&(objectCategory=person)(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local))
# requesting: ALL
#

# SecA User1, SectionA, DevDepartment, example.local
dn: CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: SecA User1
sn: User1
userCertificate:: MIIGpjCCBY6gAwIBAgITFQAAAAT63YlDOuQFSwAAAAAABDANBgkqhkiG9w0B
 AQsFADBPMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMR0wG
 wYDVQQDExRleGFtcGxlLVdJTlNFUlZFUi1DQTAeFw0yMTA1MjExMDAzMTBaFw0yMzA1MjExMDEzMT
 BaMIGZMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRYwFAY
 DVQQLEw1EZXZEZXBhcnRtZW50MREwDwYDVQQLEwhTZWN0aW9uQTETMBEGA1UEAxMKU2VjQSBVc2Vy
 MTEnMCUGCSqGSIb3DQEJARYYc2VjYS51c2VyMUBleGFtcGxlLmxvY2FsMIIBIjANBgkqhkiG9w0BA
 QEFAAOCAQ8AMIIBCgKCAQEAwBya1UzAF2+vHMjaJUZCLCit5r+IJSL7JjGmqZGy0CUZSKoMK5MGN6
 chYHLK8LiucEpk0K3zHvN0wuI/zzUZN6EwT9Ifwjjo81IKoAaJVJpreaeO2pWsW5sfa6GzC6BvTii
 pPRdeACWqlTAs2l84EaqZ9Y85foRKvpNTx8hgDGD0DcwBe02wHVahSTPYgTaHt+0n7+oZOdDIeBKR
 1CtVq7muAnvq0TErnCU4Of8YmL7gIzJllHqgy8mHao7oyUGSa4mUxv8rFw/3OGkFWPtadoA7QbAz4
 kJzUtCL7Dyp5MLLcuG70uioS9Jemgd26r3zeTJ8xqw82cFqwLCjh1IyQQIDAQABo4IDLjCCAyowPQ
 YJKwYBBAGCNxUHBDAwLgYmKwYBBAGCNxUIhaHRcJyWU4OliTqC0cgbgsjNe4FHhP2vL4TQozQCAWQ
 CAQswKQYDVR0lBCIwIAYKKwYBBAGCNwoDBAYIKwYBBQUHAwQGCCsGAQUFBwMCMA4GA1UdDwEB/wQE
 AwIFoDA1BgkrBgEEAYI3FQoEKDAmMAwGCisGAQQBgjcKAwQwCgYIKwYBBQUHAwQwCgYIKwYBBQUHA
 wIwRAYJKoZIhvcNAQkPBDcwNTAOBggqhkiG9w0DAgICAIAwDgYIKoZIhvcNAwQCAgCAMAcGBSsOAw
 IHMAoGCCqGSIb3DQMHMB0GA1UdDgQWBBQLInXDI+bR5qUxlTPz/1TzOe7AczAfBgNVHSMEGDAWgBS
 npbLvTqLDUIf4MS5Q1iNhwEVrRDCB1gYDVR0fBIHOMIHLMIHIoIHFoIHChoG/bGRhcDovLy9DTj1l
 eGFtcGxlLVdJTlNFUlZFUi1DQSxDTj13aW5zZXJ2ZXIsQ049Q0RQLENOPVB1YmxpYyUyMEtleSUyM
 FNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9ZXhhbXBsZSxEQz1sb2NhbD
 9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9
 uUG9pbnQwgcgGCCsGAQUFBwEBBIG7MIG4MIG1BggrBgEFBQcwAoaBqGxkYXA6Ly8vQ049ZXhhbXBs
 ZS1XSU5TRVJWRVItQ0EsQ049QUlBLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY
 2VzLENOPUNvbmZpZ3VyYXRpb24sREM9ZXhhbXBsZSxEQz1sb2NhbD9jQUNlcnRpZmljYXRlP2Jhc2
 U/b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlvbkF1dGhvcml0eTBNBgNVHREERjBEoCgGCisGAQQBgjc
 UAgOgGgwYc2VjYS51c2VyMUBleGFtcGxlLmxvY2FsgRhzZWNhLnVzZXIxQGV4YW1wbGUubG9jYWww
 DQYJKoZIhvcNAQELBQADggEBAHly0lGUHbmv2y/ne0SQrg/aH94d5fEZXz7ay6bsrPw1YHvKGt1a7
 m4yRSNeHqRFc1UZNQoH1yV5ENrg+5GMa/8d5NoP3XjB+A+Qn4rJ5VbiR9zwpW1+2xIB1t/bCViZWz
 BWzeXY0Vnm+dNvhCanVoYfE5BT7JzWR3yADqCzgrXHG0r/58xp0Kn2ycOq0aU5Uc03DiGWbDGdwIW
 gtxJ+oqJ/ocDsubwdSgFuaxu53HKH7aG0lC44zS8ON5xI2yVTHVil1ps6knDYRdZRoBz7Ft/64XUn
 FAZEhz2i7GM9zNFcEBUxmOk5HSSTUonihX9nhjS2CklzTe51fgvWweoelAw=
givenName: SecA
distinguishedName: CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=lo
 cal
instanceType: 4
whenCreated: 20210521081918.0Z
whenChanged: 20210521101310.0Z
displayName: SecA User1
uSNCreated: 12944
memberOf: CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local
uSNChanged: 13121
name: SecA User1
objectGUID:: XuStHu2P70+fcnh44Pq+Nw==
userAccountControl: 66048
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 132660664823454762
lastLogoff: 0
lastLogon: 132660743569982995
pwdLastSet: 132660623821814800
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+UQQAAA==
accountExpires: 9223372036854775807
logonCount: 20
sAMAccountName: seca.user1
sAMAccountType: 805306368
userPrincipalName: seca.user1@example.local
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local
dSCorePropagationData: 16010101000000.0Z
lastLogonTimestamp: 132660624203584561
msDS-SupportedEncryptionTypes: 0
mail: seca.user1@example.local

# SecA User2, SectionA, DevDepartment, example.local
dn: CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: SecA User2
sn: User2
userCertificate:: MIIGpjCCBY6gAwIBAgITFQAAAAX8Wtciz2jN9QAAAAAABTANBgkqhkiG9w0B
 AQsFADBPMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMR0wG
 wYDVQQDExRleGFtcGxlLVdJTlNFUlZFUi1DQTAeFw0yMTA1MjExMjIzMzVaFw0yMzA1MjExMjMzMz
 VaMIGZMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRYwFAY
 DVQQLEw1EZXZEZXBhcnRtZW50MREwDwYDVQQLEwhTZWN0aW9uQTETMBEGA1UEAxMKU2VjQSBVc2Vy
 MjEnMCUGCSqGSIb3DQEJARYYc2VjYS51c2VyMkBleGFtcGxlLmxvY2FsMIIBIjANBgkqhkiG9w0BA
 QEFAAOCAQ8AMIIBCgKCAQEA4maIpXAubIguK6H5VWnUWzlUSIfIuGtRhd4wG++arlwtWE9nUJLdBM
 IRdwp+FzkTIeh19U/QA7gV10AD8F3VtlGSzPgFBjf7LjOGYsFovoyNGnAnTtEXlBQpFDVs+tgqp9V
 FypHZoRy/cA7MSC3W0tonBie1nw30OV1FO0RALsKkRXucULxa1XHmr6nrRQuLY1xg2h0s/Z+RLcwM
 l8p4+ctXEGMed0mgSPnuQ9Yoox00KPkvMFuLJZPrRk9aiOLdqmWZi/8ye55SVyiD+CeKXqf13T+Q7
 8gCLDPzGV112Jw+WfxchdmuahCs9Kw97KkoUaQYDySbx2/HqGJzDMSk7QIDAQABo4IDLjCCAyowPQ
 YJKwYBBAGCNxUHBDAwLgYmKwYBBAGCNxUIhaHRcJyWU4OliTqC0cgbgsjNe4FHhP2vL4TQozQCAWQ
 CAQswKQYDVR0lBCIwIAYKKwYBBAGCNwoDBAYIKwYBBQUHAwQGCCsGAQUFBwMCMA4GA1UdDwEB/wQE
 AwIFoDA1BgkrBgEEAYI3FQoEKDAmMAwGCisGAQQBgjcKAwQwCgYIKwYBBQUHAwQwCgYIKwYBBQUHA
 wIwRAYJKoZIhvcNAQkPBDcwNTAOBggqhkiG9w0DAgICAIAwDgYIKoZIhvcNAwQCAgCAMAcGBSsOAw
 IHMAoGCCqGSIb3DQMHMB0GA1UdDgQWBBRcoZQRWZR9TUM/qSUnc/cCQNRtiTAfBgNVHSMEGDAWgBS
 npbLvTqLDUIf4MS5Q1iNhwEVrRDCB1gYDVR0fBIHOMIHLMIHIoIHFoIHChoG/bGRhcDovLy9DTj1l
 eGFtcGxlLVdJTlNFUlZFUi1DQSxDTj13aW5zZXJ2ZXIsQ049Q0RQLENOPVB1YmxpYyUyMEtleSUyM
 FNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9ZXhhbXBsZSxEQz1sb2NhbD
 9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9
 uUG9pbnQwgcgGCCsGAQUFBwEBBIG7MIG4MIG1BggrBgEFBQcwAoaBqGxkYXA6Ly8vQ049ZXhhbXBs
 ZS1XSU5TRVJWRVItQ0EsQ049QUlBLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY
 2VzLENOPUNvbmZpZ3VyYXRpb24sREM9ZXhhbXBsZSxEQz1sb2NhbD9jQUNlcnRpZmljYXRlP2Jhc2
 U/b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlvbkF1dGhvcml0eTBNBgNVHREERjBEoCgGCisGAQQBgjc
 UAgOgGgwYc2VjYS51c2VyMkBleGFtcGxlLmxvY2FsgRhzZWNhLnVzZXIyQGV4YW1wbGUubG9jYWww
 DQYJKoZIhvcNAQELBQADggEBALPz8RRsxvOhT5EZ/I0g75MgIM9w1817NxPYX/ZXAcdDnV6pMZ5dq
 fgArK3AAyzpHGz4uQ7XFuSsqULhly2I/1SQbusF6CFKqPkD9OAikH04ScQ15iyI1u7qyPrdgM1HdX
 6KZj8p40P6W3A2QPwnbqohdJVhvLoJTmR9lS2Yrssbucm5CdmwwPD2rFSTZ/VnKFjZJp6oyN/eww9
 rftrjbCakfHfVuxSmMezACI1Be2PUz9M0tjFxzfL88Y1pS6uQgzK9oF6DXEx+vsMQ6kNvhJbOdH77
 vcA1Pd9vNlvVfTMRHgfRYxo8+OexVg755HqRH4j1W45wwJuRVv91r8PA5oM=
givenName: SecA
distinguishedName: CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=lo
 cal
instanceType: 4
whenCreated: 20210521081940.0Z
whenChanged: 20210521123335.0Z
displayName: SecA User2
uSNCreated: 12952
memberOf: CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local
memberOf: CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local
uSNChanged: 16456
name: SecA User2
objectGUID:: AGu4pg7vbkasCne5z9zkdQ==
userAccountControl: 66048
badPwdCount: 1
codePage: 0
countryCode: 0
badPasswordTime: 132661464291233373
lastLogoff: 0
lastLogon: 132661377489046006
pwdLastSet: 132660623908534692
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+UgQAAA==
accountExpires: 9223372036854775807
logonCount: 1
sAMAccountName: seca.user2
sAMAccountType: 805306368
userPrincipalName: seca.user2@example.local
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local
dSCorePropagationData: 16010101000000.0Z
lastLogonTimestamp: 132660739714671261
msDS-SupportedEncryptionTypes: 0
mail: seca.user2@example.local

# SecB User1, SectionB, DevDepartment, example.local
dn: CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: SecB User1
sn: User1
givenName: SecB
distinguishedName: CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=lo
 cal
instanceType: 4
whenCreated: 20210522070846.0Z
whenChanged: 20210522070903.0Z
displayName: SecB User1
uSNCreated: 16574
memberOf: CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=local
uSNChanged: 16580
name: SecB User1
objectGUID:: MCR5lepgJEKSum8Lu8C+Sw==
userAccountControl: 66048
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 0
lastLogoff: 0
lastLogon: 0
pwdLastSet: 132661409267326750
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+WAQAAA==
accountExpires: 9223372036854775807
logonCount: 0
sAMAccountName: secb.user1
sAMAccountType: 805306368
userPrincipalName: secb.user1@example.local
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local
dSCorePropagationData: 16010101000000.0Z
mail: secb.user1@example.local

# SecB User2, SectionB, DevDepartment, example.local
dn: CN=SecB User2,OU=SectionB,OU=DevDepartment,DC=example,DC=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: SecB User2
sn: User2
givenName: SecB
distinguishedName: CN=SecB User2,OU=SectionB,OU=DevDepartment,DC=example,DC=lo
 cal
instanceType: 4
whenCreated: 20210522071209.0Z
whenChanged: 20210522071222.0Z
displayName: SecB User2
uSNCreated: 16592
memberOf: CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=local
uSNChanged: 16598
name: SecB User2
objectGUID:: qSlfUKHcIkWoUPDe9nr+rQ==
userAccountControl: 66048
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 0
lastLogoff: 0
lastLogon: 0
pwdLastSet: 132661411298264757
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+WgQAAA==
accountExpires: 9223372036854775807
logonCount: 0
sAMAccountName: secb.user2
sAMAccountType: 805306368
userPrincipalName: secb.user2@example.local
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local
dSCorePropagationData: 16010101000000.0Z
mail: secb.user2@example.local

# search reference
ref: ldaps://ForestDnsZones.example.local/DC=ForestDnsZones,DC=example,DC=loca
 l

# search reference
ref: ldaps://DomainDnsZones.example.local/DC=DomainDnsZones,DC=example,DC=loca
 l

# search reference
ref: ldaps://example.local/CN=Configuration,DC=example,DC=local

# search result
search: 2
result: 0 Success

# numResponses: 8
# numEntries: 4
# numReferences: 3

Example PowerShell script to get all members (including nested) of a specified group

  • "Domain Users" group is excluded, while it is included in the target group
PS C:\> Get-ADGroupMember WebAppX_Users  -recursive


distinguishedName : CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local
name              : SecA User2
objectClass       : user
objectGUID        : a6b86b00-ef0e-466e-ac0a-77b9cfdce475
SamAccountName    : seca.user2
SID               : S-1-5-21-506189923-3732335159-4265370833-1106

distinguishedName : CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local
name              : SecA User1
objectClass       : user
objectGUID        : 1eade45e-8fed-4fef-9f72-7878e0fabe37
SamAccountName    : seca.user1
SID               : S-1-5-21-506189923-3732335159-4265370833-1105

distinguishedName : CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=local
name              : SecB User1
objectClass       : user
objectGUID        : 95792430-60ea-4224-92ba-6f0bbbc0be4b
SamAccountName    : secb.user1
SID               : S-1-5-21-506189923-3732335159-4265370833-1112

distinguishedName : CN=SecB User2,OU=SectionB,OU=DevDepartment,DC=example,DC=local
name              : SecB User2
objectClass       : user
objectGUID        : 505f29a9-dca1-4522-a850-f0def67afead
SamAccountName    : secb.user2
SID               : S-1-5-21-506189923-3732335159-4265370833-1114

ldapsearch.exe on Windows

PS C:\OpenLDAP\ClientTools> .\ldapsearch.exe -H ldaps://winserver.example.local -y passwdfile -x -W -D "bind.user@exampl
e.local" -b "dc=example,dc=local" '(&(objectCategory=person)(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=CN=WebA
ppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local))'

@t2ym
Copy link
Author

t2ym commented May 23, 2021

Example LDAP search result converted to JSON via ldif2json

  • Get ldif2json by curl -L -O https://gist.githubusercontent.com/Xophmeister/33e6abe5e055e122f5093f1acbc91793/raw/71b9634a13652befa3c53b096c9aa8ab90117fa2/ldif2json
  • json_xs powered by JSON::XS perl module available via libjson-xs-perl package
ldapsearch -H ldaps://winserver.example.local -x -W -D "bind.user@example.local" -y passwdfile \
-b "dc=example,dc=local" \
'(&(objectCategory=person)(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local))' |\
awk -f ldif2json | json_xs -f json -t json-pretty
[
   {
      "accountExpires" : "9223372036854775807",
      "badPasswordTime" : "132660664823454762",
      "badPwdCount" : "0",
      "cn" : "SecA User1",
      "codePage" : "0",
      "countryCode" : "0",
      "dSCorePropagationData" : "16010101000000.0Z",
      "displayName" : "SecA User1",
      "distinguishedName" : "CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
      "dn" : "CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
      "givenName" : "SecA",
      "instanceType" : "4",
      "lastLogoff" : "0",
      "lastLogon" : "132661579561692834",
      "lastLogonTimestamp" : "132660624203584561",
      "logonCount" : "28",
      "mail" : "seca.user1@example.local",
      "memberOf" : "CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
      "msDS-SupportedEncryptionTypes" : "0",
      "name" : "SecA User1",
      "objectCategory" : "CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local",
      "objectClass" : [
         "top",
         "person",
         "organizationalPerson",
         "user"
      ],
      "objectGUID" : "XuStHu2P70+fcnh44Pq+Nw==",
      "objectSid" : "AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+UQQAAA==",
      "primaryGroupID" : "513",
      "pwdLastSet" : "132660623821814800",
      "sAMAccountName" : "seca.user1",
      "sAMAccountType" : "805306368",
      "sn" : "User1",
      "uSNChanged" : "13121",
      "uSNCreated" : "12944",
      "userAccountControl" : "66048",
      "userCertificate" : "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",
      "userPrincipalName" : "seca.user1@example.local",
      "whenChanged" : "20210521101310.0Z",
      "whenCreated" : "20210521081918.0Z"
   },
   {
      "accountExpires" : "9223372036854775807",
      "badPasswordTime" : "132661481838108535",
      "badPwdCount" : "2",
      "cn" : "SecA User2",
      "codePage" : "0",
      "countryCode" : "0",
      "dSCorePropagationData" : "16010101000000.0Z",
      "displayName" : "SecA User2",
      "distinguishedName" : "CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
      "dn" : "CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
      "givenName" : "SecA",
      "instanceType" : "4",
      "lastLogoff" : "0",
      "lastLogon" : "132661377489046006",
      "lastLogonTimestamp" : "132660739714671261",
      "logonCount" : "1",
      "mail" : "seca.user2@example.local",
      "memberOf" : [
         "CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
         "CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local"
      ],
      "msDS-SupportedEncryptionTypes" : "0",
      "name" : "SecA User2",
      "objectCategory" : "CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local",
      "objectClass" : [
         "top",
         "person",
         "organizationalPerson",
         "user"
      ],
      "objectGUID" : "AGu4pg7vbkasCne5z9zkdQ==",
      "objectSid" : "AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+UgQAAA==",
      "primaryGroupID" : "513",
      "pwdLastSet" : "132660623908534692",
      "sAMAccountName" : "seca.user2",
      "sAMAccountType" : "805306368",
      "sn" : "User2",
      "uSNChanged" : "16456",
      "uSNCreated" : "12952",
      "userAccountControl" : "66048",
      "userCertificate" : "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",
      "userPrincipalName" : "seca.user2@example.local",
      "whenChanged" : "20210521123335.0Z",
      "whenCreated" : "20210521081940.0Z"
   },
   {
      "accountExpires" : "9223372036854775807",
      "badPasswordTime" : "0",
      "badPwdCount" : "0",
      "cn" : "SecB User1",
      "codePage" : "0",
      "countryCode" : "0",
      "dSCorePropagationData" : "16010101000000.0Z",
      "displayName" : "SecB User1",
      "distinguishedName" : "CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=local",
      "dn" : "CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=local",
      "givenName" : "SecB",
      "instanceType" : "4",
      "lastLogoff" : "0",
      "lastLogon" : "0",
      "logonCount" : "0",
      "mail" : "secb.user1@example.local",
      "memberOf" : "CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=local",
      "name" : "SecB User1",
      "objectCategory" : "CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local",
      "objectClass" : [
         "top",
         "person",
         "organizationalPerson",
         "user"
      ],
      "objectGUID" : "MCR5lepgJEKSum8Lu8C+Sw==",
      "objectSid" : "AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+WAQAAA==",
      "primaryGroupID" : "513",
      "pwdLastSet" : "132661409267326750",
      "sAMAccountName" : "secb.user1",
      "sAMAccountType" : "805306368",
      "sn" : "User1",
      "uSNChanged" : "16580",
      "uSNCreated" : "16574",
      "userAccountControl" : "66048",
      "userPrincipalName" : "secb.user1@example.local",
      "whenChanged" : "20210522070903.0Z",
      "whenCreated" : "20210522070846.0Z"
   },
   {
      "accountExpires" : "9223372036854775807",
      "badPasswordTime" : "0",
      "badPwdCount" : "0",
      "cn" : "SecB User2",
      "codePage" : "0",
      "countryCode" : "0",
      "dSCorePropagationData" : "16010101000000.0Z",
      "displayName" : "SecB User2",
      "distinguishedName" : "CN=SecB User2,OU=SectionB,OU=DevDepartment,DC=example,DC=local",
      "dn" : "CN=SecB User2,OU=SectionB,OU=DevDepartment,DC=example,DC=local",
      "givenName" : "SecB",
      "instanceType" : "4",
      "lastLogoff" : "0",
      "lastLogon" : "0",
      "logonCount" : "0",
      "mail" : "secb.user2@example.local",
      "memberOf" : "CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=local",
      "name" : "SecB User2",
      "objectCategory" : "CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local",
      "objectClass" : [
         "top",
         "person",
         "organizationalPerson",
         "user"
      ],
      "objectGUID" : "qSlfUKHcIkWoUPDe9nr+rQ==",
      "objectSid" : "AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+WgQAAA==",
      "primaryGroupID" : "513",
      "pwdLastSet" : "132661411298264757",
      "sAMAccountName" : "secb.user2",
      "sAMAccountType" : "805306368",
      "sn" : "User2",
      "uSNChanged" : "16598",
      "uSNCreated" : "16592",
      "userAccountControl" : "66048",
      "userPrincipalName" : "secb.user2@example.local",
      "whenChanged" : "20210522071222.0Z",
      "whenCreated" : "20210522071209.0Z"
   }
]

On Windows with awk.exe

PS C:\OpenLDAP\ClientTools> .\ldapsearch.exe -H ldaps://winserver.example.local -y passwdfile -x -W -D "bind.user@example.local" -b "dc=example,dc=local" '(&(objectCategory=person)(objectClass=user)(memberOf=CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local))' | C:\gawk-5.1.0-w32-bin\bin\awk.exe -f .\ldif2json
[{"pwdLastSet":"132660623908534692","dSCorePropagationData":"16010101000000.0Z","accountExpires":"9223372036854775807","countryCode":"0","displayName":"SecA User2","cn":"SecA User2","primaryGroupID":"513","dn":"CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local","objectCategory":"CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local","objectSid":"AQUAAAAAAAUVAAAAY9grHjfqdt7RZDz+UgQAAA==","lastLogon":"132661377489046006","instanceType":"4","distinguishedName":"CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local","mail":"seca.user2@example.local","sn":"User2","sAMAccountType":"805306368","codePage":"0","memberOf":["CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local","CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local"],"badPwdCount":"2","whenChanged":"20210521123335.0Z","whenCreated":"20210521081940.0Z","name":"SecA User2","givenName":"SecA","objectClass":["top","person","organizationalPerson","user"],"userPrincipalName":"seca.user2@example.local","lastLogoff":"0","badPasswordTime":"132661481838108535","objectGUID":"AGu4pg7vbkasCne5z9zkdQ==","userCertificate":"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","msDS-SupportedEncryptionTypes":"0","sAMAccountName":"seca.user2","userAccountControl":"66048","lastLogonTimestamp":"132660739714671261","logonCount":"1","uSNChanged":"16456","uSNCreated":"12952"}]

@t2ym
Copy link
Author

t2ym commented May 23, 2021

Example LDAP search result converted to JSON via PowerShell ConvertTo-Json CmdLet

  • Binary attributes such as "userCertificate" are converted to an array of a single string containing space-delimited decimal numbers
  • -Depth option is tricky
Get-ADGroupMember WebAppX_Users  -recursive | Get-ADUser -Properties * | ConvertTo-Json -Depth 2
[
    {
        "GivenName":  "SecA",
        "Surname":  "User2",
        "UserPrincipalName":  "seca.user2@example.local",
        "Enabled":  true,
        "SamAccountName":  "seca.user2",
        "SID":  {
                    "BinaryLength":  28,
                    "AccountDomainSid":  "S-1-5-21-506189923-3732335159-4265370833",
                    "Value":  "S-1-5-21-506189923-3732335159-4265370833-1106"
                },
        "DistinguishedName":  "CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
        "Name":  "SecA User2",
        "ObjectClass":  "user",
        "ObjectGuid":  "a6b86b00-ef0e-466e-ac0a-77b9cfdce475",
        "PropertyNames":  [
                              "AccountExpirationDate",
                              "accountExpires",
                              "AccountLockoutTime",
                              "AccountNotDelegated",
                              "AllowReversiblePasswordEncryption",
                              "AuthenticationPolicy",
                              "AuthenticationPolicySilo",
                              "BadLogonCount",
                              "badPasswordTime",
                              "badPwdCount",
                              "CannotChangePassword",
                              "CanonicalName",
                              "Certificates",
                              "City",
                              "CN",
                              "codePage",
                              "Company",
                              "CompoundIdentitySupported",
                              "Country",
                              "countryCode",
                              "Created",
                              "createTimeStamp",
                              "Deleted",
                              "Department",
                              "Description",
                              "DisplayName",
                              "DistinguishedName",
                              "Division",
                              "DoesNotRequirePreAuth",
                              "dSCorePropagationData",
                              "EmailAddress",
                              "EmployeeID",
                              "EmployeeNumber",
                              "Enabled",
                              "Fax",
                              "GivenName",
                              "HomeDirectory",
                              "HomedirRequired",
                              "HomeDrive",
                              "HomePage",
                              "HomePhone",
                              "Initials",
                              "instanceType",
                              "isDeleted",
                              "KerberosEncryptionType",
                              "LastBadPasswordAttempt",
                              "LastKnownParent",
                              "lastLogoff",
                              "lastLogon",
                              "LastLogonDate",
                              "lastLogonTimestamp",
                              "LockedOut",
                              "logonCount",
                              "LogonWorkstations",
                              "mail",
                              "Manager",
                              "MemberOf",
                              "MNSLogonAccount",
                              "MobilePhone",
                              "Modified",
                              "modifyTimeStamp",
                              "msDS-SupportedEncryptionTypes",
                              "msDS-User-Account-Control-Computed",
                              "Name",
                              "nTSecurityDescriptor",
                              "ObjectCategory",
                              "ObjectClass",
                              "ObjectGUID",
                              "objectSid",
                              "Office",
                              "OfficePhone",
                              "Organization",
                              "OtherName",
                              "PasswordExpired",
                              "PasswordLastSet",
                              "PasswordNeverExpires",
                              "PasswordNotRequired",
                              "POBox",
                              "PostalCode",
                              "PrimaryGroup",
                              "primaryGroupID",
                              "PrincipalsAllowedToDelegateToAccount",
                              "ProfilePath",
                              "ProtectedFromAccidentalDeletion",
                              "pwdLastSet",
                              "SamAccountName",
                              "sAMAccountType",
                              "ScriptPath",
                              "sDRightsEffective",
                              "ServicePrincipalNames",
                              "SID",
                              "SIDHistory",
                              "SmartcardLogonRequired",
                              "sn",
                              "State",
                              "StreetAddress",
                              "Surname",
                              "Title",
                              "TrustedForDelegation",
                              "TrustedToAuthForDelegation",
                              "UseDESKeyOnly",
                              "userAccountControl",
                              "userCertificate",
                              "UserPrincipalName",
                              "uSNChanged",
                              "uSNCreated",
                              "whenChanged",
                              "whenCreated"
                          ],
        "AddedProperties":  [

                            ],
        "RemovedProperties":  [

                              ],
        "ModifiedProperties":  [

                               ],
        "PropertyCount":  108,
        "AccountExpirationDate":  null,
        "accountExpires":  9223372036854775807,
        "AccountLockoutTime":  null,
        "AccountNotDelegated":  false,
        "AllowReversiblePasswordEncryption":  false,
        "AuthenticationPolicy":  [

                                 ],
        "AuthenticationPolicySilo":  [

                                     ],
        "BadLogonCount":  2,
        "badPasswordTime":  132661481838108535,
        "badPwdCount":  2,
        "CannotChangePassword":  false,
        "CanonicalName":  "example.local/DevDepartment/SectionA/SecA User2",
        "Certificates":  [
                             "System.Security.Cryptography.X509Certificates.X509Certificate"
                         ],
        "City":  null,
        "CN":  "SecA User2",
        "codePage":  0,
        "Company":  null,
        "CompoundIdentitySupported":  [
                                          false
                                      ],
        "Country":  null,
        "countryCode":  0,
        "Created":  "\/Date(1621585180000)\/",
        "createTimeStamp":  "\/Date(1621585180000)\/",
        "Deleted":  null,
        "Department":  null,
        "Description":  null,
        "DisplayName":  "SecA User2",
        "Division":  null,
        "DoesNotRequirePreAuth":  false,
        "dSCorePropagationData":  [
                                      "\/Date(-11644473600000)\/"
                                  ],
        "EmailAddress":  "seca.user2@example.local",
        "EmployeeID":  null,
        "EmployeeNumber":  null,
        "Fax":  null,
        "HomeDirectory":  null,
        "HomedirRequired":  false,
        "HomeDrive":  null,
        "HomePage":  null,
        "HomePhone":  null,
        "Initials":  null,
        "instanceType":  4,
        "isDeleted":  null,
        "KerberosEncryptionType":  [
                                       0
                                   ],
        "LastBadPasswordAttempt":  "\/Date(1621674583810)\/",
        "LastKnownParent":  null,
        "lastLogoff":  0,
        "lastLogon":  132661377489046006,
        "LastLogonDate":  "\/Date(1621600371467)\/",
        "lastLogonTimestamp":  132660739714671261,
        "LockedOut":  false,
        "logonCount":  1,
        "LogonWorkstations":  null,
        "mail":  "seca.user2@example.local",
        "Manager":  null,
        "MemberOf":  [
                         "CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
                         "CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local"
                     ],
        "MNSLogonAccount":  false,
        "MobilePhone":  null,
        "Modified":  "\/Date(1621600415000)\/",
        "modifyTimeStamp":  "\/Date(1621600415000)\/",
        "msDS-SupportedEncryptionTypes":  0,
        "msDS-User-Account-Control-Computed":  0,
        "nTSecurityDescriptor":  {
                                     "AccessRightType":  "System.DirectoryServices.ActiveDirectoryRights",
                                     "AccessRuleType":  "System.DirectoryServices.ActiveDirectoryAccessRule",
                                     "AuditRuleType":  "System.DirectoryServices.ActiveDirectoryAuditRule",
                                     "AreAccessRulesProtected":  false,
                                     "AreAuditRulesProtected":  false,
                                     "AreAccessRulesCanonical":  true,
                                     "AreAuditRulesCanonical":  true
                                 },
        "ObjectCategory":  "CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local",
        "ObjectGUID":  "a6b86b00-ef0e-466e-ac0a-77b9cfdce475",
        "objectSid":  {
                          "BinaryLength":  28,
                          "AccountDomainSid":  "S-1-5-21-506189923-3732335159-4265370833",
                          "Value":  "S-1-5-21-506189923-3732335159-4265370833-1106"
                      },
        "Office":  null,
        "OfficePhone":  null,
        "Organization":  null,
        "OtherName":  null,
        "PasswordExpired":  false,
        "PasswordLastSet":  "\/Date(1621588790853)\/",
        "PasswordNeverExpires":  true,
        "PasswordNotRequired":  false,
        "POBox":  null,
        "PostalCode":  null,
        "PrimaryGroup":  "CN=Domain Users,CN=Users,DC=example,DC=local",
        "primaryGroupID":  513,
        "PrincipalsAllowedToDelegateToAccount":  [

                                                 ],
        "ProfilePath":  null,
        "ProtectedFromAccidentalDeletion":  false,
        "pwdLastSet":  132660623908534692,
        "sAMAccountType":  805306368,
        "ScriptPath":  null,
        "sDRightsEffective":  15,
        "ServicePrincipalNames":  [

                                  ],
        "SIDHistory":  [

                       ],
        "SmartcardLogonRequired":  false,
        "sn":  "User2",
        "State":  null,
        "StreetAddress":  null,
        "Title":  null,
        "TrustedForDelegation":  false,
        "TrustedToAuthForDelegation":  false,
        "UseDESKeyOnly":  false,
        "userAccountControl":  66048,
        "userCertificate":  [
                                "48 130 6 166 48 130 5 142 160 3 2 1 2 2 19 21 0 0 0 5 252 90 215 34 207 104 205 245 0 0 0 0 0 5 48 13 6 9 42 134 72 134 247 13 1 1 11 5 0 48 79 49 21 48 19 6 10 9 146 38 137 147 242 44 100 1 25 22 5 108 111 99 97 108 49 23 48 21 6 10 9 146 38 137 147 242 44 100 1 25 22 7 101 120 97 109 112 108 101 49 29 48 27 6 3 85 4 3 19 20 101 120 97 109 112 108 101 45 87 73 78 83 69 82 86 69 82 45 67 65 48 30 23 13 50 49 48 53 50 49 49 50 50 51 51 53 90 23 13 50 51 48 53 50 49 49 50 51 51 51 53 90 48 129 153 49 21 48 19 6 10 9 146 38 137 147 242 44 100 1 25 22 5 108 111 99 97 108 49 23 48 21 6 10 9 146 38 137 147 242 44 100 1 25 22 7 101 120 97 109 112 108 101 49 22 48 20 6 3 85 4 11 19 13 68 101 118 68 101 112 97 114 116 109 101 110 116 49 17 48 15 6 3 85 4 11 19 8 83 101 99 116 105 111 110 65 49 19 48 17 6 3 85 4 3 19 10 83 101 99 65 32 85 115 101 114 50 49 39 48 37 6 9 42 134 72 134 247 13 1 9 1 22 24 115 101 99 97 46 117 115 101 114 50 64 101 120 97 109 112 108 101 46 108 111 99 97 108 48 130 1 34 48 13 6 9 42 134 72 134 247 13 1 1 1 5 0 3 130 1 15 0 48 130 1 10 2 130 1 1 0 226 102 136 165 112 46 108 136 46 43 161 249 85 105 212 91 57 84 72 135 200 184 107 81 133 222 48 27 239 154 174 92 45 88 79 103 80 146 221 4 194 17 119 10 126 23 57 19 33 232 117 245 79 208 3 184 21 215 64 3 240 93 213 182 81 146 204 248 5 6 55 251 46 51 134 98 193 104 190 140 141 26 112 39 78 209 23 148 20 41 20 53 108 250 216 42 167 213 69 202 145 217 161 28 191 112 14 204 72 45 214 210 218 39 6 39 181 159 13 244 57 93 69 59 68 64 46 194 164 69 123 156 80 188 90 213 113 230 175 169 235 69 11 139 99 92 96 218 29 44 253 159 145 45 204 12 151 202 120 249 203 87 16 99 30 119 73 160 72 249 238 67 214 40 163 29 52 40 249 47 48 91 139 37 147 235 70 79 90 136 226 221 170 101 153 139 255 50 123 158 82 87 40 131 248 39 138 94 167 245 221 63 144 239 200 2 44 51 243 25 93 117 216 156 62 89 252 92 133 217 174 106 16 172 244 172 61 236 169 40 81 164 24 15 36 155 199 111 199 168 98 115 12 196 164 237 2 3 1 0 1 163 130 3 46 48 130 3 42 48 61 6 9 43 6 1 4 1 130 55 21 7 4 48 48 46 6 38 43 6 1 4 1 130 55 21 8 133 161 209 112 156 150 83 131 165 137 58 130 209 200 27 130 200 205 123 129 71 132 253 175 47 132 208 163 52 2 1 100 2 1 11 48 41 6 3 85 29 37 4 34 48 32 6 10 43 6 1 4 1 130 55 10 3 4 6 8 43 6 1 5 5 7 3 4 6 8 43 6 1 5 5 7 3 2 48 14 6 3 85 29 15 1 1 255 4 4 3 2 5 160 48 53 6 9 43 6 1 4 1 130 55 21 10 4 40 48 38 48 12 6 10 43 6 1 4 1 130 55 10 3 4 48 10 6 8 43 6 1 5 5 7 3 4 48 10 6 8 43 6 1 5 5 7 3 2 48 68 6 9 42 134 72 134 247 13 1 9 15 4 55 48 53 48 14 6 8 42 134 72 134 247 13 3 2 2 2 0 128 48 14 6 8 42 134 72 134 247 13 3 4 2 2 0 128 48 7 6 5 43 14 3 2 7 48 10 6 8 42 134 72 134 247 13 3 7 48 29 6 3 85 29 14 4 22 4 20 92 161 148 17 89 148 125 77 67 63 169 37 39 115 247 2 64 212 109 137 48 31 6 3 85 29 35 4 24 48 22 128 20 167 165 178 239 78 162 195 80 135 248 49 46 80 214 35 97 192 69 107 68 48 129 214 6 3 85 29 31 4 129 206 48 129 203 48 129 200 160 129 197 160 129 194 134 129 191 108 100 97 112 58 47 47 47 67 78 61 101 120 97 109 112 108 101 45 87 73 78 83 69 82 86 69 82 45 67 65 44 67 78 61 119 105 110 115 101 114 118 101 114 44 67 78 61 67 68 80 44 67 78 61 80 117 98 108 105 99 37 50 48 75 101 121 37 50 48 83 101 114 118 105 99 101 115 44 67 78 61 83 101 114 118 105 99 101 115 44 67 78 61 67 111 110 102 105 103 117 114 97 116 105 111 110 44 68 67 61 101 120 97 109 112 108 101 44 68 67 61 108 111 99 97 108 63 99 101 114 116 105 102 105 99 97 116 101 82 101 118 111 99 97 116 105 111 110 76 105 115 116 63 98 97 115 101 63 111 98 106 101 99 116 67 108 97 115 115 61 99 82 76 68 105 115 116 114 105 98 117 116 105 111 110 80 111 105 110 116 48 129 200 6 8 43 6 1 5 5 7 1 1 4 129 187 48 129 184 48 129 181 6 8 43 6 1 5 5 7 48 2 134 129 168 108 100 97 112 58 47 47 47 67 78 61 101 120 97 109 112 108 101 45 87 73 78 83 69 82 86 69 82 45 67 65 44 67 78 61 65 73 65 44 67 78 61 80 117 98 108 105 99 37 50 48 75 101 121 37 50 48 83 101 114 118 105 99 101 115 44 67 78 61 83 101 114 118 105 99 101 115 44 67 78 61 67 111 110 102 105 103 117 114 97 116 105 111 110 44 68 67 61 101 120 97 109 112 108 101 44 68 67 61 108 111 99 97 108 63 99 65 67 101 114 116 105 102 105 99 97 116 101 63 98 97 115 101 63 111 98 106 101 99 116 67 108 97 115 115 61 99 101 114 116 105 102 105 99 97 116 105 111 110 65 117 116 104 111 114 105 116 121 48 77 6 3 85 29 17 4 70 48 68 160 40 6 10 43 6 1 4 1 130 55 20 2 3 160 26 12 24 115 101 99 97 46 117 115 101 114 50 64 101 120 97 109 112 108 101 46 108 111 99 97 108 129 24 115 101 99 97 46 117 115 101 114 50 64 101 120 97 109 112 108 101 46 108 111 99 97 108 48 13 6 9 42 134 72 134 247 13 1 1 11 5 0 3 130 1 1 0 179 243 241 20 108 198 243 161 79 145 25 252 141 32 239 147 32 32 207 112 215 205 123 55 19 216 95 246 87 1 199 67 157 94 169 49 158 93 169 248 0 172 173 192 3 44 233 28 108 248 185 14 215 22 228 172 169 66 225 151 45 136 255 84 144 110 235 5 232 33 74 168 249 3 244 224 34 144 125 56 73 196 53 230 44 136 214 238 234 200 250 221 128 205 71 117 126 138 102 63 41 227 67 250 91 112 54 64 252 39 110 170 33 116 149 97 188 186 9 78 100 125 149 45 152 174 203 27 185 201 185 9 217 176 192 240 246 172 84 147 103 245 103 40 88 217 38 158 168 200 223 222 195 15 107 126 218 227 108 38 164 124 119 213 187 20 166 49 236 192 8 141 65 123 99 212 207 211 52 182 49 113 205 242 252 241 141 105 75 171 144 131 50 189 160 94 131 92 76 126 190 195 16 234 67 111 132 150 206 116 126 251 189 192 53 61 223 111 54 91 213 125 51 17 30 7 209 99 26 60 248 231 177 86 14 249 228 122 145 31 136 245 91 142 112 192 155 145 86 255 117 175 195 192 230 131"
                            ],
        "uSNChanged":  16456,
        "uSNCreated":  12952,
        "whenChanged":  "\/Date(1621600415000)\/",
        "whenCreated":  "\/Date(1621585180000)\/"
    },
    {
        "GivenName":  "SecA",
        "Surname":  "User1",
        "UserPrincipalName":  "seca.user1@example.local",
        "Enabled":  true,
        "SamAccountName":  "seca.user1",
        "SID":  {
                    "BinaryLength":  28,
                    "AccountDomainSid":  "S-1-5-21-506189923-3732335159-4265370833",
                    "Value":  "S-1-5-21-506189923-3732335159-4265370833-1105"
                },
        "DistinguishedName":  "CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
        "Name":  "SecA User1",
        "ObjectClass":  "user",
        "ObjectGuid":  "1eade45e-8fed-4fef-9f72-7878e0fabe37",
        "PropertyNames":  [
                              "AccountExpirationDate",
                              "accountExpires",
                              "AccountLockoutTime",
                              "AccountNotDelegated",
                              "AllowReversiblePasswordEncryption",
                              "AuthenticationPolicy",
                              "AuthenticationPolicySilo",
                              "BadLogonCount",
                              "badPasswordTime",
                              "badPwdCount",
                              "CannotChangePassword",
                              "CanonicalName",
                              "Certificates",
                              "City",
                              "CN",
                              "codePage",
                              "Company",
                              "CompoundIdentitySupported",
                              "Country",
                              "countryCode",
                              "Created",
                              "createTimeStamp",
                              "Deleted",
                              "Department",
                              "Description",
                              "DisplayName",
                              "DistinguishedName",
                              "Division",
                              "DoesNotRequirePreAuth",
                              "dSCorePropagationData",
                              "EmailAddress",
                              "EmployeeID",
                              "EmployeeNumber",
                              "Enabled",
                              "Fax",
                              "GivenName",
                              "HomeDirectory",
                              "HomedirRequired",
                              "HomeDrive",
                              "HomePage",
                              "HomePhone",
                              "Initials",
                              "instanceType",
                              "isDeleted",
                              "KerberosEncryptionType",
                              "LastBadPasswordAttempt",
                              "LastKnownParent",
                              "lastLogoff",
                              "lastLogon",
                              "LastLogonDate",
                              "lastLogonTimestamp",
                              "LockedOut",
                              "logonCount",
                              "LogonWorkstations",
                              "mail",
                              "Manager",
                              "MemberOf",
                              "MNSLogonAccount",
                              "MobilePhone",
                              "Modified",
                              "modifyTimeStamp",
                              "msDS-SupportedEncryptionTypes",
                              "msDS-User-Account-Control-Computed",
                              "Name",
                              "nTSecurityDescriptor",
                              "ObjectCategory",
                              "ObjectClass",
                              "ObjectGUID",
                              "objectSid",
                              "Office",
                              "OfficePhone",
                              "Organization",
                              "OtherName",
                              "PasswordExpired",
                              "PasswordLastSet",
                              "PasswordNeverExpires",
                              "PasswordNotRequired",
                              "POBox",
                              "PostalCode",
                              "PrimaryGroup",
                              "primaryGroupID",
                              "PrincipalsAllowedToDelegateToAccount",
                              "ProfilePath",
                              "ProtectedFromAccidentalDeletion",
                              "pwdLastSet",
                              "SamAccountName",
                              "sAMAccountType",
                              "ScriptPath",
                              "sDRightsEffective",
                              "ServicePrincipalNames",
                              "SID",
                              "SIDHistory",
                              "SmartcardLogonRequired",
                              "sn",
                              "State",
                              "StreetAddress",
                              "Surname",
                              "Title",
                              "TrustedForDelegation",
                              "TrustedToAuthForDelegation",
                              "UseDESKeyOnly",
                              "userAccountControl",
                              "userCertificate",
                              "UserPrincipalName",
                              "uSNChanged",
                              "uSNCreated",
                              "whenChanged",
                              "whenCreated"
                          ],
        "AddedProperties":  [

                            ],
        "RemovedProperties":  [

                              ],
        "ModifiedProperties":  [

                               ],
        "PropertyCount":  108,
        "AccountExpirationDate":  null,
        "accountExpires":  9223372036854775807,
        "AccountLockoutTime":  null,
        "AccountNotDelegated":  false,
        "AllowReversiblePasswordEncryption":  false,
        "AuthenticationPolicy":  [

                                 ],
        "AuthenticationPolicySilo":  [

                                     ],
        "BadLogonCount":  0,
        "badPasswordTime":  132660664823454762,
        "badPwdCount":  0,
        "CannotChangePassword":  false,
        "CanonicalName":  "example.local/DevDepartment/SectionA/SecA User1",
        "Certificates":  [
                             "System.Security.Cryptography.X509Certificates.X509Certificate"
                         ],
        "City":  null,
        "CN":  "SecA User1",
        "codePage":  0,
        "Company":  null,
        "CompoundIdentitySupported":  [
                                          false
                                      ],
        "Country":  null,
        "countryCode":  0,
        "Created":  "\/Date(1621585158000)\/",
        "createTimeStamp":  "\/Date(1621585158000)\/",
        "Deleted":  null,
        "Department":  null,
        "Description":  null,
        "DisplayName":  "SecA User1",
        "Division":  null,
        "DoesNotRequirePreAuth":  false,
        "dSCorePropagationData":  [
                                      "\/Date(-11644473600000)\/"
                                  ],
        "EmailAddress":  "seca.user1@example.local",
        "EmployeeID":  null,
        "EmployeeNumber":  null,
        "Fax":  null,
        "HomeDirectory":  null,
        "HomedirRequired":  false,
        "HomeDrive":  null,
        "HomePage":  null,
        "HomePhone":  null,
        "Initials":  null,
        "instanceType":  4,
        "isDeleted":  null,
        "KerberosEncryptionType":  [
                                       0
                                   ],
        "LastBadPasswordAttempt":  "\/Date(1621592882345)\/",
        "LastKnownParent":  null,
        "lastLogoff":  0,
        "lastLogon":  132661579561692834,
        "LastLogonDate":  "\/Date(1621588820358)\/",
        "lastLogonTimestamp":  132660624203584561,
        "LockedOut":  false,
        "logonCount":  28,
        "LogonWorkstations":  null,
        "mail":  "seca.user1@example.local",
        "Manager":  null,
        "MemberOf":  [
                         "CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local"
                     ],
        "MNSLogonAccount":  false,
        "MobilePhone":  null,
        "Modified":  "\/Date(1621591990000)\/",
        "modifyTimeStamp":  "\/Date(1621591990000)\/",
        "msDS-SupportedEncryptionTypes":  0,
        "msDS-User-Account-Control-Computed":  0,
        "nTSecurityDescriptor":  {
                                     "AccessRightType":  "System.DirectoryServices.ActiveDirectoryRights",
                                     "AccessRuleType":  "System.DirectoryServices.ActiveDirectoryAccessRule",
                                     "AuditRuleType":  "System.DirectoryServices.ActiveDirectoryAuditRule",
                                     "AreAccessRulesProtected":  false,
                                     "AreAuditRulesProtected":  false,
                                     "AreAccessRulesCanonical":  true,
                                     "AreAuditRulesCanonical":  true
                                 },
        "ObjectCategory":  "CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local",
        "ObjectGUID":  "1eade45e-8fed-4fef-9f72-7878e0fabe37",
        "objectSid":  {
                          "BinaryLength":  28,
                          "AccountDomainSid":  "S-1-5-21-506189923-3732335159-4265370833",
                          "Value":  "S-1-5-21-506189923-3732335159-4265370833-1105"
                      },
        "Office":  null,
        "OfficePhone":  null,
        "Organization":  null,
        "OtherName":  null,
        "PasswordExpired":  false,
        "PasswordLastSet":  "\/Date(1621588782181)\/",
        "PasswordNeverExpires":  true,
        "PasswordNotRequired":  false,
        "POBox":  null,
        "PostalCode":  null,
        "PrimaryGroup":  "CN=Domain Users,CN=Users,DC=example,DC=local",
        "primaryGroupID":  513,
        "PrincipalsAllowedToDelegateToAccount":  [

                                                 ],
        "ProfilePath":  null,
        "ProtectedFromAccidentalDeletion":  false,
        "pwdLastSet":  132660623821814800,
        "sAMAccountType":  805306368,
        "ScriptPath":  null,
        "sDRightsEffective":  15,
        "ServicePrincipalNames":  [

                                  ],
        "SIDHistory":  [

                       ],
        "SmartcardLogonRequired":  false,
        "sn":  "User1",
        "State":  null,
        "StreetAddress":  null,
        "Title":  null,
        "TrustedForDelegation":  false,
        "TrustedToAuthForDelegation":  false,
        "UseDESKeyOnly":  false,
        "userAccountControl":  66048,
        "userCertificate":  [
                                "48 130 6 166 48 130 5 142 160 3 2 1 2 2 19 21 0 0 0 4 250 221 137 67 58 228 5 75 0 0 0 0 0 4 48 13 6 9 42 134 72 134 247 13 1 1 11 5 0 48 79 49 21 48 19 6 10 9 146 38 137 147 242 44 100 1 25 22 5 108 111 99 97 108 49 23 48 21 6 10 9 146 38 137 147 242 44 100 1 25 22 7 101 120 97 109 112 108 101 49 29 48 27 6 3 85 4 3 19 20 101 120 97 109 112 108 101 45 87 73 78 83 69 82 86 69 82 45 67 65 48 30 23 13 50 49 48 53 50 49 49 48 48 51 49 48 90 23 13 50 51 48 53 50 49 49 48 49 51 49 48 90 48 129 153 49 21 48 19 6 10 9 146 38 137 147 242 44 100 1 25 22 5 108 111 99 97 108 49 23 48 21 6 10 9 146 38 137 147 242 44 100 1 25 22 7 101 120 97 109 112 108 101 49 22 48 20 6 3 85 4 11 19 13 68 101 118 68 101 112 97 114 116 109 101 110 116 49 17 48 15 6 3 85 4 11 19 8 83 101 99 116 105 111 110 65 49 19 48 17 6 3 85 4 3 19 10 83 101 99 65 32 85 115 101 114 49 49 39 48 37 6 9 42 134 72 134 247 13 1 9 1 22 24 115 101 99 97 46 117 115 101 114 49 64 101 120 97 109 112 108 101 46 108 111 99 97 108 48 130 1 34 48 13 6 9 42 134 72 134 247 13 1 1 1 5 0 3 130 1 15 0 48 130 1 10 2 130 1 1 0 192 28 154 213 76 192 23 111 175 28 200 218 37 70 66 44 40 173 230 191 136 37 34 251 38 49 166 169 145 178 208 37 25 72 170 12 43 147 6 55 167 33 96 114 202 240 184 174 112 74 100 208 173 243 30 243 116 194 226 63 207 53 25 55 161 48 79 210 31 194 56 232 243 82 10 160 6 137 84 154 107 121 167 142 218 149 172 91 155 31 107 161 179 11 160 111 78 40 169 61 23 94 0 37 170 149 48 44 218 95 56 17 170 153 245 143 57 126 132 74 190 147 83 199 200 96 12 96 244 13 204 1 123 77 176 29 86 161 73 51 216 129 54 135 183 237 39 239 234 25 57 208 200 120 18 145 212 43 85 171 185 174 2 123 234 209 49 43 156 37 56 57 255 24 152 190 224 35 50 101 148 122 160 203 201 135 106 142 232 201 65 146 107 137 148 198 255 43 23 15 247 56 105 5 88 251 90 118 128 59 65 176 51 226 66 115 82 208 139 236 60 169 228 194 203 114 225 187 210 232 168 75 210 94 154 7 118 234 189 243 121 50 124 198 172 60 217 193 106 192 176 163 135 82 50 65 2 3 1 0 1 163 130 3 46 48 130 3 42 48 61 6 9 43 6 1 4 1 130 55 21 7 4 48 48 46 6 38 43 6 1 4 1 130 55 21 8 133 161 209 112 156 150 83 131 165 137 58 130 209 200 27 130 200 205 123 129 71 132 253 175 47 132 208 163 52 2 1 100 2 1 11 48 41 6 3 85 29 37 4 34 48 32 6 10 43 6 1 4 1 130 55 10 3 4 6 8 43 6 1 5 5 7 3 4 6 8 43 6 1 5 5 7 3 2 48 14 6 3 85 29 15 1 1 255 4 4 3 2 5 160 48 53 6 9 43 6 1 4 1 130 55 21 10 4 40 48 38 48 12 6 10 43 6 1 4 1 130 55 10 3 4 48 10 6 8 43 6 1 5 5 7 3 4 48 10 6 8 43 6 1 5 5 7 3 2 48 68 6 9 42 134 72 134 247 13 1 9 15 4 55 48 53 48 14 6 8 42 134 72 134 247 13 3 2 2 2 0 128 48 14 6 8 42 134 72 134 247 13 3 4 2 2 0 128 48 7 6 5 43 14 3 2 7 48 10 6 8 42 134 72 134 247 13 3 7 48 29 6 3 85 29 14 4 22 4 20 11 34 117 195 35 230 209 230 165 49 149 51 243 255 84 243 57 238 192 115 48 31 6 3 85 29 35 4 24 48 22 128 20 167 165 178 239 78 162 195 80 135 248 49 46 80 214 35 97 192 69 107 68 48 129 214 6 3 85 29 31 4 129 206 48 129 203 48 129 200 160 129 197 160 129 194 134 129 191 108 100 97 112 58 47 47 47 67 78 61 101 120 97 109 112 108 101 45 87 73 78 83 69 82 86 69 82 45 67 65 44 67 78 61 119 105 110 115 101 114 118 101 114 44 67 78 61 67 68 80 44 67 78 61 80 117 98 108 105 99 37 50 48 75 101 121 37 50 48 83 101 114 118 105 99 101 115 44 67 78 61 83 101 114 118 105 99 101 115 44 67 78 61 67 111 110 102 105 103 117 114 97 116 105 111 110 44 68 67 61 101 120 97 109 112 108 101 44 68 67 61 108 111 99 97 108 63 99 101 114 116 105 102 105 99 97 116 101 82 101 118 111 99 97 116 105 111 110 76 105 115 116 63 98 97 115 101 63 111 98 106 101 99 116 67 108 97 115 115 61 99 82 76 68 105 115 116 114 105 98 117 116 105 111 110 80 111 105 110 116 48 129 200 6 8 43 6 1 5 5 7 1 1 4 129 187 48 129 184 48 129 181 6 8 43 6 1 5 5 7 48 2 134 129 168 108 100 97 112 58 47 47 47 67 78 61 101 120 97 109 112 108 101 45 87 73 78 83 69 82 86 69 82 45 67 65 44 67 78 61 65 73 65 44 67 78 61 80 117 98 108 105 99 37 50 48 75 101 121 37 50 48 83 101 114 118 105 99 101 115 44 67 78 61 83 101 114 118 105 99 101 115 44 67 78 61 67 111 110 102 105 103 117 114 97 116 105 111 110 44 68 67 61 101 120 97 109 112 108 101 44 68 67 61 108 111 99 97 108 63 99 65 67 101 114 116 105 102 105 99 97 116 101 63 98 97 115 101 63 111 98 106 101 99 116 67 108 97 115 115 61 99 101 114 116 105 102 105 99 97 116 105 111 110 65 117 116 104 111 114 105 116 121 48 77 6 3 85 29 17 4 70 48 68 160 40 6 10 43 6 1 4 1 130 55 20 2 3 160 26 12 24 115 101 99 97 46 117 115 101 114 49 64 101 120 97 109 112 108 101 46 108 111 99 97 108 129 24 115 101 99 97 46 117 115 101 114 49 64 101 120 97 109 112 108 101 46 108 111 99 97 108 48 13 6 9 42 134 72 134 247 13 1 1 11 5 0 3 130 1 1 0 121 114 210 81 148 29 185 175 219 47 231 123 68 144 174 15 218 31 222 29 229 241 25 95 62 218 203 166 236 172 252 53 96 123 202 26 221 90 238 110 50 69 35 94 30 164 69 115 85 25 53 10 7 215 37 121 16 218 224 251 145 140 107 255 29 228 218 15 221 120 193 248 15 144 159 138 201 229 86 226 71 220 240 165 109 126 219 18 1 214 223 219 9 88 153 91 48 86 205 229 216 209 89 230 249 211 111 132 38 167 86 134 31 19 144 83 236 156 214 71 124 128 14 160 179 130 181 199 27 74 255 231 204 105 208 169 246 201 195 170 209 165 57 81 205 55 14 33 150 108 49 157 192 133 160 183 18 126 162 162 127 161 192 236 185 188 29 74 1 110 107 27 185 220 114 135 237 161 180 148 46 56 205 47 14 55 156 72 219 37 83 29 88 165 214 155 58 146 112 216 69 214 81 160 28 251 22 223 250 225 117 39 20 6 68 135 61 162 236 99 61 204 209 92 16 21 49 152 233 57 29 36 147 82 137 226 133 127 103 134 52 182 10 73 115 77 238 117 126 11 214 193 234 30 148 12"
                            ],
        "uSNChanged":  13121,
        "uSNCreated":  12944,
        "whenChanged":  "\/Date(1621591990000)\/",
        "whenCreated":  "\/Date(1621585158000)\/"
    },
    {
        "GivenName":  "SecB",
        "Surname":  "User1",
        "UserPrincipalName":  "secb.user1@example.local",
        "Enabled":  true,
        "SamAccountName":  "secb.user1",
        "SID":  {
                    "BinaryLength":  28,
                    "AccountDomainSid":  "S-1-5-21-506189923-3732335159-4265370833",
                    "Value":  "S-1-5-21-506189923-3732335159-4265370833-1112"
                },
        "DistinguishedName":  "CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=local",
        "Name":  "SecB User1",
        "ObjectClass":  "user",
        "ObjectGuid":  "95792430-60ea-4224-92ba-6f0bbbc0be4b",
        "PropertyNames":  [
                              "AccountExpirationDate",
                              "accountExpires",
                              "AccountLockoutTime",
                              "AccountNotDelegated",
                              "AllowReversiblePasswordEncryption",
                              "AuthenticationPolicy",
                              "AuthenticationPolicySilo",
                              "BadLogonCount",
                              "badPasswordTime",
                              "badPwdCount",
                              "CannotChangePassword",
                              "CanonicalName",
                              "Certificates",
                              "City",
                              "CN",
                              "codePage",
                              "Company",
                              "CompoundIdentitySupported",
                              "Country",
                              "countryCode",
                              "Created",
                              "createTimeStamp",
                              "Deleted",
                              "Department",
                              "Description",
                              "DisplayName",
                              "DistinguishedName",
                              "Division",
                              "DoesNotRequirePreAuth",
                              "dSCorePropagationData",
                              "EmailAddress",
                              "EmployeeID",
                              "EmployeeNumber",
                              "Enabled",
                              "Fax",
                              "GivenName",
                              "HomeDirectory",
                              "HomedirRequired",
                              "HomeDrive",
                              "HomePage",
                              "HomePhone",
                              "Initials",
                              "instanceType",
                              "isDeleted",
                              "KerberosEncryptionType",
                              "LastBadPasswordAttempt",
                              "LastKnownParent",
                              "lastLogoff",
                              "lastLogon",
                              "LastLogonDate",
                              "LockedOut",
                              "logonCount",
                              "LogonWorkstations",
                              "mail",
                              "Manager",
                              "MemberOf",
                              "MNSLogonAccount",
                              "MobilePhone",
                              "Modified",
                              "modifyTimeStamp",
                              "msDS-User-Account-Control-Computed",
                              "Name",
                              "nTSecurityDescriptor",
                              "ObjectCategory",
                              "ObjectClass",
                              "ObjectGUID",
                              "objectSid",
                              "Office",
                              "OfficePhone",
                              "Organization",
                              "OtherName",
                              "PasswordExpired",
                              "PasswordLastSet",
                              "PasswordNeverExpires",
                              "PasswordNotRequired",
                              "POBox",
                              "PostalCode",
                              "PrimaryGroup",
                              "primaryGroupID",
                              "PrincipalsAllowedToDelegateToAccount",
                              "ProfilePath",
                              "ProtectedFromAccidentalDeletion",
                              "pwdLastSet",
                              "SamAccountName",
                              "sAMAccountType",
                              "ScriptPath",
                              "sDRightsEffective",
                              "ServicePrincipalNames",
                              "SID",
                              "SIDHistory",
                              "SmartcardLogonRequired",
                              "sn",
                              "State",
                              "StreetAddress",
                              "Surname",
                              "Title",
                              "TrustedForDelegation",
                              "TrustedToAuthForDelegation",
                              "UseDESKeyOnly",
                              "userAccountControl",
                              "userCertificate",
                              "UserPrincipalName",
                              "uSNChanged",
                              "uSNCreated",
                              "whenChanged",
                              "whenCreated"
                          ],
        "AddedProperties":  [

                            ],
        "RemovedProperties":  [

                              ],
        "ModifiedProperties":  [

                               ],
        "PropertyCount":  106,
        "AccountExpirationDate":  null,
        "accountExpires":  9223372036854775807,
        "AccountLockoutTime":  null,
        "AccountNotDelegated":  false,
        "AllowReversiblePasswordEncryption":  false,
        "AuthenticationPolicy":  [

                                 ],
        "AuthenticationPolicySilo":  [

                                     ],
        "BadLogonCount":  0,
        "badPasswordTime":  0,
        "badPwdCount":  0,
        "CannotChangePassword":  false,
        "CanonicalName":  "example.local/DevDepartment/SectionB/SecB User1",
        "Certificates":  [

                         ],
        "City":  null,
        "CN":  "SecB User1",
        "codePage":  0,
        "Company":  null,
        "CompoundIdentitySupported":  [

                                      ],
        "Country":  null,
        "countryCode":  0,
        "Created":  "\/Date(1621667326000)\/",
        "createTimeStamp":  "\/Date(1621667326000)\/",
        "Deleted":  null,
        "Department":  null,
        "Description":  null,
        "DisplayName":  "SecB User1",
        "Division":  null,
        "DoesNotRequirePreAuth":  false,
        "dSCorePropagationData":  [
                                      "\/Date(-11644473600000)\/"
                                  ],
        "EmailAddress":  "secb.user1@example.local",
        "EmployeeID":  null,
        "EmployeeNumber":  null,
        "Fax":  null,
        "HomeDirectory":  null,
        "HomedirRequired":  false,
        "HomeDrive":  null,
        "HomePage":  null,
        "HomePhone":  null,
        "Initials":  null,
        "instanceType":  4,
        "isDeleted":  null,
        "KerberosEncryptionType":  [

                                   ],
        "LastBadPasswordAttempt":  null,
        "LastKnownParent":  null,
        "lastLogoff":  0,
        "lastLogon":  0,
        "LastLogonDate":  null,
        "LockedOut":  false,
        "logonCount":  0,
        "LogonWorkstations":  null,
        "mail":  "secb.user1@example.local",
        "Manager":  null,
        "MemberOf":  [
                         "CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=local"
                     ],
        "MNSLogonAccount":  false,
        "MobilePhone":  null,
        "Modified":  "\/Date(1621667343000)\/",
        "modifyTimeStamp":  "\/Date(1621667343000)\/",
        "msDS-User-Account-Control-Computed":  0,
        "nTSecurityDescriptor":  {
                                     "AccessRightType":  "System.DirectoryServices.ActiveDirectoryRights",
                                     "AccessRuleType":  "System.DirectoryServices.ActiveDirectoryAccessRule",
                                     "AuditRuleType":  "System.DirectoryServices.ActiveDirectoryAuditRule",
                                     "AreAccessRulesProtected":  false,
                                     "AreAuditRulesProtected":  false,
                                     "AreAccessRulesCanonical":  true,
                                     "AreAuditRulesCanonical":  true
                                 },
        "ObjectCategory":  "CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local",
        "ObjectGUID":  "95792430-60ea-4224-92ba-6f0bbbc0be4b",
        "objectSid":  {
                          "BinaryLength":  28,
                          "AccountDomainSid":  "S-1-5-21-506189923-3732335159-4265370833",
                          "Value":  "S-1-5-21-506189923-3732335159-4265370833-1112"
                      },
        "Office":  null,
        "OfficePhone":  null,
        "Organization":  null,
        "OtherName":  null,
        "PasswordExpired":  false,
        "PasswordLastSet":  "\/Date(1621667326732)\/",
        "PasswordNeverExpires":  true,
        "PasswordNotRequired":  false,
        "POBox":  null,
        "PostalCode":  null,
        "PrimaryGroup":  "CN=Domain Users,CN=Users,DC=example,DC=local",
        "primaryGroupID":  513,
        "PrincipalsAllowedToDelegateToAccount":  [

                                                 ],
        "ProfilePath":  null,
        "ProtectedFromAccidentalDeletion":  false,
        "pwdLastSet":  132661409267326750,
        "sAMAccountType":  805306368,
        "ScriptPath":  null,
        "sDRightsEffective":  15,
        "ServicePrincipalNames":  [

                                  ],
        "SIDHistory":  [

                       ],
        "SmartcardLogonRequired":  false,
        "sn":  "User1",
        "State":  null,
        "StreetAddress":  null,
        "Title":  null,
        "TrustedForDelegation":  false,
        "TrustedToAuthForDelegation":  false,
        "UseDESKeyOnly":  false,
        "userAccountControl":  66048,
        "userCertificate":  [

                            ],
        "uSNChanged":  16580,
        "uSNCreated":  16574,
        "whenChanged":  "\/Date(1621667343000)\/",
        "whenCreated":  "\/Date(1621667326000)\/"
    },
    {
        "GivenName":  "SecB",
        "Surname":  "User2",
        "UserPrincipalName":  "secb.user2@example.local",
        "Enabled":  true,
        "SamAccountName":  "secb.user2",
        "SID":  {
                    "BinaryLength":  28,
                    "AccountDomainSid":  "S-1-5-21-506189923-3732335159-4265370833",
                    "Value":  "S-1-5-21-506189923-3732335159-4265370833-1114"
                },
        "DistinguishedName":  "CN=SecB User2,OU=SectionB,OU=DevDepartment,DC=example,DC=local",
        "Name":  "SecB User2",
        "ObjectClass":  "user",
        "ObjectGuid":  "505f29a9-dca1-4522-a850-f0def67afead",
        "PropertyNames":  [
                              "AccountExpirationDate",
                              "accountExpires",
                              "AccountLockoutTime",
                              "AccountNotDelegated",
                              "AllowReversiblePasswordEncryption",
                              "AuthenticationPolicy",
                              "AuthenticationPolicySilo",
                              "BadLogonCount",
                              "badPasswordTime",
                              "badPwdCount",
                              "CannotChangePassword",
                              "CanonicalName",
                              "Certificates",
                              "City",
                              "CN",
                              "codePage",
                              "Company",
                              "CompoundIdentitySupported",
                              "Country",
                              "countryCode",
                              "Created",
                              "createTimeStamp",
                              "Deleted",
                              "Department",
                              "Description",
                              "DisplayName",
                              "DistinguishedName",
                              "Division",
                              "DoesNotRequirePreAuth",
                              "dSCorePropagationData",
                              "EmailAddress",
                              "EmployeeID",
                              "EmployeeNumber",
                              "Enabled",
                              "Fax",
                              "GivenName",
                              "HomeDirectory",
                              "HomedirRequired",
                              "HomeDrive",
                              "HomePage",
                              "HomePhone",
                              "Initials",
                              "instanceType",
                              "isDeleted",
                              "KerberosEncryptionType",
                              "LastBadPasswordAttempt",
                              "LastKnownParent",
                              "lastLogoff",
                              "lastLogon",
                              "LastLogonDate",
                              "LockedOut",
                              "logonCount",
                              "LogonWorkstations",
                              "mail",
                              "Manager",
                              "MemberOf",
                              "MNSLogonAccount",
                              "MobilePhone",
                              "Modified",
                              "modifyTimeStamp",
                              "msDS-User-Account-Control-Computed",
                              "Name",
                              "nTSecurityDescriptor",
                              "ObjectCategory",
                              "ObjectClass",
                              "ObjectGUID",
                              "objectSid",
                              "Office",
                              "OfficePhone",
                              "Organization",
                              "OtherName",
                              "PasswordExpired",
                              "PasswordLastSet",
                              "PasswordNeverExpires",
                              "PasswordNotRequired",
                              "POBox",
                              "PostalCode",
                              "PrimaryGroup",
                              "primaryGroupID",
                              "PrincipalsAllowedToDelegateToAccount",
                              "ProfilePath",
                              "ProtectedFromAccidentalDeletion",
                              "pwdLastSet",
                              "SamAccountName",
                              "sAMAccountType",
                              "ScriptPath",
                              "sDRightsEffective",
                              "ServicePrincipalNames",
                              "SID",
                              "SIDHistory",
                              "SmartcardLogonRequired",
                              "sn",
                              "State",
                              "StreetAddress",
                              "Surname",
                              "Title",
                              "TrustedForDelegation",
                              "TrustedToAuthForDelegation",
                              "UseDESKeyOnly",
                              "userAccountControl",
                              "userCertificate",
                              "UserPrincipalName",
                              "uSNChanged",
                              "uSNCreated",
                              "whenChanged",
                              "whenCreated"
                          ],
        "AddedProperties":  [

                            ],
        "RemovedProperties":  [

                              ],
        "ModifiedProperties":  [

                               ],
        "PropertyCount":  106,
        "AccountExpirationDate":  null,
        "accountExpires":  9223372036854775807,
        "AccountLockoutTime":  null,
        "AccountNotDelegated":  false,
        "AllowReversiblePasswordEncryption":  false,
        "AuthenticationPolicy":  [

                                 ],
        "AuthenticationPolicySilo":  [

                                     ],
        "BadLogonCount":  0,
        "badPasswordTime":  0,
        "badPwdCount":  0,
        "CannotChangePassword":  false,
        "CanonicalName":  "example.local/DevDepartment/SectionB/SecB User2",
        "Certificates":  [

                         ],
        "City":  null,
        "CN":  "SecB User2",
        "codePage":  0,
        "Company":  null,
        "CompoundIdentitySupported":  [

                                      ],
        "Country":  null,
        "countryCode":  0,
        "Created":  "\/Date(1621667529000)\/",
        "createTimeStamp":  "\/Date(1621667529000)\/",
        "Deleted":  null,
        "Department":  null,
        "Description":  null,
        "DisplayName":  "SecB User2",
        "Division":  null,
        "DoesNotRequirePreAuth":  false,
        "dSCorePropagationData":  [
                                      "\/Date(-11644473600000)\/"
                                  ],
        "EmailAddress":  "secb.user2@example.local",
        "EmployeeID":  null,
        "EmployeeNumber":  null,
        "Fax":  null,
        "HomeDirectory":  null,
        "HomedirRequired":  false,
        "HomeDrive":  null,
        "HomePage":  null,
        "HomePhone":  null,
        "Initials":  null,
        "instanceType":  4,
        "isDeleted":  null,
        "KerberosEncryptionType":  [

                                   ],
        "LastBadPasswordAttempt":  null,
        "LastKnownParent":  null,
        "lastLogoff":  0,
        "lastLogon":  0,
        "LastLogonDate":  null,
        "LockedOut":  false,
        "logonCount":  0,
        "LogonWorkstations":  null,
        "mail":  "secb.user2@example.local",
        "Manager":  null,
        "MemberOf":  [
                         "CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=local"
                     ],
        "MNSLogonAccount":  false,
        "MobilePhone":  null,
        "Modified":  "\/Date(1621667542000)\/",
        "modifyTimeStamp":  "\/Date(1621667542000)\/",
        "msDS-User-Account-Control-Computed":  0,
        "nTSecurityDescriptor":  {
                                     "AccessRightType":  "System.DirectoryServices.ActiveDirectoryRights",
                                     "AccessRuleType":  "System.DirectoryServices.ActiveDirectoryAccessRule",
                                     "AuditRuleType":  "System.DirectoryServices.ActiveDirectoryAuditRule",
                                     "AreAccessRulesProtected":  false,
                                     "AreAuditRulesProtected":  false,
                                     "AreAccessRulesCanonical":  true,
                                     "AreAuditRulesCanonical":  true
                                 },
        "ObjectCategory":  "CN=Person,CN=Schema,CN=Configuration,DC=example,DC=local",
        "ObjectGUID":  "505f29a9-dca1-4522-a850-f0def67afead",
        "objectSid":  {
                          "BinaryLength":  28,
                          "AccountDomainSid":  "S-1-5-21-506189923-3732335159-4265370833",
                          "Value":  "S-1-5-21-506189923-3732335159-4265370833-1114"
                      },
        "Office":  null,
        "OfficePhone":  null,
        "Organization":  null,
        "OtherName":  null,
        "PasswordExpired":  false,
        "PasswordLastSet":  "\/Date(1621667529826)\/",
        "PasswordNeverExpires":  true,
        "PasswordNotRequired":  false,
        "POBox":  null,
        "PostalCode":  null,
        "PrimaryGroup":  "CN=Domain Users,CN=Users,DC=example,DC=local",
        "primaryGroupID":  513,
        "PrincipalsAllowedToDelegateToAccount":  [

                                                 ],
        "ProfilePath":  null,
        "ProtectedFromAccidentalDeletion":  false,
        "pwdLastSet":  132661411298264757,
        "sAMAccountType":  805306368,
        "ScriptPath":  null,
        "sDRightsEffective":  15,
        "ServicePrincipalNames":  [

                                  ],
        "SIDHistory":  [

                       ],
        "SmartcardLogonRequired":  false,
        "sn":  "User2",
        "State":  null,
        "StreetAddress":  null,
        "Title":  null,
        "TrustedForDelegation":  false,
        "TrustedToAuthForDelegation":  false,
        "UseDESKeyOnly":  false,
        "userAccountControl":  66048,
        "userCertificate":  [

                            ],
        "uSNChanged":  16598,
        "uSNCreated":  16592,
        "whenChanged":  "\/Date(1621667542000)\/",
        "whenCreated":  "\/Date(1621667529000)\/"
    }
]

@t2ym
Copy link
Author

t2ym commented May 23, 2021

Extract specified properties from JSON by jq

ldapsearch -H ldaps://winserver.example.local -x -W -D "bind.user@example.local" -y passwdfile -b "dc=example,dc=local" \
'(&(objectCategory=person)(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local))' |\
 awk -f ldif2json | jq -M '[.[] | {dn: .dn, mail: .mail, userCertificate: .userCertificate }] '
[
  {
    "dn": "CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
    "mail": "seca.user1@example.local",
    "userCertificate": "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"
  },
  {
    "dn": "CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
    "mail": "seca.user2@example.local",
    "userCertificate": "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"
  },
  {
    "dn": "CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=local",
    "mail": "secb.user1@example.local",
    "userCertificate": null
  },
  {
    "dn": "CN=SecB User2,OU=SectionB,OU=DevDepartment,DC=example,DC=local",
    "mail": "secb.user2@example.local",
    "userCertificate": null
  }
]

@t2ym
Copy link
Author

t2ym commented May 23, 2021

List SHA1 fingerprints for JSON userCertificate props

jq -nc '$ARGS.positional' --args `for i in \`ldapsearch -H ldaps://winserver.example.local -x -W -D "bind.user@example.local" -y passwdfile -b "dc=example,dc=local" '(&(objectCategory=person)(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local))' |awk -f ldif2json  | jq '.[].userCertificate' | sed -e 's/^"\(.*\)"$/\1/' | sed -e 's/^null//' | egrep -e .\`; do { echo -n ${i} | base64 -d | sha1sum | cut -c1-40 | awk '{print toupper($0)}'; } done` | jq .
[
  "C94F88A3E4B9CC73D919F74620F821D28782B8AF",
  "020C1FCEA19A398DD4E544A3263E0A6EC6357CFD"
]

Powershell to get SHA1 hash list of userCertificate for group members who have the attribute

Get-ADGroupMember WebAppX_Users  -recursive |
Get-ADUser -Properties userCertificate |
Select userCertificate |
ForEach-Object { if ($_.userCertificate) {
Get-FileHash -Algorithm SHA1 -InputStream (new-object System.IO.MemoryStream(,$_.userCertificate[0]))} } |
ForEach-Object { $_.Hash } | ConvertTo-Json
[
    "020C1FCEA19A398DD4E544A3263E0A6EC6357CFD",
    "C94F88A3E4B9CC73D919F74620F821D28782B8AF"
]

@t2ym
Copy link
Author

t2ym commented May 24, 2021

Get Fingerprints for Roles mapped from AD group and subgroups

  • Pseudo-role "*" to show the root group DN
  • Other meta-infomration such as timestamp may be useful
$group = "CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local"; $outfile = "roles.json"; $jsonBase = @{"*"=$group}; Get-ADGroupMember $group |
Select distinguishedName |
ForEach-Object { $jsonBase.Add(($_.distinguishedName -replace "CN=([^,]*),.*", "`$1"), 
@(,(Get-ADGroupMember $_.distinguishedName -recursive |
Get-ADUser -Properties userCertificate |
Select userCertificate | 
ForEach-Object { if ($_.userCertificate) {
Get-FileHash -Algorithm SHA1 -InputStream (new-object System.IO.MemoryStream(,$_.userCertificate[0]))} } |
ForEach-Object { $_.Hash }) |
ForEach-Object { $_ })); }; $jsonBase | ConvertTo-Json | Out-File $outfile; Get-Content $outfile;
{
    "Admin":  [
                  "C94F88A3E4B9CC73D919F74620F821D28782B8AF"
              ],
    "*":  "CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
    "User":  [
                 "C94F88A3E4B9CC73D919F74620F821D28782B8AF",
                 "020C1FCEA19A398DD4E544A3263E0A6EC6357CFD",
                 "E92C3F99D1ADF24B4895C4A7C96214056CEDF23F",
                 "DEC457FBC9C1828B7654ED36343E5AD85008E99C",
                 "BD639B17FAFA564DF2F7E8729781A38E9B4A6024"
             ]
}

On UN*X-like systems

  • LDAP configuration at ~/.ldaprc
TLS_CACERT {PATH_TO_TRUSTED_CA_FILE_IN_CONCATENATED_PEM}
get_roles() { local GROUP_DN="$1";local BIND_USER="$2";local BIND="$3";local SERVERURI="$4";local PASSWDFILE="$5";local LDIF2JSON="$6"; local OUTFILE="$7";\
  get_fingerprints () { local SUBGROUP_DN=$1; jq -nc '$ARGS.positional' \
    --args `for i in \`ldapsearch -H ${SERVERURI} -x -W -D ${BIND_USER} -y passwdfile -b ${BIND} \
    "(&(objectCategory=person)(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=${SUBGROUP_DN}))" |\
    awk -f ${LDIF2JSON} | jq '.[].userCertificate' | sed -e 's/^"\(.*\)"$/\1/' | sed -e 's/^null//' | egrep -e .\`; \
    do { echo -n ${i} | base64 -d | sha1sum | cut -c1-40 | awk '{print toupper($0)}'; } done` | jq .;
  }; \
  echo \{ `ldapsearch -H ${SERVERURI} -x -W -D "${BIND_USER}" -y ${PASSWDFILE} -b "${BIND}" "(distinguishedName=${GROUP_DN})" | awk -f ${LDIF2JSON} | jq .[].member | jq -r .[] |\
  while read line; do { echo \"\`echo -n \"${line}\" | sed -e 's/^"CN=\([^,]*\),.*$/\\1/'\`\": \`get_fingerprints ${line}\`, ; } done` \} \{\"*\": \"${GROUP_DN}\" \} |\
  sed -e 's/, *}/}/' | jq -s add >${OUTFILE}; \
  cat ${OUTFILE}; unset get_fingerprints; unset get_roles;\
}; \
get_roles "CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local" "bind.user@example.local" "dc=example,dc=local" "ldaps://winserver.example.local" "./passwdfile" "./ldif2json" "./roles.json"
{
  "User": [
    "C94F88A3E4B9CC73D919F74620F821D28782B8AF",
    "020C1FCEA19A398DD4E544A3263E0A6EC6357CFD",
    "DEC457FBC9C1828B7654ED36343E5AD85008E99C",
    "BD639B17FAFA564DF2F7E8729781A38E9B4A6024",
    "E92C3F99D1ADF24B4895C4A7C96214056CEDF23F"
  ],
  "Admin": [
    "C94F88A3E4B9CC73D919F74620F821D28782B8AF"
  ],
  "*": "CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local"
}

Group and User configurations in the above scripts

  • Subgroups mapped to roles can be located in any LDAP paths including outside of the container OU to avoid role name conflicts with other web applications
function Get-ADTree {
  param( $group )
  
  if ($group.GetType().FullName -eq "System.String") {
    Get-ADTree (Get-ADGroup $group);
  }
  elseif ($group.ObjectClass -eq "group") {
    @{$group.distinguishedName=(Get-ADGroupMember $group | ForEach-Object { Get-ADTree $_ })}
  }
  else {
    $group.distinguishedName
  }
}
Get-ADTree "CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local" | ConvertTo-Json -Depth 5
  • Output reformatted with jq .
  • To show a single element array, ConvertTo-Json -Depth 5 -AsArray should be used in PowerShell 7.1
{
  "CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
    {
      "CN=Admin,OU=SectionA,OU=DevDepartment,DC=example,DC=local": "CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local"
    },
    {
      "CN=User,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
        {
          "CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
            "CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
            "CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
            "CN=SecA User3,OU=SectionA,OU=DevDepartment,DC=example,DC=local"
          ]
        },
        {
          "CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=local": [
            "CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=local",
            "CN=SecB User2,OU=SectionB,OU=DevDepartment,DC=example,DC=local"
          ]
        }
      ]
    }
  ]
}

@t2ym
Copy link
Author

t2ym commented May 25, 2021

Map groups to roles generated from AD groups and subgroups

  • If only groups of which a user is a direct member is known, the user's roles can be determined by this map from groups to roles
  • Searching only for groups should be faster than exhaustive search for userCertificate attributes
  • userCertificate attributes are not populated until users sign in to their computers
    • Web apps for all users should be able to authenticate and authorize such users at their first sign-in operations, where intranet web services must be of their focus
      • Retrieval of their group membership attributes from Active Directory should be done just on their first access to web apps without delay
    • For intranet web apps that are expected to be registered on requests, all the expected userCertificate attributes should be existent before their access attempts. Fingerprints can be pre-fetched for such applications
  • Option # 1: Direct groups can be fetched from Active Directory on each user access to the target web app
  • Option # 2: Find a way to fetch all the fingerprints of target users of relevant groups in a reasonable query load on Active Directory
  • Option # 3: Hybrid solution with fingerprints mapped to roles for normal users and roles from Active Directory groups on demand as a fallback to achieve complete service levels
    1. Authenticate on verify callback via trusted certificate issuer(s)
    2. Authorize on request middleware via fingerprints assigned to role(s)
    3. Authorize as a fallback on request middleware via Active Directory group membership mapped to role(s)
    • Prototyping LDAP accessor class: ldap_member_of.cc
      • Basic synchronous search for memberOf attributes
      • Primitive fallback mechanism for synchronous search
      • Basic asynchronous search for memberOf attributes
        • Note: In .net core, polling is used for async LDAP operations as callback interface is unavailable in OpenLDAP

Underlying native libraries don't support callback-based function, so we will instead use polling and use a Stopwatch to track the timeout manually.

  • dummy item for indentation
    • dummy item for indentation
      • Fallback mechanism for asynchronous search
  • Caching of roles derived from group membership in Active Directory is essential for performance
  • On Web Apps, it may NOT be trivial to map a user's subject in user certificate to Active Directory distinguishedName
    • If emailAddress is included in the subject, it should be trivial
    • Is this simple conversion feasible? subject: CN=${Name},OU... == distinguishedName
  • Format-Json came from https://stackoverflow.com/questions/56322993/proper-formating-of-json-using-powershell/56324939
function Get-ADGroupRoles {
  param( $group, $roles, $result, $root )

  if ($group.GetType().FullName -eq "System.String") {
    [void]($result = @{});
    [void]($roles = @());
    [void]($root = Get-ADGroup $group);
    [void](Get-ADGroupRoles $root $roles $result $root);
    $result
  }
  else {
    if ($root.distinguishedName -ne $group.distinguishedName) {
      if ($roles.Count -eq 0) {
        [void]($private:roles = @(($group.distinguishedName -replace "CN=([^,]*),.*", "`$1")));
        [void]($result.add($group.distinguishedName,$private:roles.psobject.copy()));
      }
      else {
        [void]($private:existingRoles = $result[$group.distinguishedName]);
        if ($private:existingRoles) {
          [void]($roles | ForEach-Object { $private:existingRoles += $_; });
          [void]($result[$group.distinguishedName] = $private:existingRoles);
        }
        else {
          [void]($result.add($group.distinguishedName, $roles.psobject.copy()));
        }
        [void]($private:roles = $roles.psobject.copy());
      }
    }
    Get-ADGroupMember $group |
    Where-Object { $_.objectClass -eq "group" } |
    ForEach-Object { Get-ADGroupRoles $_ $private:roles $result $root }
  }
}
Get-ADGroupRoles WebAppX_Users  | ConvertTo-Json -Depth 5 | Format-Json
{
    "CN=Interim_Group3,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
        "Admin",
        "User"
    ],
    "CN=Admin,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
        "Admin"
    ],
    "CN=Interim_Group2,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
        "User"
    ],
    "CN=User,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
        "User"
    ],
    "CN=Interim_Group1,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
        "User"
    ],
    "CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=local": [
        "User"
    ],
    "CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
        "User"
    ]
}

Group and User configurations in the above script

function Get-ADTree {
  param( $group )
  
  if ($group.GetType().FullName -eq "System.String") {
    Get-ADTree (Get-ADGroup $group);
  }
  elseif ($group.ObjectClass -eq "group") {
    @{$group.distinguishedName=(Get-ADGroupMember $group | ForEach-Object { Get-ADTree $_ })}
  }
  else {
    $group.distinguishedName
  }
}
Get-ADTree WebAppX_Users  | ConvertTo-Json -Depth 7 | Format-Json
{
    "CN=WebAppX_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
        {
            "CN=Admin,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
                "CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
                {
                    "CN=Interim_Group3,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
                        "CN=SecA User4,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
                        "CN=SecA User5,OU=SectionA,OU=DevDepartment,DC=example,DC=local"
                    ]
                }
            ]
        },
        {
            "CN=User,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
                {
                    "CN=SecA_Users,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
                        "CN=SecA User1,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
                        "CN=SecA User2,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
                        "CN=SecA User3,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
                        "CN=SecA User4,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
                        "CN=SecA User5,OU=SectionA,OU=DevDepartment,DC=example,DC=local"
                    ]
                },
                {
                    "CN=SecB_Users,OU=SectionB,OU=DevDepartment,DC=example,DC=local": [
                        "CN=SecB User1,OU=SectionB,OU=DevDepartment,DC=example,DC=local",
                        "CN=SecB User2,OU=SectionB,OU=DevDepartment,DC=example,DC=local"
                    ]
                },
                {
                    "CN=Interim_Group1,OU=SectionA,OU=DevDepartment,DC=example,DC=local": {
                        "CN=Interim_Group2,OU=SectionA,OU=DevDepartment,DC=example,DC=local": {
                            "CN=Interim_Group3,OU=SectionA,OU=DevDepartment,DC=example,DC=local": [
                                "CN=SecA User4,OU=SectionA,OU=DevDepartment,DC=example,DC=local",
                                "CN=SecA User5,OU=SectionA,OU=DevDepartment,DC=example,DC=local"
                            ]
                        }
                    }
                }
            ]
        }
    ]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment