Explorar el Código

autenticazione e controllo (elementare) dei permessi. NON funziona come singleton.

auth
Andrea Papotti hace 13 años
padre
commit
e0b50b620c
Se han modificado 11 ficheros con 143 adiciones y 15 borrados
  1. +16
    -0
      controllers/admin.py
  2. +1
    -1
      controllers/demo/due.py
  3. +17
    -0
      controllers/forbidden.py
  4. +40
    -0
      controllers/login.py
  5. +19
    -0
      controllers/logout.py
  6. +2
    -1
      controllers/secret.py
  7. +42
    -7
      decorators.py
  8. +1
    -1
      dispatch_wsgi.py
  9. +1
    -4
      router.py
  10. BIN
     
  11. +4
    -1
      static/index.html

+ 16
- 0
controllers/admin.py Ver fichero

@@ -0,0 +1,16 @@
#!/usr/bin/python
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-

from decorators import WSGISimpleAuth # decoratore ( singleton )
auth = WSGISimpleAuth()

@auth.require( 'admin superadmin hyperadmin' )
def application( environ, start_response ):
storage = environ['auth.storage']

start_response( '200 OK', [('content-type', 'text/html; charset=utf-8')] )

return [
"<h1>GOSH BATMAN! HOW DID SHE DO THE IMPOSSIBLE?</h1>",
"<a href='/index.html'>index</a>"
]

+ 1
- 1
controllers/demo/due.py Ver fichero

@@ -18,4 +18,4 @@ def application( environ, start_response ):

start_response( '200 OK', [('content-type', 'text/html; charset=utf-8')] )

return [ html, '<br><br><hr><br>', '<pre>', pformat( environ, width=132 ), '</pre>' ] # TODO: pformat..... ---> trasformarlo in un decoratore
return [ html, '<br><br><hr><br>', '<pre>', pformat( environ, width=132 ), '</pre>' ]

+ 17
- 0
controllers/forbidden.py Ver fichero

@@ -0,0 +1,17 @@
#!/usr/bin/python
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-

from decorators import WSGISimpleAuth # decoratore ( singleton )
auth = WSGISimpleAuth()

def application( environ, start_response ):
start_response( '200 OK', [('content-type', 'text/html; charset=utf-8')] )

return [
"<center>",
"<h1>FORBIDDEN</h1>",
"<img src='/attack_dog.jpg'>",
"<br><br><br>",
"Maybe you should go back to <a href='/index.html'>index</a>",
"</center>"
]

+ 40
- 0
controllers/login.py Ver fichero

@@ -0,0 +1,40 @@
#!/usr/bin/python
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-

from decorators import WSGISimpleAuth # decoratore ( singleton )
auth = WSGISimpleAuth()

@auth.require()
def application( environ, start_response ):
storage = environ['auth.storage']

import cgi
post_environ = environ.copy()
post_environ['QUERY_STRING'] = ''
post = cgi.FieldStorage(
fp=environ['wsgi.input'],
environ=post_environ,
keep_blank_values=True
)

if 'password' in post:
password = post['password'].value
storage['permissions'] = [ 'auth' ]
html = [
"You are logged in, now you can see the <a href='/secret'>Secret</a> page.",
]

else:
storage['timeout'] = -1
html = [
"<form method='POST'>"
"Password: <input type='password' value='' name='password' />",
"<input type='submit'>",
"</form>",
]

start_response( '200 OK', [('content-type', 'text/html; charset=utf-8')] )

return html



+ 19
- 0
controllers/logout.py Ver fichero

@@ -0,0 +1,19 @@
#!/usr/bin/python
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-

from decorators import WSGISimpleAuth # decoratore ( singleton )
auth = WSGISimpleAuth()

@auth.require()
def application( environ, start_response ):
storage = environ['auth.storage']

storage['timeout'] = -1

start_response( '200 OK', [('content-type', 'text/html; charset=utf-8')] )

return [
"<h5>Now you are logged out</h5>",
"<a href='/index.html'>index</a>"
]


+ 2
- 1
controllers/secret.py Ver fichero

@@ -4,7 +4,7 @@
from decorators import WSGISimpleAuth # decoratore ( singleton )
auth = WSGISimpleAuth()

@auth.require()
@auth.require( 'auth' )
def application( environ, start_response ):
storage = environ['auth.storage']

@@ -14,4 +14,5 @@ def application( environ, start_response ):
"<h1>The secret code is:</h1>",
"<h6>''keep calm and carry on''</h6>"
"<h5>uuid:%s</h5>" % environ['auth.uuid'],
"<a href='/index.html'>index</a>"
]

+ 42
- 7
decorators.py Ver fichero

@@ -158,7 +158,7 @@ class WSGISimpleAuth( object ):
"""Generate a unique session ID"""
return hashlib.sha256(
str(os.getpid())
+ str(time())
+ str(time.time())
+ str(random.random())
).hexdigest()

@@ -169,7 +169,7 @@ class WSGISimpleAuth( object ):
self._lock.release()


def require( self, permission='', group='', p_g_mode='AND', p_mode='OR', g_mode='OR' ):
def require( self, permissions=[], groups=[], p_g_mode='AND', p_mode='OR', g_mode='OR' ):
def real_decorator( wsgi_application ):
def wrapper( environ, start_response ):
#--------------------------------------------------------------
@@ -185,6 +185,8 @@ class WSGISimpleAuth( object ):
#
# salva le informazioni legate al cookie
#
timeout = storage.get( 'timeout', self.__timeout )
storage['epoch_timeout'] = time.time() + timeout
storage['epoch_write'] = time.time()

self.acquire_lock() ## LOCK
@@ -203,6 +205,7 @@ class WSGISimpleAuth( object ):
start_response( status, response_headers );

#--------------------------------------------------------------

#
# recupera UUID dal cookie
#
@@ -218,24 +221,56 @@ class WSGISimpleAuth( object ):

self.acquire_lock() ## LOCK

f = open( path, 'r' )

try:
f = open( path, 'r' )
storage = cPickle.load( f )
f.close()

if storage['epoch_timeout'] < time.time():
# dati scaduti rimuove il file dei permessi..
os.unlink( path )

# ... e finge di non everlo mai trovato
raise Exception

logged_in = True

except:
# UUID assente, crea una nuova struttura dati
storage = {
'epoch_created': time.time(),
'permissions': [],
'groups': [],
'timeout': self.__timeout
}

f.close()
logged_in = False

self.release_lock() ## RELEASE

storage['epoch_read'] = time.time()

if permissions:
if isinstance( permissions, str ):
p = permissions.split()
else:
p = permissions

if not logged_in:
# non autenticato -> redirect to 'login_url'
start_response( '302 Found', [('Location', '/login'),] )
yield 'Please <a href="%s">login</a> first.' % '/login'
return

for perm in p:
if perm in storage['permissions']:
break
else:
# permessi insufficienti -> redirect to 'forbidden_url'
start_response( '302 Found', [('Location', '/forbidden'),] )
yield 'This page is not for your eyes.'
return

#
# popola environ
#
@@ -258,7 +293,7 @@ class WSGISimpleAuth( object ):
"""
{
uuid: jkfghkjgdhfgkjlsk,
permission=[],
permissions=[],
groups=[],
timeout=3600
}
@@ -267,7 +302,7 @@ class WSGISimpleAuth( object ):

{
uuid: jkfghkjgdhfgkjlsk,
permission=[],
permissions=[],
groups=[],
timeout=3600
}

+ 1
- 1
dispatch_wsgi.py Ver fichero

@@ -52,7 +52,7 @@ from router import WSGIRouter, WSGISmartRouter
#
def index( environ, start_response ):
start_response( '200 OK', [('content-type', 'text/html')] )
return [ 'Index was here' ]
return [ 'Index was <a href="/index.html">here</a>' ]

#
# hello: esempio minimo di applicazione WSGI


+ 1
- 4
router.py Ver fichero

@@ -78,8 +78,7 @@ class WSGISmartRouter(object):
tokens = [ token for token in environ['SCRIPT_URL'].split('/') if token ]

#for idx in range( 1, len( tokens ) + 1 ): # from shortest path to longest one
# from longest path to shortest one
for idx in range( len( tokens ) , 0, -1 ):
for idx in range( len( tokens ) , 0, -1 ): # from longest path to shortest one
module = os.path.normpath( self.cont_dir + '/'.join( tokens[:idx] ) + '.py' )
args = tokens[idx:]

@@ -88,8 +87,6 @@ class WSGISmartRouter(object):
environ['router.args'] = args

if environ['REQUEST_METHOD'] == 'GET' and hasattr( handler, 'get' ):
# FIXME: forse è meglio eseguire QUI la start_response
# e compilare il template (solo per GET e POST)
return handler.get( environ, start_response )

elif environ['REQUEST_METHOD'] == 'POST' and hasattr( handler, 'post' ):



+ 4
- 1
static/index.html Ver fichero

@@ -12,7 +12,10 @@
<li><a href="/demo">test autorouting</a></li>
<li><a href="/demo/due">test autorouting (longest path possible)</a></li>
<li><a href="/demo/sql">test sql access</a></li>
<li><a href="/secret">test authenticated</a></li>
<li><a href="/login">login</a></li>
<li><a href="/secret">secret page</a></li>
<li><a href="/admin">admin page (you have no permissions)</a></li>
<li><a href="/logout">logout</a></li>
</ul>
<div style="position:fixed; bottom:0; left:10px;">
<a rel="license" href="http://creativecommons.org/licenses/by/3.0/deed.en_US"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by/3.0/88x31.png" /></a>


Cargando…
Cancelar
Guardar