= Overview = This page describes how we used an existing MoinMoin installation to provide user authentication for a separate Django-based web application. Our use case looks like this: * There are a MoinMoin wiki and a Django web site hosted on the same server. * Users who are logged in to MoinMoin should automatically be logged in to Django. * The Django login page should redirect to the MoinMoin login page. After login, the user should be redirected back to the page they came from. The login part requires Django to read the MoinMoin cookie and look up the session and user in MoinMoin. This is similar to [[HelpOnAuthentication/ExternalCookie]]--just in reverse. Redirecting to the login page and back requires a small change to the MoinMoin code. When a Django page requires a logged-in user, it should redirect to MoinMoin's login action, passing the query string "?action=login&next=". When the user clicks the login button, she should be redirected back to the Django page at "". = MoinMoin Changes = Adding the query parameter "next" requires changes to the login action and to the login form. This is the modified `LoginHandler.handle()` method in the file `MoinMoin/action/login.py` (based on MoinMoin 1.9.3): {{{#!python # MoinMoin/action/login.py def handle(self): _ = self._ request = self.request form = request.values islogin = form.get('login', '') display_login_form = not islogin if islogin: # user pressed login button if request._login_multistage: return self.handle_multistage() if hasattr(request, '_login_messages'): for msg in request._login_messages: request.theme.add_msg(wikiutil.escape(msg), "error") if request.user.valid: if "next" in form: request.theme.send_title(_("Login"), pagename=self.pagename, pi_refresh=(0, form["next"])) request.write( "

You will be redirected to %s. " % (form["next"], form["next"])) request.write(" If not click the link.

") request.theme.send_footer(self.pagename) request.theme.send_closing_html() return else: return self.page.send_page() else: display_login_form = True if display_login_form: request.theme.send_title(_("Login"), pagename=self.pagename) # Start content (important for RTL support) request.write(request.formatter.startContent("content")) request.write(userform.getLogin(request)) request.write(request.formatter.endContent()) request.theme.send_footer(self.pagename) request.theme.send_closing_html() }}} The important part is passing the "pi_refresh" parameter to `theme.send_title()`. This results in a `` element being added to the page, same as with the "#REFRESH" processing instruction. '''Note:''' What I really wanted to do is calling `request.http_redirect()` so that the redirection happens through an HTTP status code. However, `request.http_redirect()` is implemented inside the Werkzeug library by raising an exception. This aborts request processing before the login information is properly stored to the session. I asked about this on IRC, and the "pi_refresh" looks like the best solution with 1.9.3. In addition to handling "next", I changed the method to stay on the login page when the user mistypes their password. (The original version goes to a wiki page, which we don't want when coming from a Django page.) The second change is adding a hidden "next" form field to the login form in the `asHTML()` method in the file `MoinMoin/userform/login.py` (based on 1.9.3): {{{#!python # MoinMoin/userform/login.py def asHTML(self): ... self._form.append(html.INPUT(type="hidden", name="action", value="login")) if "next" in request.values: self._form.append(html.P().append(html.Text( "The page that you are trying to access requires you to log in" " with your wiki account. Once you have logged in, you will" " be redirected back."))) self._form.append(html.INPUT(type="hidden", name="next", value=request.values["next"])) ... }}} = Django Changes = To sign in to Django using MoinMoin, the Django code needs to do several things: * Check for the MoinMoin cookie sent by the browser. (This only works if Django and MoinMoin are on the same server. In our case, MoinMoin is at root "/" and Django is at "/d".) * Check whether the cookie represents a valid MoinMoin session. (The cookie points to a session file in `wiki/data/cache/__session__`.) * Extract the username from the session and map it to a Django user. (In our case, a Django user object is automatically created if it doesn't exist yet.) The file [[attachment:wiki_auth.py]] contains the authentication middleware and backend that does this. The code accesses the MoinMoin session and user files directly. This makes the code independent of the MoinMoin classes, but it ties the code to the specific format of these files. To enable it, add the class `WikiAuthMiddleware` to your `MIDDLEWARE_CLASSES` setting in Django. In addition, set the `LOGIN_URL` setting to the URL of a Django view that redirects to MoinMoin's login action and adds the "next" query parameter. The view code might look something like this: {{{#!python from django.conf import settings from django.http import HttpResponseRedirect, QueryDict WIKI_URL = '/' def login(request): redirect_to = request.REQUEST.get('next', '') if not redirect_to: redirect_to = settings.LOGIN_REDIRECT_URL query = QueryDict('', mutable=True) query['action'] = 'login' query['next'] = redirect_to return HttpResponseRedirect(WIKI_URL + "?" + query.urlencode(safe='/')) }}}