Created
September 6, 2017 15:52
-
-
Save danfunk/50e901377ae9506526dae71caac6a647 to your computer and use it in GitHub Desktop.
Modified simple flask app for authenticating against shibbloeth.
This file contains hidden or 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
| from datetime import datetime | |
| from flask import Flask, session, redirect | |
| from flask_sso import SSO | |
| # Here is a barebones flask app that should work with UVA's shibboleth. | |
| # It is taken from this gist: https://gist.github.com/alexpearce/4ef660422085838ff2d2 | |
| # But modified to use UVA's keys. I used this website to work through | |
| # the process: https://alexpearce.me/2014/10/setting-up-flask-with-apache-and-shibboleth/ | |
| # | |
| # I added the following section to the apache configuration for the site. | |
| # | |
| # Apache Configuration: | |
| # User login endpoint for Python | |
| # <Location /login> | |
| # AuthType shibboleth | |
| # ShibRequestSetting requireSession 1 | |
| # require shibboleth | |
| # </Location> | |
| # | |
| # An attempt to navigate to /login will redirect you to the NetBadge login page, if you | |
| # are not authenticated. Otherwise it will pull the header values out of the response, | |
| # and place them in the flask session object, for later reference. It then redirects you | |
| # to the root url ("/") where you can view the information that comes back from Shibboleth. | |
| # | |
| def get_user_session_info(key): | |
| return session['user'].get( | |
| key, | |
| 'Key `{0}` not found in user session info'.format(key) | |
| ) | |
| def get_user_details(fields): | |
| defs = [ | |
| '<dt>{0}</dt><dd>{1}</dd>'.format(f, get_user_session_info(f)) | |
| for f in fields | |
| ] | |
| return '<dl>{0}</dl>'.format(''.join(defs)) | |
| def create_app(): | |
| app = Flask('SSOTutorial') | |
| # Add a secret key for encrypting session information | |
| app.secret_key = 'cH\xc5\xd9\xd2\xc4,^\x8c\x9f3S\x94Y\xe5\xc7!\x06>A' | |
| #: Here is a custom attribute map for UVA's available fields, at least the ones | |
| # I was able to pull back on 9/6/2017 | |
| SSO_ATTRIBUTE_MAP = { | |
| 'eppn': (True, 'eppn'), # dhf8r@virginia.edu | |
| 'uid': (False, 'uid'), # dhf8r | |
| 'givenName': (False, 'givenName'), # Daniel | |
| 'mail': (False, 'email'), # dhf8r@Virginia.EDU | |
| 'sn': (False, 'surName'), # Funk | |
| 'affiliation': (False, 'affiliation'), # 'staff@virginia.edu;member@virginia.edu' | |
| 'displayName': (False, 'displayName'), # Daniel Harold Funk | |
| 'title': (False, 'title') # SOFTWARE ENGINEER V | |
| } | |
| app.config.setdefault('SSO_ATTRIBUTE_MAP', SSO_ATTRIBUTE_MAP) | |
| app.config.setdefault('SSO_LOGIN_URL', '/login') | |
| # This attaches the *flask_sso* login handler to the SSO_LOGIN_URL, | |
| # which essentially maps the SSO attributes to a dictionary and | |
| # calls *our* login_handler, passing the attribute dictionary | |
| ext = SSO(app=app) | |
| @ext.login_handler | |
| def login(user_info): | |
| session['user'] = user_info | |
| return redirect('/') | |
| @app.route('/logout') | |
| def logout(): | |
| session.pop('user') | |
| return redirect('/') | |
| @app.route('/') | |
| def index(): | |
| time = datetime.now().time() | |
| timestr = '{0:02d}:{1:02d}:{2:02d}'.format( | |
| time.hour, time.minute, time.second | |
| ) | |
| headings = '<h1>Hello, World!</h1><h2>Server time: {0}</h2>'.format( | |
| timestr | |
| ) | |
| if 'user' in session: | |
| details = get_user_details([ | |
| 'eppn', | |
| 'uid', | |
| 'givenName', | |
| 'mail', | |
| 'sn', | |
| 'affiliation', | |
| 'displayName', | |
| 'title' | |
| ]) | |
| button = ( | |
| '<form action="/logout" method="get">' | |
| '<input type="submit" value="Log out">' | |
| '</form>' | |
| ) | |
| else: | |
| details = '' | |
| button = ( | |
| '<form action="/login" method="get">' | |
| '<input type="submit" value="Log in">' | |
| '</form>' | |
| ) | |
| return headings + details + button | |
| return app | |
| def wsgi(*args, **kwargs): | |
| return create_app()(*args, **kwargs) | |
| if __name__ == '__main__': | |
| create_app().run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment