From: Michael Tremer Date: Mon, 26 Jun 2023 09:47:19 +0000 (+0000) Subject: people: Move SSO for Discourse X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2fe1d960aec7b367632ce4075fefd43719f3acf0;p=ipfire.org.git people: Move SSO for Discourse Signed-off-by: Michael Tremer --- diff --git a/src/web/__init__.py b/src/web/__init__.py index 6b0e2b8d..732fd5a5 100644 --- a/src/web/__init__.py +++ b/src/web/__init__.py @@ -156,6 +156,9 @@ class Application(tornado.web.Application): (r"/password\-reset", auth.PasswordResetInitiationHandler), (r"/password\-reset/([a-z_][a-z0-9_-]{0,31})/(\w+)", auth.PasswordResetHandler), + # Single-Sign-On for Discourse + (r"/sso/discourse", auth.SSODiscourse), + # User Groups (r"/users/groups", users.GroupIndexHandler), (r"/users/groups/([a-z_][a-z0-9_-]{0,31})", users.GroupShowHandler), @@ -322,9 +325,6 @@ class Application(tornado.web.Application): (r"/subscribe", people.SubscribeHandler), (r"/unsubscribe", people.UnsubscribeHandler), - # Single-Sign-On for Discourse - (r"/sso/discourse", people.SSODiscourse), - # Serve any static files (r"/static/(.*)", tornado.web.StaticFileHandler, { "path" : self.settings.get("static_path") }), diff --git a/src/web/auth.py b/src/web/auth.py index d633a94b..792205fe 100644 --- a/src/web/auth.py +++ b/src/web/auth.py @@ -2,6 +2,7 @@ import logging import tornado.web +import urllib.parse from . import base @@ -193,6 +194,61 @@ class PasswordResetHandler(AuthenticationMixin, base.BaseHandler): self.redirect("/") +class SSODiscourse(CacheMixin, base.BaseHandler): + @base.ratelimit(minutes=24*60, requests=100) + @tornado.web.authenticated + def get(self): + # Fetch Discourse's parameters + sso = self.get_argument("sso") + sig = self.get_argument("sig") + + # Decode payload + try: + params = self.accounts.decode_discourse_payload(sso, sig) + + # Raise bad request if the signature is invalid + except ValueError: + raise tornado.web.HTTPError(400) + + # Redirect back if user is already logged in + args = { + "nonce" : params.get("nonce"), + "external_id" : self.current_user.uid, + + # Pass email address + "email" : self.current_user.email, + "require_activation" : "false", + + # More details about the user + "username" : self.current_user.uid, + "name" : "%s" % self.current_user, + "bio" : self.current_user.description or "", + + # Avatar + "avatar_url" : self.current_user.avatar_url(absolute=True), + "avatar_force_update" : "true", + + # Send a welcome message + "suppress_welcome_message" : "false", + + # Group memberships + "admin" : "true" if self.current_user.is_admin() else "false", + "moderator" : "true" if self.current_user.is_moderator() else "false", + } + + # Format payload and sign it + payload = self.accounts.encode_discourse_payload(**args) + signature = self.accounts.sign_discourse_payload(payload) + + qs = urllib.parse.urlencode({ + "sso" : payload, + "sig" : signature, + }) + + # Redirect user + self.redirect("%s?%s" % (params.get("return_sso_url"), qs)) + + class APICheckUID(base.APIHandler): @base.ratelimit(minutes=1, requests=100) def get(self): diff --git a/src/web/people.py b/src/web/people.py index a0174c26..5cc0c8c7 100644 --- a/src/web/people.py +++ b/src/web/people.py @@ -3,7 +3,6 @@ import datetime import ldap import tornado.web -import urllib.parse from .. import countries @@ -209,61 +208,6 @@ class UserPasswdHandler(auth.CacheMixin, base.BaseHandler): self.redirect("/users/%s" % account.uid) -class SSODiscourse(auth.CacheMixin, base.BaseHandler): - @base.ratelimit(minutes=24*60, requests=100) - @tornado.web.authenticated - def get(self): - # Fetch Discourse's parameters - sso = self.get_argument("sso") - sig = self.get_argument("sig") - - # Decode payload - try: - params = self.accounts.decode_discourse_payload(sso, sig) - - # Raise bad request if the signature is invalid - except ValueError: - raise tornado.web.HTTPError(400) - - # Redirect back if user is already logged in - args = { - "nonce" : params.get("nonce"), - "external_id" : self.current_user.uid, - - # Pass email address - "email" : self.current_user.email, - "require_activation" : "false", - - # More details about the user - "username" : self.current_user.uid, - "name" : "%s" % self.current_user, - "bio" : self.current_user.description or "", - - # Avatar - "avatar_url" : self.current_user.avatar_url(absolute=True), - "avatar_force_update" : "true", - - # Send a welcome message - "suppress_welcome_message" : "false", - - # Group memberships - "admin" : "true" if self.current_user.is_admin() else "false", - "moderator" : "true" if self.current_user.is_moderator() else "false", - } - - # Format payload and sign it - payload = self.accounts.encode_discourse_payload(**args) - signature = self.accounts.sign_discourse_payload(payload) - - qs = urllib.parse.urlencode({ - "sso" : payload, - "sig" : signature, - }) - - # Redirect user - self.redirect("%s?%s" % (params.get("return_sso_url"), qs)) - - class AgentModule(ui_modules.UIModule): def render(self, account): return self.render_string("people/modules/agent.html", account=account)