diff --git a/README.md b/README.md index 6a263f5..6b7f1dc 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,6 @@ location /saml/ { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Saml-Entity-Id https://samldemo.iamdev.s.uw.edu/saml; - # acs - post-back url registered with the IdP. - proxy_set_header X-Saml-Acs /saml/login; proxy_pass http://saml:5000/; } @@ -50,3 +47,50 @@ randomly-generated string. Otherwise, we generate one on the fly, which only works as long as the app is running, and won't work in a distributed environment. SECRET_KEY is used to sign cookies, so setting a new key effectively invalidates all existing sessions. + + +## Service Provider (SP) Entity ID and ACS URL + +There are two ways to declare your SP entity-id and acs-url. With both of +these, the `X-Forwarded-` headers listed are crucial. + +### By inference + +With this the saml proxy will make assumptions that the request URL and proxy +path are registered as an SP. + +If host https://example.com has the following proxy config... + +``` +location /saml/ { + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Prefix /saml/; + proxy_pass http://saml:5000/; + } +``` + +Then the SP entity-id to register is `https://example.com/saml` and the ACS +endpoint to register is `https://example.com/saml/login`. + +### Explicitly + +You can also declare these items explicitly by passing them in as headers... + +``` +location /saml/ { + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Prefix /saml/; + proxy_set_header X-Saml-Entity-Id https://samldemo.iamdev.s.uw.edu/saml; + proxy_set_header X-Saml-Acs /saml/login; + proxy_pass http://saml:5000/; +} +``` + +You typically won't need to explicitly declare `X-Saml-Acs`. `X-Saml-Entity-Id` +may need to be declared if for any reason the entity-id doesn't match with how +we infer it, such as with an existing entity-id, or when multiple hosts +share a single Entity ID. diff --git a/app.py b/app.py index bbff115..0e28ecd 100644 --- a/app.py +++ b/app.py @@ -1,13 +1,14 @@ from flask import Flask, Response, request, session, abort, redirect import flask -from werkzeug.contrib.fixers import ProxyFix +from werkzeug.middleware.proxy_fix import ProxyFix import uw_saml2 from urllib.parse import urljoin from datetime import timedelta import os import secrets app = Flask(__name__) -app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1) +app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_prefix=1) +POSTBACK_ROUTE = '/login' if os.environ.get('SECRET_KEY'): app.secret_key = os.environ['SECRET_KEY'] else: @@ -56,10 +57,13 @@ def status(group=None): def _saml_args(): """Get entity_id and acs_url from request.headers.""" - return { - 'entity_id': request.headers['X-Saml-Entity-Id'], - 'acs_url': urljoin(request.url_root, request.headers['X-Saml-Acs']) - } + entity_id = request.url_root[:-1] # remove trailing slash + acs_url = urljoin(request.url_root, POSTBACK_ROUTE[1:]) + if 'X-Saml-Entity-Id' in request.headers: + entity_id = request.headers['X-Saml-Entity-Id'] + if 'X-Saml-Acs' in request.headers: + acs_url = urljoin(request.url_root, request.headers['X-Saml-Acs']) + return dict(entity_id=entity_id, acs_url=acs_url) @app.route('/login/') @@ -75,6 +79,7 @@ def login_redirect(return_to=''): return_to - the path to redirect back to after authentication. This and the request.query_string are set on the SAML RelayState. """ + app.logger.error(f'URL ROOT {request.url_root}') query_string = '?' + request.query_string.decode() if query_string == '?': query_string = '' @@ -85,7 +90,7 @@ def login_redirect(return_to=''): return redirect(uw_saml2.login_redirect(return_to=return_to, **args)) -@app.route('/login', methods=['GET', 'POST']) +@app.route(POSTBACK_ROUTE, methods=['GET', 'POST']) def login(): """ Process a SAML Response, and set the uwnetid and groups on the session. diff --git a/test/nginx/server.conf b/test/nginx/server.conf index 6b381c8..09c7ed2 100644 --- a/test/nginx/server.conf +++ b/test/nginx/server.conf @@ -28,10 +28,9 @@ server { location /saml/ { proxy_set_header Host $http_host; - proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Saml-Entity-Id https://samldemo.iamdev.s.uw.edu/saml; - proxy_set_header X-Saml-Acs /saml/login; + proxy_set_header X-Forwarded-Prefix /saml/; proxy_pass http://saml:5000/; }