')
+
+ self.issueEvent(event.subject, 'send_msg', resp)
+
+ return True
+
+
+def usage():
+ print "Usage: " + sys.argv[0] + " ARGUMENT... [OPTIONS]... bindip bindport\n"
+ print "Start a webserver on the given bindip and bindport. On the page a"
+ print "tree representation of all DNs starting with a given base DN is"
+ print "visualized."
+ print "Only simple binds to the directory with DN and password are supported.\n"
+ print "ARGUMENTS:\n"
+ print " {:30s} : {:s}".format('-H, --hosturi=URI', 'The URI to the ldap server to query in the form:')
+ print " {:30s} {:s}".format('', 'ldap[s]://host.uri[:port]')
+ print " {:30s} : {:s}".format('-D, --binddn=DN', 'The DN to use for the LDAP bind.')
+ print " {:30s} : {:s}".format('-p, --password=PASSWORD', 'The password to use for the LDAP bind.')
+ print " {:30s} : {:s}\n".format('-b, --basedn=DN', 'The DN to start the tree with.')
+ print "OPTIONS:\n"
+ print " {:30s} : {:s}".format('-h, --help', 'Show this help page')
+
+def main():
+ try:
+ opts, args = getopt.getopt(
+ sys.argv[1:],
+ 'hH:D:b:p:',
+ ['help', 'hosturi=', 'binddn=', 'basedn=', 'password='])
+ except getopt.GetoptError as err:
+ print str(err)
+ usage()
+ sys.exit(2)
+
+ hosturi = binddn = basedn = password = None
+
+ for o, a in opts:
+ if o in ["-h", "--help"]:
+ usage()
+ sys.exit(0)
+ elif o in ["-H", "--hosturi"]:
+ hosturi = a
+ elif o in ["-D", "--binddn"]:
+ binddn = a
+ elif o in ["-b", "--basedn"]:
+ basedn = a
+ elif o in ["-p", "--password"]:
+ password = a
+ else:
+ print "unknown parameter: " + a
+ usage()
+ sys.exit(2)
+
+ if not hosturi or not binddn or not basedn or not password:
+ usage()
+ sys.exit(2)
+
+ server = Server(
+ Application(
+ args[0], int(args[1], hosturi, binddn, basedn, password))
+ server.bindTcp(args[0], int(args[1]), Http())
+ server.start(1.0)
+
+if __name__ == '__main__':
+ main()
+# vim: set ft=python et ts=8 sw=4 sts=4:
diff --git a/ldaptree.py b/ldaptree.py
index 57bcb80..66cfabf 100755
--- a/ldaptree.py
+++ b/ldaptree.py
@@ -1,7 +1,9 @@
#!/usr/bin/python
from os.path import dirname, realpath
import getopt, sys
+reload(sys)
sys.path.append(dirname(realpath(__file__)) + '/lib')
+sys.setdefaultencoding('utf-8')
import getpass
from LdapTree import LdapTree
diff --git a/lib/Communication/Connection.py b/lib/Communication/Connection.py
index 872bc05..7eb0991 100644
--- a/lib/Communication/Connection.py
+++ b/lib/Communication/Connection.py
@@ -31,7 +31,7 @@ class Connection(CommunicationEndPoint):
if not self._current_msg or self._current_msg.ready():
self._current_msg = self._protocol.createMessage(
self.getTransport().remote)
-
+
end = self._protocol.getParser().parse(
self._current_msg, self._read_buffer)
diff --git a/lib/LdapTree.py b/lib/LdapTree.py
index 7c59f7b..bd44136 100644
--- a/lib/LdapTree.py
+++ b/lib/LdapTree.py
@@ -1,6 +1,10 @@
+from os.path import dirname, realpath
+
import ldap
import pygraphviz as pgv
+from jinja2 import Environment, FileSystemLoader
+
class LdapTree(object):
def __init__(self, hosturi, binddn, basedn, password, use_gssapi):
#ldap.set_option(ldap.OPT_DEBUG_LEVEL, 1)
@@ -19,16 +23,23 @@ class LdapTree(object):
self._basedn = basedn
self._ldap_result = []
+ self._data = None
+
def text(self, filename = None):
"""
Returns a text representing the directory.
If filename is given it will be written in that file.
"""
+ env = Environment(loader=FileSystemLoader(
+ dirname(dirname(realpath(__file__))) + '/templates'))
+ template = env.get_template('simple.txt.j2')
+ text = template.render(ldaptree=self).encode('utf8')
+
if filename:
with open(filename, "w") as text_file:
- text_file.write(self._text(self._basedn, 0))
+ text_file.write(text)
else:
- return self._text(self._basedn, 0)
+ return text
def graph(self, filename = None):
"""
@@ -54,26 +65,11 @@ class LdapTree(object):
else:
return graph.draw(format='svg')
- def _text(self, dn, level):
- """
- Recursive function that returns a string representation of the
- directory where each depth is indicated by a dash.
- """
- result = self._ldap.search_s(dn, ldap.SCOPE_ONELEVEL)
- indent = '-' * level
- text = indent + dn + "\n"
-
- for entry in (entry[0] for entry in result):
- if entry:
- text += self._text(entry, level + 1)
-
- return text
-
def _graph(self, graph, dn):
"""
Recursive function creating a graphviz graph from the directory.
"""
- result = self._ldap.search_s(dn, ldap.SCOPE_ONELEVEL)
+ result = self.node(dn)
minlen = thislen = 1
edge_start = dn
@@ -85,6 +81,7 @@ class LdapTree(object):
sub.add_node(
point, shape='circle', fixedsize='true', width='0.04',
label='', fillcolor='transparent')
+ #sub.add_node(entry, URL='https://www.google.de/')
sub.add_node(entry)
graph.add_edge(edge_start, point, arrowhead='none',
minlen=str(minlen))
@@ -94,3 +91,62 @@ class LdapTree(object):
thislen += minlen
return thislen
+
+ @property
+ def all(self):
+ if self._data == None:
+ self._data = {}
+ result = self._ldap.search_s(self._basedn, ldap.SCOPE_SUBTREE)
+ for entry in result:
+ self._data[entry[0]] = entry[1:][0]
+
+ return self._data
+
+ @property
+ def dn_tree(self):
+ retval = {}
+ for d in self.all.keys():
+ current = retval
+ for k in reversed(d.split(',')):
+ try:
+ current = current[k]
+ except:
+ current[k] = {}
+ current = current[k]
+ return retval
+
+ @property
+ def hirarchy(self):
+ return self._hirarchy(self.dn_tree)
+
+ def _hirarchy(self, dn, base=[], depth=0):
+ """
+ Hirarchie generates a flat list where each parent is
+ followed by all its childs, so that in a template one
+ can simple iterate over it to display the complete tree.
+ Recently I learned that "recursive loops" are possible
+ within jinja2. So we can alter the template that it
+ ensures child displays correctly
+ """
+ retval = []
+ for d in dn.keys():
+ base_name = ','.join(reversed(base))
+ name = ','.join(reversed(base + [d]))
+ retval.append((depth, base_name, name))
+ retval += self._hirarchy(dn[d], base + [d], depth+1)
+ return retval
+
+ def childs(self, dn):
+ """
+ Recently I learned that "recursive loops" are possible
+ within jinja2. So we can alter the template that it
+ ensures child displays correctly. So this function should
+ return all child dn's to a given dn.
+ """
+ return [d for d in self.hirarchy if d[1] == dn]
+
+ def node(self, dn):
+ if dn in self.all:
+ return self.all[dn]
+ else:
+ return {}
diff --git a/lib/Transport/TcpSocket.py b/lib/Transport/TcpSocket.py
index 4e850a6..6985d37 100644
--- a/lib/Transport/TcpSocket.py
+++ b/lib/Transport/TcpSocket.py
@@ -62,13 +62,13 @@ class TcpSocket(Socket):
def recv(self, size):
data = ''
- try:
+ try:
data = self.socket.recv(size)
except socket.error as error:
if error.errno not in CONTINUE:
raise Transport.Error(Transport.Error.ERR_FAILED)
return None
-
+
if not data:
raise Transport.Error(Transport.Error.ERR_REMOTE_CLOSE)
@@ -76,7 +76,7 @@ class TcpSocket(Socket):
def send(self, data, remote=None):
send = 0
- try:
+ try:
if self.socket:
send = self.socket.send(data)
except socket.error as error:
diff --git a/templates/simple.html.j2 b/templates/simple.html.j2
new file mode 100644
index 0000000..cdc8f04
--- /dev/null
+++ b/templates/simple.html.j2
@@ -0,0 +1,89 @@
+
+
+
+
+ Ldap
+
+
+
+
+
Ldap
+
+
+
+
+ {% set depth=0 -%}
+ {% for d in ldaptree.hirarchy -%}
+ {% if depth>=d[0] and depth!=0 -%}
+
+
+
+ {% endif -%}
+ {% if depth < d[0] -%}
+ {% set depth=d[0] -%}
+
+ {% endif -%}
+ {% if depth > d[0] -%}
+ {% for i in range(depth-d[0]) -%}
+