Integrating Shibboleth Authentication into your Application
We assume you have set up your system with the Shibboleth SP as described in the documentation.
The Shibboleth SP is tightly integrated with the Apache webserver and provides the user information to the apache process with the mod_shib module as UTF-8 encoded environment variables.
Accessing the Data via the Apache Environment
The following text assumes your application is running within Apache, i.e. as a python wsgi application or ruby passenger or tomcat with ajp. An alternative is the case of a seperate application server behind an Apache proxy, described below.
Let's assume you application has a login form at the url /login (Note that you need a dedicated login page, a dropdown menu will not so!), say along the lines of this highly simplistic python code:
Classical Login Route
@app.route('/login', methods=['GET', 'POST'])
def login_page():
if request.method == 'POST':
message = validate_login_form(request)
if session.user_is_authenticated:
redirect(url_for('startpage'))
return render_login_form(message)
- By default, the page renders a login form that will than make a post to the same url.
- If the page is called via post request, you validate the user input from the login form.
- If the authentication is successful, or the page is called by a GET from an authenticated user request, you send the user to the startpage.
- Otherwise you display the login form again, containing the error message from the validation.
Here the validate_login_form function will do something like
Form Validation
def validate_login_form(request):
user = get_user_from_db_by_name(request.data.name)
if user:
if check_user_password(user,request.data.password):
session.current_user = user
session.user_is_authenticated = true
return true
else:
return "Password incorrect."
else:
return "User unknown."
Thus it returns true if the user and password combination is known, otherwise it informs the user about the error.
Now to add a hook for Shibboleth to the mix, lets add an else branch to the request.method switch to process Shibboleth information.
Login Route with Shibboleth Hook
@app.route('/login', methods=['GET', 'POST'])
def login_page():
if request.method == 'POST':
message = validate_login_form(request)
else:
process_shib_data(request)
if session.user_is_authenticated:
redirect(url_for('startpage'))
return render_login_form(message)
Then the process_shib_data function does something like
Shibboleth Data Processing
def process_shib_data(request):
if request.environ.get('Shib-Session-ID'):
user = get_user_from_db_by_name(request.environ.get('REMOTE_USER'))
if not user:
user = create_user(request.environ.get('REMOTE_USER'),request.environ.get('mail'),request.environ.get('displayName'))
session.current_user = user
session.user_is_authenticated = true
return true
else:
return false
Thus the function checks whether there is a Shibboleth session by checking for the existence of a session id.
If successful, It takes the user currently logged through shibboleth and tries logging him in. If the user does not yet exist locally, he will be created.
This of course assume you have a username field that can by any string (in particular including @ symbols) and you won't run into trouble with multiple users having the same mail address.
You can also do more than just create plain users, such as e.g. mapping groups based on the isMemberOf attribute etc.
How it Works
If there is Shibboleth data in the Apache session available, you use it to (optionally create and) log in the user, otherwise you simply default back to standard behaviour.
Enabling Shibboleth in Apache
Now to switch between Shibboleth and standard login, you simply protect the login page by Shibboleth.
Corresponding Apache Settings
<Location /login>
AuthType shibboleth
ShibRequestSetting requireSession true
Require valid-user
</Location>
Using mod_proxy
In case you can't or won't run your application within Apache's enviroment, you can also put Apache as a reverse proxy in front of your application server (or say a docker container for that matter).
Beware the Security implications
This setup is not encouraged! Be are of the possible implications and security pitfalls!
On the Apache end, you will need to enable
ShibUseHeaders On
and than process the request headers instead of environment variables at the end.
Character Encoding
While Apache will happily forward the UTF-8 encoded strings to the backend, as per RFC 2616 HTTP request headers are expected to be ISO-8859-1 encoded and some application servers such as Tomcat will interpret them as such!