X-Git-Url: https://git.mdrn.pl/wolnelektury.git/blobdiff_plain/6280673f35e13e75e81c5b7821bd2a44a1831eab..357027375ff8867f42ca34bcbfb5a78b5b185fc3:/src/basicauth.py diff --git a/src/basicauth.py b/src/basicauth.py new file mode 100644 index 000000000..befcc6fe7 --- /dev/null +++ b/src/basicauth.py @@ -0,0 +1,100 @@ +############################################################################# +# from http://djangosnippets.org/snippets/243/ + +from functools import wraps +import base64 + +from django.http import HttpResponse +from django.contrib.auth import authenticate, login + +# +def view_or_basicauth(view, request, test_func, realm = "", *args, **kwargs): + """ + This is a helper function used by 'logged_in_or_basicauth' and + 'has_perm_or_basicauth' (deleted) that does the nitty of determining if they + are already logged in or if they have provided proper http-authorization + and returning the view if all goes well, otherwise responding with a 401. + """ + if test_func(request.user): + # Already logged in, just return the view. + # + return view(request, *args, **kwargs) + + # They are not logged in. See if they provided login credentials + # + if 'HTTP_AUTHORIZATION' in request.META: + auth = request.META['HTTP_AUTHORIZATION'].split() + if len(auth) == 2: + # NOTE: We are only support basic authentication for now. + # + if auth[0].lower() == "basic": + uname, passwd = base64.b64decode(auth[1]).split(':') + user = authenticate(username=uname, password=passwd) + if user is not None: + if user.is_active: + login(request, user) + request.user = user + return view(request, *args, **kwargs) + + # Either they did not provide an authorization header or + # something in the authorization attempt failed. Send a 401 + # back to them to ask them to authenticate. + # + response = HttpResponse() + response.status_code = 401 + response['WWW-Authenticate'] = 'Basic realm="%s"' % realm + return response + + +# +def logged_in_or_basicauth(realm = ""): + """ + A simple decorator that requires a user to be logged in. If they are not + logged in the request is examined for a 'authorization' header. + + If the header is present it is tested for basic authentication and + the user is logged in with the provided credentials. + + If the header is not present a http 401 is sent back to the + requestor to provide credentials. + + The purpose of this is that in several django projects I have needed + several specific views that need to support basic authentication, yet the + web site as a whole used django's provided authentication. + + The uses for this are for urls that are access programmatically such as + by rss feed readers, yet the view requires a user to be logged in. Many rss + readers support supplying the authentication credentials via http basic + auth (and they do NOT support a redirect to a form where they post a + username/password.) + + Use is simple: + + @logged_in_or_basicauth + def your_view: + ... + + You can provide the name of the realm to ask for authentication within. + """ + def view_decorator(func): + def wrapper(request, *args, **kwargs): + return view_or_basicauth(func, request, + lambda u: u.is_authenticated(), + realm, *args, **kwargs) + return wrapper + return view_decorator + + +############################################################################# + + +def factory_decorator(decorator): + """ generates a decorator for a function factory class + if A(*) == f, factory_decorator(D)(A)(*) == D(f) + """ + def fac_dec(func): + @wraps(func) + def wrapper(*args, **kwargs): + return decorator(func(*args, **kwargs)) + return wrapper + return fac_dec