This is an example SAML SP service written using Flask and pysaml2. It is an attempt at modernizing an existing project while also following the design used in Flask's tutorial project.
- python 3.6+
- virtualenv (or conda)
- poetry
You will also need a development environment capable of compiling Python packages and the "libffi" and "libxmlsec1" development libraries, which are needed by PySAML2.
Instructions for installing these development libraries will differ depending on your host operating system.
Optionally, you will also need to install ngrok if you want to validate the SP externally.
$ brew install libffi libxmlsec1
$ sudo yum install libffi-devel xmlsec1 xmlsec1-openssl
$ sudo apt-get install libffi-dev xmlsec1 libxmlsec1-openssl
$ poetry install
$ conda create --name flask-pysaml2-example python=3
$ conda activate flask-pysaml2-example
$ pip install poetry
$ poetry install
$ FLASK_APP=flask_pysaml2_example flask run
Additionally you can use docker compose
to start the service:
$ docker compose up
The fastest way to test this example SAML SP is to use the saml.oktadev.com service.
-
Edit the
flask_pysaml2_example/__init__.py
file and edit the appropriate entry in theSAML_IDP_SETTINGS
Flask config value, changing this:app.config.from_mapping( SECRET_KEY='dev', SQLALCHEMY_TRACK_MODIFICATIONS=False, SQLALCHEMY_DATABASE_URI=f'sqlite:///{Path(app.instance_path) / "flask_pysaml2_example.sql"}', SAML_IDP_SETTINGS={ # Add the settings for each IDP you want to use. Each entry in the # dictionary requires to keys: # # entityid: An identifier for the SP. Usually this is the same as the Single Sign On URL. # It will default to the SSO URL if left empty or undefined. # metadata_url: This is the metadata URL for the IDP. # # This configuration can be used with https://developer.okta.com/ # 'example-oktadev': { # 'entityid': 'http://flask-pysaml2-example', # 'metadata_url': 'https://<dev-account>.okta.com/app/<app-id>/sso/saml/metadata' # }, } )
to this (Using the
metadata_url
value exposed by the IdP):app.config.from_mapping( SECRET_KEY='dev', SQLALCHEMY_TRACK_MODIFICATIONS=False, SQLALCHEMY_DATABASE_URI=f'sqlite:///{Path(app.instance_path) / "flask_pysaml2_example.sql"}', SAML_IDP_SETTINGS={ 'example-oktadev': { 'entityid': 'http://flask-pysaml2-example', 'metadata_url': 'https://dev-12345678.okta.com/app/foobar/sso/saml/metadata' } } )
-
Start the example SAML SP
$ FLASK_APP=flask_pysaml2_example FLASK_DEBUG=1 flask run --port 5000
-
Start ngrok on the port that the example SAML SP is running on, in this case 5000/tcp.
$ ngrok http 5000
-
Replace the "" place holder with the assigned ngrok sub-domain. If Flask was started using
FLASK_DEBUG=1
, the application will be restarted automatically, otherwise, you'll have to stop it and start it again. -
Run saml.oktadev.com to test this example SAML SP
-
Open saml.oktadev.com in your browser and fill out as follows:
- Issuer: "urn:example:idp"
- SAML ACS URL: "http://.ngrok.io/saml/sso/example-oktadev"
- SAML Audience URI: "http://flask-pysaml2-example"
Be sure to replace the string "" with the sub-domain that ngrok selected for you!
-
Click the "Submit" button.
-
If the interaction was successful, the output will be similar to one in the following screenshot:
-
The application can also be used to follow the "SAML-enable your Python application" guide.
After successfully completing the steps in the "Testing" section above, select the "Run security validation" option to have saml.oktadev.com run an extended series of security tests against your SAML SP.