[bootle] authnetifizierung mit authkit

Django, Flask, Bottle, WSGI, CGI…
Antworten
.robert
User
Beiträge: 274
Registriert: Mittwoch 25. April 2007, 17:59

Hi,

ich spiele gerade ein wenig mit Bottle rum, und würde jetzt gerne per Authkit eine Authentifizierung mit einbauen. Ich hatte gehofft dass das damit schön easy geht.

Diese Code (geklaut von der authkit seite und leicht angepasst) funktioniert:

Code: Alles auswählen

#!/usr/bin/env python

from authkit.permissions import UserIn
from authkit.authorize import authorized, authorize, PermissionError
from authkit.authorize import middleware as authorize_middleware
from paste import httpexceptions

class NoSuchActionError(httpexceptions.HTTPNotFound):
	pass

class AuthorizeExampleApp:
	
	def __call__(self, environ, start_response):
		if environ['PATH_INFO'] == '/':
			method = 'index'
		else:
			method = environ['PATH_INFO'].split('/')[1]
		if not hasattr(self, method):
			raise NoSuchActionError('No such method')
		app = getattr(self,method)
		# This facilitates an alternative way you might want to check permisisons
		# rather than using an authorize() decorator
		if hasattr(app, 'permission'):
			app = authorize_middleware(app, app.permission)
		return app(environ, start_response) 

	def index(self, environ, start_response):
		start_response('200 OK', [('Content-type','text/html')])
		return ['''
			<html>
			<head>
			<title>AuthKit Authorize Example</title>
			</head>
			<body>
			<h1>Authorize Example</h1>
			<p>Try the following links. You should only be able to sign 
			in as user <tt>james</tt> with the password the same as the 
			username.</p>
			<ul>
			   <li><a href="/mid_method_test">Mid Method</a></li>
			   <li><a href="/decorator_test">Decorator</a></li>
			   <li><a href="/attribute_test">Attribute (middleware)</a></li>
			</ul>
			<p>Once you have signed in you will need to close your 
			browser to clear the authentication cache.</p>
			</body>
			</html>
		''']

	def mid_method_test(self, environ, start_response):
		"""Authorize using a mid-method permissions check"""
		if authorized(environ, UserIn(users=['james'])):
			start_response('200 OK', [('Content-type','text/html')])
			return ['Access granted to /mid_method_test']
		else:
			start_response('200 OK', [('Content-type','text/html')])
			return ['User is not authorized']

	@authorize(UserIn(users=['james']))
	def decorator_test(self, environ, start_response):
		"""Authorize using a decorator"""
		start_response('200 OK', [('Content-type','text/html')])
		return ['Access granted to /decorator_test']

	def attribute_test(self, environ, start_response):
		"""Authorize using a permission attribute"""
		start_response('200 OK', [('Content-type','text/html')])
		return ['Access granted to /attribute_test']
	attribute_test.permission = UserIn(users=['james'])

if __name__ == '__main__':
	
	from paste.httpserver import serve
	from authkit.authenticate import middleware
	
	def valid(environ, username, password):
		"""
		Sample, very insecure validation function
		"""
		return username == password
		
	app = httpexceptions.make_middleware(AuthorizeExampleApp())
	app = middleware(
		app, 
		setup_method='form,cookie',
		cookie_secret='uiuisecret',
		form_authenticate_user_data = """
			robert:robert
			james:james
		""",
		cookie_signoutpath = '/signout'
	)

serve(app, host='0.0.0.0', port=8080)
aber wie setzte ich dass mit bottle um? mein blauäugiger ansatz funktioniert jedenfalls nicht:

Code: Alles auswählen

from authkit.authorize import authorized, authorize, PermissionError
from authkit.authorize import middleware as authorize_middleware
from authkit.authenticate import middleware
from authkit.permissions import UserIn

from bottle import *

@route('/')
def hello():
	if authorized(request.environ, UserIn(users=['james'])):
		return "Hallo James"
	else:
		return "hello, stranger"

@authorize(UserIn(users=['james']))
@route('/secret', method='GET')
def secret():
	return "secret"

# get the default bottle application
app = default_app()

app = middleware(app,
		setup_method='form,cookie',
		cookie_secret='secretstring',
		form_authenticate_user_data = """
			robert:robert
			james:james
		""",
		cookie_signoutpath = '/signout'
	)

# run the application
run(app=app, reloader=True)
kann mir da jemand auf die sprünge helfen?

Danke!
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

AuthKit arbeitet meines Wissens mit Exceptions, die Bottle aber ab fängt. Mit `bottle.default_app().catchall = False` sollte es funktionieren.

http://bottle.paws.de/page/faq#how-to-u ... middleware
Bottle: Micro Web Framework + Development Blog
.robert
User
Beiträge: 274
Registriert: Mittwoch 25. April 2007, 17:59

Hi,

leider nein.

Code: Alles auswählen

from authkit.authorize import authorized, authorize, PermissionError
from authkit.authorize import middleware as authorize_middleware
from authkit.authenticate import middleware
from authkit.permissions import UserIn

from bottle import *

@route('/')
def hello():
	if authorized(request.environ, UserIn(users=['james'])):
		return "Hallo James"
	else:
		return "hello, stranger"

@route('/signout')
def signout():
	return "signout"

@authorize(UserIn(users=['james']))
@route('/secret1', method='GET')
def secret1():
	return "secret1"

@route('/secret2')
def secret2():
	return "secret 2"
secret2.persission = UserIn(users=['james'])

# get the default bottle application
app = default_app()
app.catchall = False
app = middleware(app,
		setup_method='form,cookie',
		cookie_secret='secretstring',
		form_authenticate_user_data = """
			robert:robert
			james:james
		""",
		cookie_signoutpath = '/signout',
	)

# run the application
run(app=app, reloader=True)
Weder der Decorator (bei def secret1) noch das Attribute bei secret2 hat eine Wirkung, die FUnktionen können auch ohne Cookie etc aufgerufen werden.
Wenn ich bei secret1 den @route und dann den @authorize Decorator setzte, kommt die Fehlermeldung

Code: Alles auswählen

Traceback (most recent call last):
  File "/usr/lib/python2.6/wsgiref/handlers.py", line 93, in run
    self.result = application(self.environ, self.start_response)
  File "/usr/local/lib/python2.6/dist-packages/AuthKit-0.4.5-py2.6.egg/authkit/authenticate/__init__.py", line 331, in __call__
    return self.app(environ, start_response)
  File "/usr/local/lib/python2.6/dist-packages/AuthKit-0.4.5-py2.6.egg/authkit/authenticate/cookie.py", line 480, in __call__
    return self.app(environ, cookie_setting_start_response)
  File "/usr/local/lib/python2.6/dist-packages/AuthKit-0.4.5-py2.6.egg/authkit/authenticate/multi.py", line 87, in __call__
    app_iter = app(environ, start_response)
  File "/usr/local/lib/python2.6/dist-packages/AuthKit-0.4.5-py2.6.egg/authkit/authenticate/multi.py", line 55, in app
    return self.default(environ, find)
  File "/usr/local/lib/python2.6/dist-packages/AuthKit-0.4.5-py2.6.egg/authkit/authenticate/__init__.py", line 321, in __call__
    return self.app(environ, start_response)
  File "/usr/local/lib/python2.6/dist-packages/AuthKit-0.4.5-py2.6.egg/authkit/authenticate/__init__.py", line 344, in __call__
    return self.app(environ, start_response)
  File "/usr/local/lib/python2.6/dist-packages/AuthKit-0.4.5-py2.6.egg/authkit/authenticate/__init__.py", line 321, in __call__
    return self.app(environ, start_response)
  File "/usr/local/lib/python2.6/dist-packages/AuthKit-0.4.5-py2.6.egg/authkit/authenticate/__init__.py", line 425, in __call__
    return self.application(environ, start_response)
  File "/usr/local/lib/python2.6/dist-packages/bottle-0.6.4-py2.6.egg/bottle.py", line 309, in __call__
    output = handler(**args)
TypeError: input() takes exactly 3 arguments (0 given)
localhost - - [06/Mar/2010 18:35:13] "GET /secret1 HTTP/1.1" 500 59
[/quote]
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

AuthKit scheint ziemlich eng mit pylons verzahnt zu sein...

Hier mal eine Version des Dekorators, die auch mit Bottle funktionieren sollte:

Code: Alles auswählen

def authorize(permission):
    def decorator(func):
        def wrapper(**kargs):
            all_conf = request.environ.get('authkit.config')
            if all_conf is None:
                abort(500, 'Authentication middleware not present')
            if all_conf.get('setup.enable', True) is True:
                def fakeapp(*ignore, **me):
                    return func(**kargs)
                return permission.check(fakeapp, request.environ, None)
            return func(**kargs)
        return wrapper
    return decorator
Ich muss sagen das ich AuthKit ziemlich unbenutzbar finde, wenn man nicht gerade mit pure WSGI oder pylons arbeitet. Selbst die Basis-Werkzeuge (cookie parsing u.s.w.) haben paste-Abhängigkeiten und schmeißen munter mit paste.httpexceptions um sich oder versuchen, WSGI callbacks auszuführen. Das, was ich bisher an Quelltext von AuthKit gelesen habe, erscheint mir sehr umständlich, starr und unflexibel.

Besonders stört mich, das ständig Funktionen auf tauchen, die irgendetwas machen und dann eine Callback Funktion mit den WSGI Parametern aufrufen wollen. das 'irgentwas' als eigenständige Funktion sucht man aber vergeblich. Daher auch der "fakeapp(*ignore, **me)" Blödsinn da oben.
Bottle: Micro Web Framework + Development Blog
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich habe im Netz vorhin noch einiges negatives zu Authkit gefunden. Nun frage ich mich aber wirklich mal, welche WSGI Authentication Lib (unabhängig vom Framework) empfehlenswert ist?
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Ich bin kurz davor, eine zu schreiben ;) Zumindest Basic und DigestAuth und Cookies. Das sollte ja nicht so schwer sein.

Ich lese gerade massenweise except-blöcke ohne Angabe der exception im AuthKit code. Das würde zum Beispiel auch Strg+c abfangen und verhindern, das Bottle sich beendet. Prima.

EDIT: OK, Digest Auth ist schwer. Oder zumindest umständlich. Basic kann bottle ja schon. Siehe "bottle.request.auth"
Zuletzt geändert von Defnull am Samstag 6. März 2010, 19:48, insgesamt 1-mal geändert.
Bottle: Micro Web Framework + Development Blog
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

@Hyperion Ich persönlich finde das Konzept von zine ja ganz nett, eventuell würde ich auch mal bei solace vorbei schauen. Da liesse sich sicherlich was extrahieren, selbst wenn es nur Inspiration ist.
.robert
User
Beiträge: 274
Registriert: Mittwoch 25. April 2007, 17:59

Also auch weg mit authkit :(
Hyperion hat geschrieben:Nun frage ich mich aber wirklich mal, welche WSGI Authentication Lib (unabhängig vom Framework) empfehlenswert ist?

Jap, das Frage ich mich auch.

Ich hatte gehofft, eben eine recht einfache Authentication Lib zu finden, die ich mit Bottle oder Werkzeug (oder oder) einsetzen kann, eben ohne alles selber zu schreiben...

Ich schau mir dann gleich mal den Code von Zine und Solace an (oder warte bis Defnull fertig ist ;-))
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Defnull hat geschrieben:Ich bin kurz davor, eine zu schreiben ;) Zumindest Basic und DigestAuth und Cookies. Das sollte ja nicht so schwer sein.
Das mach mal :-)
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Vielleicht erklärt sich mitsuhiko auch selbst bereit, den Authentication-Code aus Zine so zu modularisieren, dass es als eigenes Paket geschrieben werden kann. Ich bin ebenfalls an einer guten auth-lib, die unabhängig vom verwendeten framework ist, interessiert.

Edit: Typo
Zuletzt geändert von derdon am Samstag 6. März 2010, 23:49, insgesamt 1-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

derdon hat geschrieben:Vielleicht erklärt sich mitsuhiko auch selbst bereit, den Authentication-Code aus Zine so zu modularisieren, dass er als eigenes Paket geschrieben werden kann. Ich bin ebenfalls an einer guten auth-lib, die unabhängig vom verwendeten framework ist, interessiert.
Das wäre natürlich prima. Speziell die Framework Unbahängigkeit würde ja durchaus ins Konzept von werkzeug aber auch bottle passen :-)
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

derdon hat geschrieben:Vielleicht erklärt sich mitsuhiko auch selbst bereit, den Authentication-Code aus Zine so zu modularisieren, dass es als eigenes Paket geschrieben werden kann. Ich bin ebenfalls an einer guten auth-lib, die unabhängig vom verwendeten framework ist, interessiert.
So wie ich seinen Zeitplan kenne ist das eher nicht drin, sollte es jemand von euch machen wollen ist er aber sicher offen, was patches betrifft…
simlan
User
Beiträge: 6
Registriert: Montag 20. April 2009, 16:41

Defnull hat geschrieben:AuthKit scheint ziemlich eng mit pylons verzahnt zu sein...

Hier mal eine Version des Dekorators, die auch mit Bottle funktionieren sollte:

Code: Alles auswählen

def authorize(permission):
    def decorator(func):
        def wrapper(**kargs):
            all_conf = request.environ.get('authkit.config')
            if all_conf is None:
                abort(500, 'Authentication middleware not present')
            if all_conf.get('setup.enable', True) is True:
                def fakeapp(*ignore, **me):
                    return func(**kargs)
                return permission.check(fakeapp, request.environ, None)
            return func(**kargs)
        return wrapper
    return decorator
Ich muss sagen das ich AuthKit ziemlich unbenutzbar finde, wenn man nicht gerade mit pure WSGI oder pylons arbeitet. Selbst die Basis-Werkzeuge (cookie parsing u.s.w.) haben paste-Abhängigkeiten und schmeißen munter mit paste.httpexceptions um sich oder versuchen, WSGI callbacks auszuführen. Das, was ich bisher an Quelltext von AuthKit gelesen habe, erscheint mir sehr umständlich, starr und unflexibel.

Besonders stört mich, das ständig Funktionen auf tauchen, die irgendetwas machen und dann eine Callback Funktion mit den WSGI Parametern aufrufen wollen. das 'irgentwas' als eigenständige Funktion sucht man aber vergeblich. Daher auch der "fakeapp(*ignore, **me)" Blödsinn da oben.
Ja das is total schlimm. Bin seit zwei tagen dran ne brauchbare Dokumentation zu finden die nicht vorraussetzt das man mit paste per du ist und schon weiß wie sich die dämlichen Pylons config Files in Dicts übersetzen lassen. Geschweige den ne aktuelle Doku zu finden ..die nicht auf Pylons beruht...

Ach ja repoze.who gibts auch noch aber ehrlich gesagt ..... Overkill

Wenn du deine Lösung irgendwo auf Github oda so hast sag Bescheid würds mir gern mal anschauen.

Gruß Sim

p.s: Bottle is cool. Danke dafür ;)
Antworten