Page tree
Skip to end of metadata
Go to start of metadata

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)
  1. By default, the page renders a login form that will than make a post to the same url.
  2. If the page is called via post request, you validate the user input from the login form.
  3. 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.
  4. 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!

 

 

  • No labels