Package: politico-staff-auth
__          _____  _____                 __  .__
  _______/  |______ _/ ____\/ ____\ _____   __ ___/  |_|  |__
 /  ___/\   __\__  \\   __\\   __\  \__  \ |  |  \   __\  |  \
 \___ \  |  |  / __ \|  |   |  |     / __ \|  |  /|  | |   Y  \
/____  > |__| (____  /__|   |__|    (____  /____/ |__| |___|  / /\
     \/            \/                    \/                 \/  \/POLITICO staff authThis app stores a handful of useful utilities we use across our various Django apps at POLITICO to integrate our staff authorization and authentication, which is implemented with Slack viaPython Social Auth.RequirementsPython 3.6 —brew install pythonPipenv —brew install pipenvDjango (tested on versions 2.1.x and 2.2.x)A Slack workspace with usersA Slack app connected to that workspace, with a "Redirect URL" entry matching the following pattern:http://<your server name>/social/complete/slack/(Note:you can have multiple "Redirect URLs" for the same app. For local development, you'll be aliasinglocalhostto a subdomain of your choosing, as described in the"Domain resolution"section below.)Optional:PostgreSQL —brew install postgresqlWhat's inside./staff_auth/The app that handles staff Slack authorization and authentication../staff_auth/templates/admin/login.htmland./staff_auth/static/staff_auth/css/custom-login.cssCustom HTML and CSS to add a "Staff login (with Slack)" button to the standard Django admin login form.staff_auth.backend.WorkspaceSpecificSlackOAuth2A subclass of Python Social Auth's Slack authentication backend. Unlike the original, this variant forces users to log in with credentials from the specified Slack workspace (rather than from any Slack workspace).staff_auth.middleware.InvalidWorkspaceErrorMiddlewareA middleware that listens for Python Social Auth'sAuthForbiddenexceptions and maps them to rich output in aStaffAuthErrorViewpage.staff_auth.pipeline.associate_by_emailA function that finds any existing Django users with the same email address as the sign-er in-er, and ties this new sign-in to the same account — but only if that user has previously had a separate social-auth tie in.staff_auth.pipeline.promote_staffer_to_staffA function that promotes all Slack-authenticated users to "staff" status (meaning they can log into the Django admin) when they first sign in with their Slack credentials.staff_auth.pipeline.promote_manager_to_superuserA function that promotes all Slack-authenticated users to "superuser" status (meaning they can log into the Django admin) when they first sign in with their Slack credentials — if the email address on their Slack account matches an email address found in thesettings.MANAGERSlist.staff_auth.views.StaffAuthErrorViewAn error page shown to users if they try and log in via a different Slack workspace.(Note that the HTML and CSS for this view live at./staff_auth/templates/staff_auth/auth-error.htmland./staff_auth/static/staff_auth/css/page-styles.css, respectively.)./example/An example Django project that shows how we implement staff Slack access.Inside this directory you'll find a standard (if threadbare) Django app, with an example.envfile, aPipfileand amanage.pyscript at the top level.Inside theexampleappsubdirectory is this example app'ssettings.pyfile (where you can see an example implementation ofpolitico-staff-auth's required configuration variables), along with aurls.pyfile to demonstrate how that piece of wiring should be performed. Standard helper files includingwsgi.pycan also be found in this subdirectory.Launching the example appChange into the./example/directory one level below this README and install dependencies.cd./example/
pipenvinstallCreate a.envfile from the.env.exampletemplate, and insert appropriate values.cp.env.example.envSee the"Configuration"section below for more information about what goes in each setting.Create a new blank database, then populate it with the necessary tables.makedatabase
pipenvrunpythonmanage.pymigrateStart the Django test server.pipenvrunpythonmanage.pyrunserverNavigate tothe admin site on your test serverand click the "Staff login" button.InstallationInstall from PyPI:pipenvinstallpolitico-staff-authAddstaff_authandsocial_djangoto the list of apps installed into Django.In your project'ssettings.py:INSTALLED_APPS=["staff_auth",# ...# Existing installed apps# ..."social_django",]NOTE:Thestaff_authapp must be first in this list (or, at least, must appear before the pre-existing linedjango.contrib.admin). Thesocial_djangoline should appear after all apps that are distributed with Django itself.Add the credentials for your staff's Slack workspace.In your project'ssettings.py:STAFF_AUTH_SLACK_KEY="auth-key"STAFF_AUTH_SLACK_SECRET="secret-key"STAFF_AUTH_SLACK_TEAM="my-value-here"For more on these values, see the"Configuration"section below.NOTE:We recommend reading these values from environment variables, but there's no accounting for taste.Add the required middleware for rich login error messages.In your project'ssettings.py:MIDDLEWARE=[# ...# Existing middleware# ..."staff_auth.middleware.InvalidWorkspaceErrorMiddleware",]NOTE:Thestaff_auth.middleware.InvalidWorkspaceErrorMiddlewareentry should go at the end of the existingMIDDLEWARElist.With the previous steps complete, you can now implement the basic staff auth settings.In your project'ssettings.py:fromstaff_auth.configured_settingsimportconfigure_staff_authstaff_auth_settings=configure_staff_auth(key=STAFF_AUTH_SLACK_KEY,secret=STAFF_AUTH_SLACK_SECRET,team=STAFF_AUTH_SLACK_TEAM,)forsetting_name,setting_valueinstaff_auth_settings.items():globals()[setting_name]=setting_valueSet Django to use the Slack auth backend whenever users are asked to log in.In your project'ssettings.py:LOGIN_URL="staff_auth:slack-login"Wire up thestaff_authandsocial_djangoURLs.In your project's top-level URLconf (urls.pyfile):urlpatterns=[# ...# Existing URL patterns# ...path("social/",include("social_django.urls",namespace="social")),path("staff-auth/",include("staff_auth.urls")),]Optional:Add pipelines.In your project'ssettings.py:SOCIAL_AUTH_PIPELINE=("social_core.pipeline.social_auth.social_details","social_core.pipeline.social_auth.social_uid","social_core.pipeline.social_auth.auth_allowed","social_core.pipeline.social_auth.social_user","social_core.pipeline.user.get_username","social_core.pipeline.user.create_user","social_core.pipeline.social_auth.associate_user","social_core.pipeline.social_auth.load_extra_data","staff_auth.pipeline.promote_staffer_to_staff","staff_auth.pipeline.promote_manager_to_superuser","social_core.pipeline.user.user_details",)You can disable either or both of thestaff_auth.pipelineclasses listed above, but please take care to preserve the order seen here — re-ordering these pipelines could produce unintended and hard-to-debug consequences.NOTE:The behaviors ofstaff_auth.pipeline.promote_staffer_to_staffandstaff_auth.pipeline.promote_manager_to_superuserare described in the"What's inside"section above.NOTE 2:If you're not using eitherstaff_auth.pipelineclass, skip this step and ensure your project'ssettings.pyfile has noSOCIAL_AUTH_PIPELINEvalue set.Optional:Modify the URLs where users are bounced to when they successfully log in or log out.These are standard Django settings, and can take either URLs or named URL patterns (as you would pass to the{% url %}template tag).In your project'ssettings.py:LOGIN_REDIRECT_URL="/my/url/pattern/"LOGOUT_REDIRECT_URL="namespace:view-name"NOTE:For more information, see the Django documentation entrieshereandhere.ConfigurationSettingWhat it doesSTAFF_AUTH_SLACK_KEYThe'Client ID'from the Slack "app" you've connected to your workspace for authenticating users. Passed to Python Social Auth asSOCIAL_AUTH_SLACK_KEY.STAFF_AUTH_SLACK_SECRETTheClient Secretfrom this Slack "app". Passed to Python Social Auth asSOCIAL_AUTH_SLACK_SECRET.STAFF_AUTH_SLACK_TEAMThe name of the Slack workspace where your users have accounts. (A handy way of remembering this: it's also the subdomain of slack.com where users log in to use Slack itself.) Passed to Python Social Auth asSOCIAL_AUTH_SLACK_TEAM.Copyright© 2019–present POLITICO LLC