[cpif] r54 - in trunk: . backend frontend-web

svn at argo.es svn at argo.es
Sat May 19 21:33:35 CEST 2007


Author: jcea
Date: Sat May 19 21:33:33 2007
New Revision: 54

Log:
Creacion de nuevos usuarios.

Todos los accesos son autentificados.

Por defecto existe un usuario "master", que
puede crear usuarios nuevos y parar el servicio.

La clave de dicho usuario se pasa como parametro
al lanzar el servicio. Es decir,
"python init.py MASTERKEY".

Una vez creado ese usuario, siempre que lancemos
el servicio ES NECESARIO indicar la MISMA masterkey.



Added:
   trunk/frontend-web/url_nuevo_usuario.py
      - copied, changed from r53, /trunk/frontend-web/url_stop.py
   trunk/frontend-web/url_nuevo_usuario_POST.py
      - copied, changed from r53, /trunk/frontend-web/url_stop.py
Modified:
   trunk/TODO
   trunk/backend/database.py
   trunk/frontend-web/init.py
   trunk/frontend-web/servidor_web.py
   trunk/frontend-web/url_.py
   trunk/frontend-web/url_INVALIDA.py
   trunk/frontend-web/url_hilo.py
   trunk/frontend-web/url_nuevo_hilo_POST.py
   trunk/frontend-web/url_nuevo_post_POST.py
   trunk/frontend-web/url_stop.py
   trunk/frontend-web/url_todo_leido.py

Modified: trunk/TODO
==============================================================================
--- trunk/TODO	(original)
+++ trunk/TODO	Sat May 19 21:33:33 2007
@@ -40,3 +40,9 @@
 
   Ver http://en.wikipedia.org/wiki/Cross_site_scripting
 
+- 20070519: FRONTAL WEB: Ahora que hacemos varias transacciones
+  por acceso web, podemos tener inconsistencias entre ellas. Por
+  ejemplo, verificar la autentificacion de un usuario, y que
+  el usuario desaparezca subitamente entre esa verificacion
+  y el calculo de su indice de hilos, por ejemplo.
+

Modified: trunk/backend/database.py
==============================================================================
--- trunk/backend/database.py	(original)
+++ trunk/backend/database.py	Sat May 19 21:33:33 2007
@@ -1,7 +1,7 @@
 # $Id$
 
 
-VERSION_DB="2007051102"
+VERSION_DB="2007051901"
 
 
 def normaliza_nick(nick) :
@@ -46,7 +46,36 @@
 
   init()
 
-def usuario_add(conn,nick,datos) :
+# Si suministramos una cookie, de ahi se saca el
+# usuario y se comprueba su identidad.
+# Si pasamos nick/clave, de ahi comprobamos tambien su identidad
+# Si SOLO pasamos un nick, solo comprobamos si el usuario existe,
+# pero no verificamos identidad.
+def usuario_verifica(conn,nick=None,clave=None,cookie=None) :
+  root=conn.get_root()
+
+  if clave :
+    usuario=root["usuarios"]["usuarios"].get(normaliza_nick(nick),None)
+    if usuario and (clave==usuario["clave"]) :
+      import random,sys
+      cookie=str(random.randint(0,sys.maxint))+str(random.randint(0,sys.maxint))
+      usuario["cookie"]=cookie
+      cookie="%s-%s" %(nick,cookie)
+      return nick,cookie
+  elif cookie :
+    i=cookie.rfind("-")
+    if i<=0 : return None # Al menos un caracter
+    nick=cookie[:i]
+    cookie=cookie[i+1:] # Nos saltamos el "-"
+    usuario=root["usuarios"]["usuarios"].get(normaliza_nick(nick),None)
+    if usuario and (cookie==usuario["cookie"]) :
+      return nick,None
+  elif nick :
+    return normaliza_nick(nick) in root["usuarios"]["usuarios"]
+
+  return None
+
+def usuario_add(conn,nick,datos,clave=None) :
   from durus.btree import BTree
   from durus.persistent_dict import PersistentDict
   import time
@@ -59,6 +88,10 @@
 
   usuarios["num_usuarios"]+=1
 
+  if not clave :
+    import random,sys
+    clave=str(random.randint(0,sys.maxint))
+
   usuarios["usuarios"][nick_normalizado]=PersistentDict(
                        {"ultimo mensaje conocido":root["mensajes"]["num_mensajes"],
                         "punto de lectura no leidos":BTree(),
@@ -68,6 +101,8 @@
                         "num mensajes":0,
                         "mensajes":BTree(),
                         "datos":datos,
+                        "clave":clave,
+                        "cookie":None,
                         "nick":nick})
 
 def usuario_get(conn,nick) :

Modified: trunk/frontend-web/init.py
==============================================================================
--- trunk/frontend-web/init.py	(original)
+++ trunk/frontend-web/init.py	Sat May 19 21:33:33 2007
@@ -18,7 +18,13 @@
   database.init_database(monitor)
 
   @monitor
-  def inicializa(conn) :
+  def inicializa(conn,masterkey) :
+    master=conn.get_root()["usuarios"]["usuarios"].get("master",None)
+    if master :
+      assert master["clave"]==masterkey
+    else :
+      database.usuario_add(conn,"master",None,clave=masterkey)
+
     usuarios=("Usuario1","Usuario2")
     for i in usuarios :
       if not database.usuario_get(conn,i) :
@@ -40,7 +46,7 @@
         database.mensaje_add(conn,"Cuerpo del hilo %d" %i,r.sample(usuarios,1)[0],titulo="Hilo %d" %i)
       time.time=t
 
-  inicializa()
+  inicializa(masterkey=sys.argv[1])
 
 # Lanzamos el servidor web en un hilo separado
   from servidor_web import servidor_web

Modified: trunk/frontend-web/servidor_web.py
==============================================================================
--- trunk/frontend-web/servidor_web.py	(original)
+++ trunk/frontend-web/servidor_web.py	Sat May 19 21:33:33 2007
@@ -11,30 +11,54 @@
     must_stop=False
 
     @monitor
-    def elige_usuario(conn,self) :
-      usuarios=[i["nick"] for i in conn.get_root()["usuarios"]["usuarios"].values()]
-      texto=["<p><li><a href='/%s'>%s</a>" %(i,i) for i in usuarios]
+    def elige_usuario(conn,self,path) :
+      if path[0]=="LOGIN" :
+        import cgi,database
+        path.pop(0)
+        ctype,pdict=cgi.parse_header(self.headers.getheader('content-type'))
+        cuerpo=cgi.FieldStorage(fp=self.rfile,headers=self.headers,environ={'REQUEST_METHOD':'POST'},keep_blank_values=1)
+        usuario=cuerpo.getfirst("usuario")
+        clave=cuerpo.getfirst("clave")
+        if usuario and clave :
+          resultado=database.usuario_verifica(conn,nick=usuario,clave=clave)
+          if resultado :
+            nick,cookie=resultado
+            if cookie :
+              cookie="cpif_auth=%s; path=/;" %cookie
+            return (cookie, (302,"/"+"/".join(path),"") )
 
-      return (200,"text/html; charset=utf-8",
+      return (None,(200,"text/html; charset=utf-8",
 """
 <html><head></head>
-<body><h1>Elige el usuario</h1>
-<ul>
-%s
-</ul>
-<p><a href="/stop">Parar la demo</a>
-</body></html>""" %"\r\n".join(texto))
+<body>
+<form action="/LOGIN/%s" method="post" enctype="multipart/form-data">
+<table>
+<tr><td>Usuario:</td><td><input type="text" name="usuario" size="25" value="" /></td></tr>
+<tr><td>Clave:</td><td><input type="password" name="clave" size="25" value="" /></td></tr>
+<tr><td colspan=2 align=right><input class="form-element" type="submit" name="submit" value="Log In"/></td></tr>
+</table>
+</form>
+</body></html>""" % ("/".join(path)) ))
 
     def do_GET(self) :
       global urls
+      cookie=self.headers.get("cookie",None)
+      if cookie :
+        import Cookie
+        cookie=Cookie.SimpleCookie(cookie)
+        print cookie
+        @monitor
+        def verifica(conn,cookie) :
+          import database
+          return database.usuario_verifica(conn,cookie=cookie)
+        cookie=verifica(cookie["cpif_auth"].value)
       try :
         path=self.path.split("/")[1:]
-        usuario=path.pop()
-
-        if not usuario :
-          resultado=self.elige_usuario()
+        if not cookie :
+          cookie,resultado=self.elige_usuario(path)
+          print cookie
         else :
-          if not len(path) : path=[""]
+          usuario,cookie=cookie
           resultado=urls.get(path[0],None)
           if resultado :
             resultado=resultado(self,path,usuario)
@@ -54,8 +78,11 @@
       self.send_response(estado)
       if estado==301 or estado==302 :
         self.send_header("Location",resultado[1])
+        self.send_header("Content-Type","text/html; charset=utf-8")
       else :
         self.send_header("Content-Type",resultado[1])
+      if cookie!=None :
+        self.send_header("Set-Cookie",cookie)
       self.end_headers()
       self.wfile.write(resultado[2])
 

Modified: trunk/frontend-web/url_.py
==============================================================================
--- trunk/frontend-web/url_.py	(original)
+++ trunk/frontend-web/url_.py	Sat May 19 21:33:33 2007
@@ -52,10 +52,10 @@
       estilos.append(estilo)
       ts_creacion=time.ctime(hilos[hilo]["TS"])
       if no_leido :
-        texto.append("<div class='%s'><a href='/hilo/%d/%s'>%s</a> <font size=-2>(%s)</font> - <a href='/hilo/%d/%s#%d'>No leido</a></div>"
-                     %(estilo,hilo,usuario,titulo,ts_creacion,hilo,usuario,punto_no_leido[hilo]))
+        texto.append("<div class='%s'><a href='/hilo/%d'>%s</a> <font size=-2>(%s)</font> - <a href='/hilo/%d#%d'>No leido</a></div>"
+                     %(estilo,hilo,titulo,ts_creacion,hilo,punto_no_leido[hilo]))
       else :
-        texto.append("<div class='%s'><a href='/hilo/%d/%s'>%s</a> <font size=-2>(%s)</font></div>" %(estilo,hilo,usuario,titulo,ts_creacion))
+        texto.append("<div class='%s'><a href='/hilo/%d'>%s</a> <font size=-2>(%s)</font></div>" %(estilo,hilo,titulo,ts_creacion))
     ts=ts2
     fecha-=delta_dia
 
@@ -69,20 +69,21 @@
 .impar {background-color: eef}
 </style>
 
-<p align='right'><a href="/todo_leido/%s">Marcar todos los hilos como leidos</a>
+<p align='right'><a href="/todo_leido">Marcar todos los hilos como leidos</a>
 %s
 <hr>
 %s
 <hr>
-<form action="/nuevo_hilo_POST/%s" method="post" enctype="multipart/form-data">
+<form action="/nuevo_hilo_POST" method="post" enctype="multipart/form-data">
 <table>
 <tr><td>T&iacute;tulo:</td><td><input type="text" name="titulo" size="60" value="" /></td></tr>
 <tr><td>Texto:</td><td><br><textarea name="texto" rows="10" cols="60"></textarea></td></tr>
 <tr><td colspan=2 align=right><input class="form-element" type="submit" name="submit" value="Publicar nuevo hilo"/></td></tr>
 </table>
 </form>
-<p><a href="/stop/cualquier_usuario">Parar la demo</a>
-</body></html>""" %(usuario,"\r\n".join(texto),calendario.vista_mensual(conn,fecha_elegida,usuario),usuario))
+<p><a href="/stop">Parar la demo</a>
+<p><a href="/nuevo_usuario">Dar de alta un nuevo usuario</a>
+</body></html>""" %("\r\n".join(texto),calendario.vista_mensual(conn,fecha_elegida,usuario)))
 
 @monitor
 def init(conn) :

Modified: trunk/frontend-web/url_INVALIDA.py
==============================================================================
--- trunk/frontend-web/url_INVALIDA.py	(original)
+++ trunk/frontend-web/url_INVALIDA.py	Sat May 19 21:33:33 2007
@@ -3,5 +3,13 @@
 from globales import monitor
 
 def gestiona_url(handler,path,usuario) :
-  return (401,"text/html; charset=utf-8","La URL introducida es incorrecta")
+  return (401,"text/html; charset=utf-8",
+"""
+<html><title>La URL introducida es incorrecta</title>
+<body>
+<h1>La URL introducida es incorrecta</h1>
+<p><a href="/">P&aacute;gina principal</a>
+<p><a href="/stop">Parar la demo</a>
+</body></html>
+""")
 

Modified: trunk/frontend-web/url_hilo.py
==============================================================================
--- trunk/frontend-web/url_hilo.py	(original)
+++ trunk/frontend-web/url_hilo.py	Sat May 19 21:33:33 2007
@@ -32,14 +32,14 @@
 </style>
 %s
 <hr>
-<p><a href="/%s">P&aacute;gina principal</a>
-<p><form action="/nuevo_post_POST/%s/%s" method="post" enctype="multipart/form-data">
+<p><a href="/">P&aacute;gina principal</a>
+<p><form action="/nuevo_post_POST/%s" method="post" enctype="multipart/form-data">
 <table>
 <tr><td>Texto:</td><td><br><textarea name="texto" rows="10" cols="60"></textarea></td></tr>
 <tr><td colspan=2 align=right><input class="form-element" type="submit" name="submit" value="Publicar nuevo mensaje"/></td></tr>
 </table>
 </form>
-<p><a href="/stop/cualquier_usuario">Parar la demo</a>
-</body></html>""" %("\r\n".join(texto),usuario,hilo_num,usuario))
+<p><a href="/stop">Parar la demo</a>
+</body></html>""" %("\r\n".join(texto),hilo_num))
 
 

Modified: trunk/frontend-web/url_nuevo_hilo_POST.py
==============================================================================
--- trunk/frontend-web/url_nuevo_hilo_POST.py	(original)
+++ trunk/frontend-web/url_nuevo_hilo_POST.py	Sat May 19 21:33:33 2007
@@ -12,5 +12,5 @@
   texto=texto.replace("\r","").replace("\n","<br>\r\n")
   import database
   database.mensaje_add(conn,texto,usuario,titulo=titulo)
-  return (302,"/%s" %usuario,"")
+  return (302,"/","")
 

Modified: trunk/frontend-web/url_nuevo_post_POST.py
==============================================================================
--- trunk/frontend-web/url_nuevo_post_POST.py	(original)
+++ trunk/frontend-web/url_nuevo_post_POST.py	Sat May 19 21:33:33 2007
@@ -13,5 +13,5 @@
   texto=texto.replace("\r","").replace("\n","<br>\r\n")
   import database
   database.mensaje_add(conn,texto,usuario,hilo=hilo)
-  return (302,"/%s" %(usuario), "")
+  return (302,"/", "")
 

Copied: trunk/frontend-web/url_nuevo_usuario.py (from r53, /trunk/frontend-web/url_stop.py)
==============================================================================
--- /trunk/frontend-web/url_stop.py	(original)
+++ trunk/frontend-web/url_nuevo_usuario.py	Sat May 19 21:33:33 2007
@@ -3,11 +3,28 @@
 from globales import monitor
 
 def gestiona_url(handler,path,usuario) :
-  handler.must_stop=True
+  if usuario!="master" :
+    return(200,"text/html; charset=utf-8",
+"""
+<html><head></head><body>
+<h1>Solo el usuario 'master' puede dar de alta nuevos usuarios</h1>
+<p><a href="/">P&aacute;gina principal</a>
+<p><a href="/stop">Parar la demo</a>
+</body></html>""")
 
   return (200,"text/html; charset=utf-8",
 """
-<html><head></head><body>
-<h1>PARAMOS EL SERVICIO!!</h1>
+<html><head></head>
+<body>
+<form action="/nuevo_usuario_POST" method="post" enctype="multipart/form-data">
+<table>
+<tr><td>Usuario:</td><td><input type="text" name="usuario" size="25" value="" /></td></tr>
+<tr><td>Clave:</td><td><input type="password" name="clave1" size="25" value="" /></td></tr>
+<tr><td>Confirma la clave:</td><td><input type="password" name="clave2" size="25" value="" /></td></tr>
+<tr><td colspan=2 align=right><input class="form-element" type="submit" name="submit" value="Crea usuario"/></td></tr>
+</table>
+</form>
+<p><a href="/">P&aacute;gina principal</a>
+<p><a href="/stop">Parar la demo</a>
 </body></html>""")
 

Copied: trunk/frontend-web/url_nuevo_usuario_POST.py (from r53, /trunk/frontend-web/url_stop.py)
==============================================================================
--- /trunk/frontend-web/url_stop.py	(original)
+++ trunk/frontend-web/url_nuevo_usuario_POST.py	Sat May 19 21:33:33 2007
@@ -2,12 +2,67 @@
 
 from globales import monitor
 
-def gestiona_url(handler,path,usuario) :
-  handler.must_stop=True
-
-  return (200,"text/html; charset=utf-8",
+ at monitor
+def gestiona_url(conn,handler,path,usuario) :
+  if usuario!="master" :
+    return(200,"text/html; charset=utf-8",
 """
 <html><head></head><body>
-<h1>PARAMOS EL SERVICIO!!</h1>
+<h1>Solo el usuario 'master' puede dar de alta nuevos usuarios</h1>
+<p><a href="/">P&aacute;gina principal</a>
+<p><a href="/stop">Parar la demo</a>
 </body></html>""")
+
+  import cgi
+  ctype,pdict=cgi.parse_header(handler.headers.getheader('content-type'))
+  cuerpo=cgi.FieldStorage(fp=handler.rfile,headers=handler.headers,environ={'REQUEST_METHOD':'POST'},keep_blank_values=1)
+  nick=cuerpo.getfirst("usuario").strip()
+  clave1=cuerpo.getfirst("clave1").strip()
+  clave2=cuerpo.getfirst("clave2").strip()
+
+  if not (nick and clave1 and clave2) :
+    return (200,"text/html; charset=utf-8",
+"""
+<html><head></head>
+<body>
+<h1>No puedes dejar ningun campo en blanco</h1>
+<p><a href="/">P&aacute;gina principal</a>
+<p><a href="/stop">Parar la demo</a>
+</body></html>
+""")
+
+  if clave1!=clave2 :
+    return (200,"text/html; charset=utf-8",
+"""
+<html><head></head>
+<body>
+<h1>Las claves introducidas no coinciden</h1>
+<p><a href="/">P&aacute;gina principal</a>
+<p><a href="/stop">Parar la demo</a>
+</body></html>
+""")
+
+  import database
+  if database.usuario_verifica(conn,nick=nick) :
+    return (200,"text/html; charset=utf-8",
+"""
+<html><head></head>
+<body>
+<h1>El usuario ya existe</h1>
+<p><a href="/">P&aacute;gina principal</a>
+<p><a href="/stop">Parar la demo</a>
+</body></html>
+""")
+
+  database.usuario_add(conn,nick,None,clave=clave1)
+
+  return (200,"text/html; charset=utf-8",
+"""
+<html><head></head>
+<body>
+<h1>Alta exitosa</h1>
+<p><a href="/">P&aacute;gina principal</a>
+<p><a href="/stop">Parar la demo</a>
+</body></html>
+""")
 

Modified: trunk/frontend-web/url_stop.py
==============================================================================
--- trunk/frontend-web/url_stop.py	(original)
+++ trunk/frontend-web/url_stop.py	Sat May 19 21:33:33 2007
@@ -3,8 +3,17 @@
 from globales import monitor
 
 def gestiona_url(handler,path,usuario) :
-  handler.must_stop=True
+  if usuario!="master" :
+    return(200,"text/html; charset=utf-8",
+"""
+<html><head></head><body>
+<h1>Solo el usuario 'master' puede parar el servicio</h1>
+<p><a href="/">P&aacute;gina principal</a>
+<p><a href="/stop">Parar la demo</a>
+</body></html>""")
+
 
+  handler.must_stop=True
   return (200,"text/html; charset=utf-8",
 """
 <html><head></head><body>

Modified: trunk/frontend-web/url_todo_leido.py
==============================================================================
--- trunk/frontend-web/url_todo_leido.py	(original)
+++ trunk/frontend-web/url_todo_leido.py	Sat May 19 21:33:33 2007
@@ -6,5 +6,5 @@
 def gestiona_url(conn,handler,path,usuario) :
   import database
   database.marca_todo_leido(conn,usuario)
-  return (302,"/%s" %usuario,"")
+  return (302,"/","")
 



More information about the cpif mailing list