Skip to content

Instantly share code, notes, and snippets.

@danfunk
Created September 6, 2017 15:52
Show Gist options
  • Select an option

  • Save danfunk/50e901377ae9506526dae71caac6a647 to your computer and use it in GitHub Desktop.

Select an option

Save danfunk/50e901377ae9506526dae71caac6a647 to your computer and use it in GitHub Desktop.
Modified simple flask app for authenticating against shibbloeth.
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