Loading test/fakeldap.cpp +59 −0 Changes for test/fakeldap.cpp: 59 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -204,6 +204,16 @@ Server::Server(std::vector<Object> objects, std::string bindDn, std::string bind _acceptThread = std::thread(&Server::acceptLoop, this); } bool Server::object(const std::string &dn, Object &out) { std::lock_guard<std::mutex> l(_objectsLock); for (const Object &o : _objects) if (lower(o.dn) == lower(dn)) { out = o; return true; } return false; } Server::~Server() { _stop = true; ::shutdown(_listen, SHUT_RDWR); Loading Loading @@ -263,10 +273,59 @@ std::string Server::answer(const ldap::Message &m, bool &bound, bool &quit) { return message(m.id, bound ? result(ldap::BindResponse, 0) : result(ldap::BindResponse, 49, "80090308: LdapErr: invalid credentials")); } if (m.op == ldap::AddRequest || m.op == ldap::ModifyRequest) { uint8_t resp = m.op == ldap::AddRequest ? ldap::AddResponse : ldap::ModifyResponse; if (!bound) return message(m.id, result(resp, 1, "a successful bind must be completed")); ber::Reader r(m.body); std::string dn = r.next(ber::OctetString).content; ber::Reader list(r.next(ber::Sequence).content); std::lock_guard<std::mutex> l(_objectsLock); Object *o = nullptr; for (Object &x : _objects) if (lower(x.dn) == lower(dn)) o = &x; if (m.op == ldap::AddRequest) { if (o) return message(m.id, result(resp, 68, "entry already exists")); Object n{ dn, {} }; while (!list.atEnd()) { ber::Reader a(list.next(ber::Sequence).content); std::string type = a.next(ber::OctetString).content; std::vector<std::string> vals; ber::Reader v(a.next(ber::Set).content); while (!v.atEnd()) vals.push_back(v.next(ber::OctetString).content); n.attrs.emplace_back(type, vals); } _objects.push_back(n); return message(m.id, result(resp, 0)); } if (!o) return message(m.id, result(resp, 32, "no such object")); while (!list.atEnd()) { ber::Reader c(list.next(ber::Sequence).content); int op = (int)ber::toInt(c.next(ber::Enumerated)); ber::Reader a(c.next(ber::Sequence).content); std::string type = a.next(ber::OctetString).content; std::vector<std::string> vals; ber::Reader v(a.next(ber::Set).content); while (!v.atEnd()) vals.push_back(v.next(ber::OctetString).content); auto it = o->attrs.begin(); for (; it != o->attrs.end(); ++it) if (lower(it->first) == lower(type)) break; if (op == 2) { /* replace */ if (it != o->attrs.end()) it->second = vals; else o->attrs.emplace_back(type, vals); } else if (op == 0) { if (it != o->attrs.end()) it->second.insert(it->second.end(), vals.begin(), vals.end()); else o->attrs.emplace_back(type, vals); } else if (it != o->attrs.end()) { o->attrs.erase(it); } } return message(m.id, result(resp, 0)); } if (m.op != ldap::SearchRequest) return message(m.id, result(ldap::ExtendedResponse, 2, "unsupported")); if (!bound) return message(m.id, result(ldap::SearchResultDone, 1, "a successful bind must be completed")); std::lock_guard<std::mutex> objLock(_objectsLock); _searches++; ber::Reader r(m.body); Loading test/fakeldap.h +3 −0 Changes for test/fakeldap.h: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ public: int port() const { return _port; } /* how many searches were answered */ int searches() const { return _searches; } /* the object with this DN as it is now (after adds and modifies) */ bool object(const std::string &dn, Object &out); private: void acceptLoop(); Loading @@ -63,6 +65,7 @@ private: std::string answer(const adconnect::ldap::Message &m, bool &bound, bool &quit); std::vector<Object> _objects; std::mutex _objectsLock; std::string _bindDn, _bindPassword; int _listen = -1; int _port = 0; Loading Loading
test/fakeldap.cpp +59 −0 Changes for test/fakeldap.cpp: 59 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -204,6 +204,16 @@ Server::Server(std::vector<Object> objects, std::string bindDn, std::string bind _acceptThread = std::thread(&Server::acceptLoop, this); } bool Server::object(const std::string &dn, Object &out) { std::lock_guard<std::mutex> l(_objectsLock); for (const Object &o : _objects) if (lower(o.dn) == lower(dn)) { out = o; return true; } return false; } Server::~Server() { _stop = true; ::shutdown(_listen, SHUT_RDWR); Loading Loading @@ -263,10 +273,59 @@ std::string Server::answer(const ldap::Message &m, bool &bound, bool &quit) { return message(m.id, bound ? result(ldap::BindResponse, 0) : result(ldap::BindResponse, 49, "80090308: LdapErr: invalid credentials")); } if (m.op == ldap::AddRequest || m.op == ldap::ModifyRequest) { uint8_t resp = m.op == ldap::AddRequest ? ldap::AddResponse : ldap::ModifyResponse; if (!bound) return message(m.id, result(resp, 1, "a successful bind must be completed")); ber::Reader r(m.body); std::string dn = r.next(ber::OctetString).content; ber::Reader list(r.next(ber::Sequence).content); std::lock_guard<std::mutex> l(_objectsLock); Object *o = nullptr; for (Object &x : _objects) if (lower(x.dn) == lower(dn)) o = &x; if (m.op == ldap::AddRequest) { if (o) return message(m.id, result(resp, 68, "entry already exists")); Object n{ dn, {} }; while (!list.atEnd()) { ber::Reader a(list.next(ber::Sequence).content); std::string type = a.next(ber::OctetString).content; std::vector<std::string> vals; ber::Reader v(a.next(ber::Set).content); while (!v.atEnd()) vals.push_back(v.next(ber::OctetString).content); n.attrs.emplace_back(type, vals); } _objects.push_back(n); return message(m.id, result(resp, 0)); } if (!o) return message(m.id, result(resp, 32, "no such object")); while (!list.atEnd()) { ber::Reader c(list.next(ber::Sequence).content); int op = (int)ber::toInt(c.next(ber::Enumerated)); ber::Reader a(c.next(ber::Sequence).content); std::string type = a.next(ber::OctetString).content; std::vector<std::string> vals; ber::Reader v(a.next(ber::Set).content); while (!v.atEnd()) vals.push_back(v.next(ber::OctetString).content); auto it = o->attrs.begin(); for (; it != o->attrs.end(); ++it) if (lower(it->first) == lower(type)) break; if (op == 2) { /* replace */ if (it != o->attrs.end()) it->second = vals; else o->attrs.emplace_back(type, vals); } else if (op == 0) { if (it != o->attrs.end()) it->second.insert(it->second.end(), vals.begin(), vals.end()); else o->attrs.emplace_back(type, vals); } else if (it != o->attrs.end()) { o->attrs.erase(it); } } return message(m.id, result(resp, 0)); } if (m.op != ldap::SearchRequest) return message(m.id, result(ldap::ExtendedResponse, 2, "unsupported")); if (!bound) return message(m.id, result(ldap::SearchResultDone, 1, "a successful bind must be completed")); std::lock_guard<std::mutex> objLock(_objectsLock); _searches++; ber::Reader r(m.body); Loading
test/fakeldap.h +3 −0 Changes for test/fakeldap.h: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ public: int port() const { return _port; } /* how many searches were answered */ int searches() const { return _searches; } /* the object with this DN as it is now (after adds and modifies) */ bool object(const std::string &dn, Object &out); private: void acceptLoop(); Loading @@ -63,6 +65,7 @@ private: std::string answer(const adconnect::ldap::Message &m, bool &bound, bool &quit); std::vector<Object> _objects; std::mutex _objectsLock; std::string _bindDn, _bindPassword; int _listen = -1; int _port = 0; Loading