LdapService.py 4.96 KB
#!/usr/bin/python

import time
import random
import mmap

from os.path import dirname, realpath
import sys, getopt
reload(sys)
from sys import path, setdefaultencoding
path.append(dirname(realpath(__file__)) + '/lib')
setdefaultencoding('utf-8')

from struct import pack
from collections import deque

from Server import Server

from Event.EventHandler import EventHandler
from Event.EventDispatcher import EventDispatcher
from Communication.EndPoint import CommunicationEndPoint

from Protocol.Http.Http import Http
from Protocol.Websocket.Websocket import Websocket

from jinja2 import Environment, FileSystemLoader

from LdapTree import LdapTree

class Application(EventHandler):
    def __init__(self, ip, port, hosturi, binddn, basedn, password):
        super(Application, self).__init__()

        self._event_methods = {
            EventDispatcher.eventId('heartbeat')     : self._heartbeat,
            CommunicationEndPoint.eventId('new_msg') : self._handle_data,
            CommunicationEndPoint.eventId('close')   : self._handle_close,
            CommunicationEndPoint.eventId('upgrade') : self._upgrade
        }

        self._websockets = []

        env = Environment(loader=FileSystemLoader(
            dirname(realpath(__file__)) + '/templates'))
        template = env.get_template('websocket.html.j2')
        # TODO get ip and port or better our complete base uri here.
        self._page = template.render(ip=ip, port=port)

        random.seed()

        self.ldaptree = LdapTree(hosturi, binddn, basedn, password, False)

    def _upgrade(self, event):
        self._websockets.append(event.subject)
        # let other also handle the upgrade .. no return True

    def _heartbeat(self, event):
        now = pack('!d', time.time())
        for event.subject in self._websockets:
            self.issueEvent(event.subject, 'send_msg', now)

        return True

    def _handle_data(self, event):
        protocol = event.subject.getProtocol()

        if event.subject.hasProtocol(Http):
            if event.data.isRequest():
                if event.data.getUri() == '/':
                    resp = protocol.createResponse(event.data, 200, 'OK')
                    resp.setBody(self._page)
                elif event.data.getUri() == '/ldap':
                    resp = protocol.createResponse(event.data, 200, 'OK')
                    resp.setHeader('Content-Type', 'image/svg+xml')
                    resp.setBody(self.ldaptree.graph())
                else:
                    resp = protocol.createResponse(
                            event.data, 404, 'Not Found')
                    resp.setBody('<h1>404 - Not Found</h1>')

                self.issueEvent(event.subject, 'send_msg', resp)

        return True

    def _handle_close(self, event):
        if event.subject in self._websockets:
            print 'websocket closed...'
            self._websockets = [w for w in self._websockets if w!=event.subject]

        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: