From 49856f36361a71aba71c43c77cebb22340010181 Mon Sep 17 00:00:00 2001 From: equinox Date: Fri, 1 Apr 2011 05:42:06 +0200 Subject: initial checkin --- .gitignore | 5 ++ dosign.py | 19 ++++++++ index.py | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++ static/app_subdap.png | Bin 0 -> 4579 bytes static/app_wiki.png | Bin 0 -> 3778 bytes static/details.js | 28 +++++++++++ static/fire.png | Bin 0 -> 8663 bytes static/layout.css | 92 ++++++++++++++++++++++++++++++++++++ static/ldap.png | Bin 0 -> 10942 bytes static/logo.png | Bin 0 -> 28959 bytes templates/create.html | 21 +++++++++ templates/error.html | 19 ++++++++ templates/layout.xi | 24 ++++++++++ templates/login.html | 20 ++++++++ templates/select.html | 17 +++++++ tmpl.py | 50 ++++++++++++++++++++ versign.py | 30 ++++++++++++ 17 files changed, 453 insertions(+) create mode 100644 .gitignore create mode 100644 dosign.py create mode 100755 index.py create mode 100644 static/app_subdap.png create mode 100644 static/app_wiki.png create mode 100644 static/details.js create mode 100644 static/fire.png create mode 100644 static/layout.css create mode 100644 static/ldap.png create mode 100644 static/logo.png create mode 100644 templates/create.html create mode 100644 templates/error.html create mode 100644 templates/layout.xi create mode 100644 templates/login.html create mode 100644 templates/select.html create mode 100644 tmpl.py create mode 100644 versign.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..45858e9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +cherrypy.config +*.pyc +*.pem +*.pub +*.orig diff --git a/dosign.py b/dosign.py new file mode 100644 index 0000000..e0d3465 --- /dev/null +++ b/dosign.py @@ -0,0 +1,19 @@ +import M2Crypto.RSA +import M2Crypto.EVP +import time +import base64, urllib + +ts = int(time.time()) +user = 'equinox' +data = '%d:%s' % (ts, user) + +algo = 'sha256' + +digest = M2Crypto.EVP.MessageDigest(algo) +digest.update(data) +digval = digest.final() + +key = M2Crypto.RSA.load_key('rsa.pem') +signature = key.sign(digval, algo = algo) + +print urllib.urlencode([('user', user), ('ts', ts), ('signature', base64.urlsafe_b64encode(signature))]) diff --git a/index.py b/index.py new file mode 100755 index 0000000..0fd89af --- /dev/null +++ b/index.py @@ -0,0 +1,128 @@ +#!/usr/bin/python +# -*- coding: utf8 -*- + +import sys, os, cgi +appbase = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(appbase) + +import threading +import cherrypy +from tmpl import expose, render +from lxml import etree +from lxml.html import formfill +from StringIO import StringIO +import ldap +import mx.DateTime +from accountservice import accountservice + +class ldapobj(object): + def __init__(s, data): + if len(data) != 1: + raise ValueError, "invalid number of results" + dn, fields = data[0] + s._keys = fields.keys() + for k, v in fields.iteritems(): + s.__dict__[k] = v + s.dn = dn + def __getitem__(s, key): + l = s.__dict__[key] + if len(l) != 1: + raise IndexError, "invalid number of attributes" + return l[0] + def keys(s): + return s._keys + +class SubdapSite(object): + def __init__(s): + cherrypy.config.update({'error_page.404': s.http_404}) + + @expose('error.html') + def http_404(s, status, message, **kwargs): + return render(details = status + ' - ' + message) + + @expose('login.html') + def index(s): + return render(errors = {}) + @expose('login.html') + def login(s, username = None, password = None): + if username == None or password == None: + return render(errors = {'password': 'Login incorrect'}) + if username == '' or password == '': + return render(errors = {'password': 'Login incorrect'}) + + dn = "cn=%s,ou=people,dc=sublab,dc=org" % (username) + try: + l = ldap.initialize('ldaps://taifun.local.sublab.org/') + l.simple_bind_s(dn, password) + except ldap.INVALID_CREDENTIALS: + return render(errors = {'password': 'Login incorrect'}) + except ldap.LDAPError, e: + return render(errors = {'password': 'Login incorrect'}) + # e.message['info'] + + user = ldapobj(l.search_s(dn, ldap.SCOPE_BASE, '(objectclass=*)', [])) + return render('select.html', user = user) + +## x = '' +# for r in data: +# if r[0] != dn: +# continue +## x += '%s\n' % (r[0]) +# for k, v in r[1].iteritems(): +# for value in v: +# details.append([k, value]) +## x += '%s
%s
\n' % (k, "
".join(v)) + + @expose('create.html') + def create(s): + return render(errors = {}, username = '') + @expose('create.html') + def docreate(s, username = None, password = None, password2 = None): + errors = {} + if username == None or username == '': + errors['username'] = 'please specify an user name' + elif accountservice.name_valid(username) != 'valid': + errors['username'] = 'username invalid or taken' + if password == None or len(password) < 6: + errors['password'] = 'please specify a password of at least 6 characters' + if password2 != password: + errors['password2'] = 'passwords did not match' + if len(errors) > 0: + return render(errors = errors, username = username) + + accountservice.name_create(username, password) + return s.login(username, password) + + @cherrypy.expose + def kill(s): + import sys + sys.exit(0) + +config = { + 'global': { + 'server.socket_port': 8080, + 'server.socket_host': '127.0.0.1', +# 'server.socket_host': '::1', + 'tools.staticdir.root': appbase, + }, + '/': { + 'tools.decode.on': True, + 'tools.encode.on': True, + 'tools.gzip.on': True, + 'tools.proxy.on': True, +# 'tools.caching.on': False, +# 'tools.expires.secs': 0, +# 'tools.expires.force': True, + }, + '/static': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': 'static', + }, +} + +if len(sys.argv) >= 2 and sys.argv[1] == 'standalone': + cherrypy.quickstart(SubdapSite(), "/", config) +else: + cherrypy.config.update({'environment': 'embedded'}) + application = cherrypy.Application(SubdapSite(), script_name = None, config = config) + diff --git a/static/app_subdap.png b/static/app_subdap.png new file mode 100644 index 0000000..6e985bc Binary files /dev/null and b/static/app_subdap.png differ diff --git a/static/app_wiki.png b/static/app_wiki.png new file mode 100644 index 0000000..80c894b Binary files /dev/null and b/static/app_wiki.png differ diff --git a/static/details.js b/static/details.js new file mode 100644 index 0000000..bd42bb4 --- /dev/null +++ b/static/details.js @@ -0,0 +1,28 @@ + +function add(type) { + var node = document.getElementById("hperson"); + + ntr = document.createElement("tr"); + ntd = document.createElement("td"); + ntxt = document.createTextNode("x"); + ntd.appendChild(ntxt); + ntr.appendChild(ntd); + + node.parentNode.insertBefore(ntr, node); + + window.alert('tag' + node.nodeName); + for (node = node.nextSibling; node != null; node = node.nextSibling) { + window.alert('tag' + node.nodeName); + if (node.nodeName != 'TR') + continue; + var td = node.getElementsByTagName("TD"); + if (td == null) + continue; + var input = td[1].getElementsByTagName("INPUT"); + if (input == null) + continue; + for (var k = 0; k < input.length; k++) + input[k].style.display = 'none'; + } +} + diff --git a/static/fire.png b/static/fire.png new file mode 100644 index 0000000..4d9ff87 Binary files /dev/null and b/static/fire.png differ diff --git a/static/layout.css b/static/layout.css new file mode 100644 index 0000000..eb670f5 --- /dev/null +++ b/static/layout.css @@ -0,0 +1,92 @@ +body, table { + font-family:sans; + font-size:11pt; +} +body#formcont { + margin:auto; + text-align:center; +} +body#formcont < div { + display:inline-block; +} +img#logo { + display:inline-block; + margin:3em; + margin-right:0.5em; +} +body#formcont form, +body#formcont div.cont { + display:inline-block; + vertical-align:top; + text-align:right; + border-left:1px solid #ccc; + margin:3em; + margin-left:0.5em; + padding:2em; + min-height:180px; +} + +p.app { + border:1px solid #ccc; + padding:2pt; + padding-right:8pt; +} +p.app img { + display:inline-block; + margin:2px; + border:0px; + vertical-align:middle; +} +p.app a { + text-decoration:none; +} + +a#create { + display:block; + font-size:75%; + text-align:right; + margin-bottom:1em; +} +b.error { + display:block; + color:red; + font-style:italic; + font-size:9pt; + margin-bottom:3pt; + max-width:15em; +} +div#creatpw { + margin-top:1em; +} +input[type=submit] { + margin-top:1em; +} +body#error img { + float:left; + margin:2em; + margin-right:0.5em; +} +body#error div#cont { + margin:2em; + margin-left:260px; + border-left:1px solid #ccc; + padding:1em; + padding-bottom:10em; +} +body#error h1 { + margin-top:1em; +} +body#error code { + font-size:10pt; +} +body#error pre { + max-width:45em; + font-size:8.5pt; + border:1px solid #d73f0b; + padding:1em; + background-color:#210; + color:#ffb100; +} + + + diff --git a/static/ldap.png b/static/ldap.png new file mode 100644 index 0000000..cc7559c Binary files /dev/null and b/static/ldap.png differ diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000..e1968a0 Binary files /dev/null and b/static/logo.png differ diff --git a/templates/create.html b/templates/create.html new file mode 100644 index 0000000..2ac6563 --- /dev/null +++ b/templates/create.html @@ -0,0 +1,21 @@ + + + + + create + + +
+
uid:
+ ${errors.username} +
password:
+ ${errors.password} +
repeat:
+ ${errors.password2} + +
+
+ diff --git a/templates/error.html b/templates/error.html new file mode 100644 index 0000000..0399863 --- /dev/null +++ b/templates/error.html @@ -0,0 +1,19 @@ + + + + + login + + + subdap +
+

kaputt!

+

subdap.exe hat ein Problem festgestellt und musste beendet werden.
+ Bitte schicken sie einen Fehlerbericht an equinox ! diac24 ! net.

+
${details}
+
+ + diff --git a/templates/layout.xi b/templates/layout.xi new file mode 100644 index 0000000..6a5418a --- /dev/null +++ b/templates/layout.xi @@ -0,0 +1,24 @@ + + + + + + subdap<py:if test="title">: ${title}</py:if> + + ${select('*[local-name()!="title"]')} + + + + + +
+ + ${select('*')} +
+ +
+ diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..41b6c43 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,20 @@ + + + + + login + + +
+ Konto erstellen +
uid:
+ ${errors.username} +
passwort:
+ ${errors.password} + +
+
+ diff --git a/templates/select.html b/templates/select.html new file mode 100644 index 0000000..e7dc1f2 --- /dev/null +++ b/templates/select.html @@ -0,0 +1,17 @@ + + + + + login + + +
+ Hallo ${user['cn']}! +

wiki sublab.org wiki

+

wiki Benutzerdaten

+
+
+ diff --git a/tmpl.py b/tmpl.py new file mode 100644 index 0000000..6551728 --- /dev/null +++ b/tmpl.py @@ -0,0 +1,50 @@ +import os, traceback + +import cherrypy +from genshi.core import Stream +from genshi.output import encode, get_serializer +from genshi.template import Context, TemplateLoader + +loader = TemplateLoader( + os.path.join(os.path.dirname(__file__), 'templates'), + auto_reload=True +) + +def render(*args, **kwargs): + if args: + assert len(args) == 1, 'Expected exactly one argument, but got %r' % (args,) + template = loader.load(args[0]) + else: + template = cherrypy.thread_data.template + #ctxt = Context(url = cherrypy.url) + ctxt = Context(url = myurl) + ctxt.push(kwargs) + return template.generate(ctxt) + +def exc(exc): + return render('error.html', details = traceback.format_exc()) + +def expose(filename, method='html', encoding='utf-8', **options): + def decorate(func): + @cherrypy.expose + def wrapper(*args, **kwargs): + cherrypy.thread_data.template = loader.load(filename) + cherrypy.thread_data.func = func + opt = options.copy() + if method == 'html': + opt.setdefault('doctype', 'html') + serializer = get_serializer(method, **opt) + try: + stream = func(*args, **kwargs) + except Exception, e: + stream = exc(e) + if not isinstance(stream, Stream): + return stream + return encode(serializer(stream), method = serializer, encoding = encoding) + return wrapper + return decorate + +def myurl(url): + return '/subdap/' + url + + diff --git a/versign.py b/versign.py new file mode 100644 index 0000000..aa406df --- /dev/null +++ b/versign.py @@ -0,0 +1,30 @@ +import M2Crypto.RSA +import M2Crypto.EVP +import time, sys +import base64, cgi + +str = sys.argv[1] +data = cgi.parse_qs(str) + +ts = int(data['ts'][0]) +user = data['user'][0] +signature = base64.urlsafe_b64decode(data['signature'][0]) + +data = '%d:%s' % (ts, user) + +algo = 'sha256' + +digest = M2Crypto.EVP.MessageDigest(algo) +digest.update(data) +digval = digest.final() + +key = M2Crypto.RSA.load_pub_key('rsa.pub') + +try: + if key.verify(digval, signature, algo = algo): + print 'OKAY' + else: + print 'FAIL' +except: + print 'FAIL (hard)' + -- cgit v1.2.1