| @@ -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>" | |||
| ] | |||
| @@ -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>' ] | |||
| @@ -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>" | |||
| ] | |||
| @@ -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 | |||
| @@ -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>" | |||
| ] | |||
| @@ -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>" | |||
| ] | |||
| @@ -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 | |||
| } | |||
| @@ -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 | |||
| @@ -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' ): | |||
| @@ -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> | |||