Created
September 6, 2013 00:33
-
-
Save davehughes/6458078 to your computer and use it in GitHub Desktop.
Implementation of User 'masquerade' in Django.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 1) Add MasqueradeMiddleware to Django's middleware stack (see comment below for placement) | |
class MasqueradeMiddleware(object): | |
''' | |
Looks for a field in the active session specifying a user to masquerade as | |
and sets request.user to that user, storing the real user to the session. | |
This middleware is dependent on the existence of sessions, so it should be | |
deployed after ('inside') Django's session middleware. It should probably | |
be deployed after middleware like the TermsAndConditionsMiddleware which | |
implement one-time intercepts, so that masquerading superusers don't get | |
redirected to (and have to accept, on behalf of the effective user) the | |
site terms. | |
''' | |
SESSION_KEY_BASE = 'user.base_user' | |
SESSION_KEY_EFFECTIVE = 'user.effective_user' | |
def process_request(self, request): | |
request.is_masquerade_session = False | |
if hasattr(request, 'session'): | |
eff_user = request.session.get(self.SESSION_KEY_EFFECTIVE) | |
if eff_user: | |
request.user = eff_user | |
request.is_masquerade_session = True | |
# 2) Route to this view function (guard with appropriate access control, like is_staff), which turns masquerading | |
# on and off | |
def masquerade(request): | |
if request.method != 'POST': | |
return http.HttpResponseNotAllowed(['POST']) | |
BASE_USER = middleware.MasqueradeMiddleware.SESSION_KEY_BASE | |
EFFECTIVE_USER = middleware.MasqueradeMiddleware.SESSION_KEY_EFFECTIVE | |
# override user based on session key for authorization purposes | |
user = request.session.get(BASE_USER, request.user) | |
if not user.is_superuser: | |
return http.HttpResponseForbidden() | |
# update session to reflect changes | |
if request.POST.get('update'): | |
user_id = request.POST.get('user_id') | |
if not user_id: | |
messages.error(request, 'No user ID provided.') | |
else: | |
# set appropriate masquerade info in session | |
try: | |
effective_user = User.objects.get(id=user_id) | |
request.session[EFFECTIVE_USER] = effective_user | |
request.session[BASE_USER] = user | |
request.user = effective_user | |
except User.DoesNotExist: | |
messages.error(request, 'User does not exist.') | |
elif request.POST.get('clear'): | |
# reset current request user and clear masquerade info from session | |
request.user = user | |
if EFFECTIVE_USER in request.session: | |
del request.session[EFFECTIVE_USER] | |
if BASE_USER in request.session: | |
del request.session[BASE_USER] | |
else: | |
messages.error(request, 'No valid operation specified') | |
return http.HttpResponseRedirect(request.REQUEST.get('next', '/')) | |
# 3) (Optional) add this context processor to Django's context processor stack to allow templates to do | |
# conditional things like displaying a 'stop masquerading' button | |
def masquerade_context(request): | |
''' | |
Context processor that adds an 'is_masquerade_session' variable to | |
indicate whether the user in the current session is masquerading as another | |
user (this is superuser functionality). | |
''' | |
ms = False | |
eu = None | |
if hasattr(request, 'session'): | |
if request.session.get(MasqueradeMiddleware.SESSION_KEY_EFFECTIVE): | |
ms = True | |
eu = request.session.get(MasqueradeMiddleware.SESSION_KEY_EFFECTIVE) | |
return { 'is_masquerade_session': ms, 'effective_user': eu } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment