SATOSA

SATOSA is a proxy written in Python which helps for translating between different authentication protocols such as SAML2, OpenID Connect and OAuth2.

We will slowly learn about SATOSA in details in the coming chapters. For now we will learn how to configure one SATOSA instance to work with our example IdP and service provider.

SP ---> SATOSA FRONTEND <--->SATOSA BACKEND <-----> IdP

Setting up SATOSA

$ git clone https://github.com/IdentityPython/satosa.git
$ cd satosa
$ python3 -m venv .venv
$ source .venv/bin/activate
$ python3 -m pip install wheel
$ python3 -m pip install -e .
$ cd example/
$ cp internal_attributes.yaml.example internal_attributes.yaml
$ cp proxy_conf.yaml.example proxy_conf.yaml
$ cp ~/localhost+2.pem ./proxy.crt
$ cp ~/localhost+2.pem ./backend.crt
$ cp ~/localhost+2-key.pem ./backend.key
$ cp ~/localhost+2-key.pem ./proxy.key

Here we are using the same key/certificate for both the proxy frontend and backend.

Update the proxy_conf.yaml file first.

--- proxy_conf.yaml.example	2023-11-27 12:48:53.272742476 +0100
+++ proxy_conf.yaml	2023-11-21 16:15:21.878249924 +0100
@@ -1,7 +1,7 @@
-BASE: https://example.com
+BASE: https://localhost:8010
 
 COOKIE_STATE_NAME: "SATOSA_STATE"
-CONTEXT_STATE_DELETE: yes
+CONTEXT_STATE_DELETE: false
 STATE_ENCRYPTION_KEY: "asdASD123"
 
 cookies_samesite_compat:
@@ -15,8 +15,8 @@
 FRONTEND_MODULES:
   - "plugins/frontends/saml2_frontend.yaml"
 
-MICRO_SERVICES:
-  - "plugins/microservices/static_attributes.yaml"
+MICRO_SERVICES: []
+#  - "plugins/microservices/static_attributes.yaml"
 
 LOGGING:
   version: 1

We are mentioning that we will be using port 8010 along with TLS for the example server.

We are also using both SAML frontend and backend. This is mentioned via the following in the proxy_conf.yaml file. There can be more than one frontend and backend.

BACKEND_MODULES:
  - "plugins/backends/saml2_backend.yaml"

FRONTEND_MODULES:
  - "plugins/frontends/saml2_frontend.yaml"

We need to setup next frontend and backend.

$ cd plugins/backends/
$ cp saml2_backend.yaml.example saml2_backend.yaml
diff -Naur saml2_backend.yaml.example saml2_backend.yaml
--- saml2_backend.yaml.example	2023-11-21 16:06:31.650318811 +0100
+++ saml2_backend.yaml	2023-11-21 16:26:37.869130158 +0100
@@ -1,14 +1,14 @@
 module: satosa.backends.saml2.SAMLBackend
 name: Saml2
 config:
-  idp_blacklist_file: /path/to/blacklist.json
+  #idp_blacklist_file: /path/to/blacklist.json
 
-  acr_mapping:
-    "": default-LoA
-    "https://accounts.google.com": LoA1
+  # acr_mapping:
+  #   "": default-LoA
+  #   "https://accounts.google.com": LoA1
 
   # disco_srv must be defined if there is more than one IdP in the metadata specified above
-  disco_srv: http://disco.example.com
+  #disco_srv: http://disco.example.com
 
   entityid_endpoint: true
   mirror_force_authn: no
@@ -80,8 +80,9 @@
             text: "http://sp.logo.url/"
             width: "100"
             height: "100"
-        authn_requests_signed: true
-        want_response_signed: true
+        authn_requests_signed: false
+        want_response_signed: false
+        want_assertions_or_response_signed: true
         allow_unsolicited: true
         endpoints:
           assertion_consumer_service:

And the same for the frontend:

$ cd ../frontends/
$ cp saml2_frontend.yaml.example saml2_frontend.yaml

And update it with the following configuration.

--- saml2_frontend.yaml.example	2023-11-27 12:41:56.187392054 +0100
+++ saml2_frontend.yaml	2023-11-21 16:20:25.274196172 +0100
@@ -49,8 +49,8 @@
               "remd:contactType": "http://refeds.org/metadata/contactType/security",
             },
         }
-    key_file: frontend.key
-    cert_file: frontend.crt
+    key_file: proxy.key
+    cert_file: proxy.crt
     metadata:
       local: [sp.xml]

Next we will have to generate the metadata for the SATOSA proxy and then start the proxy server itself.

$ cd ../..
$ satosa-saml-metadata proxy_conf.yaml proxy.key proxy.crt
$ gunicorn -b 0.0.0.0:8010 satosa.wsgi:app --keyfile proxy.key --certfile proxy.crt

Updating the IdP with proxy's metadata

Now we have to update the IdP with the proxy's metadata as service provider. We can either link or copy the backend.xml file for this.

$ ln -s ../../../satosa/example/backend.xml

And then updated the idp_conf.py file.

--- idp_conf.py.example	2023-11-21 14:41:57.200660142 +0100
+++ idp_conf.py	2023-11-21 16:30:32.719075149 +0100
@@ -2,15 +2,13 @@
 # -*- coding: utf-8 -*-
 import os.path
 
+from saml2 import BINDING_HTTP_REDIRECT, BINDING_URI
 from saml2 import BINDING_HTTP_ARTIFACT
 from saml2 import BINDING_HTTP_POST
-from saml2 import BINDING_HTTP_REDIRECT
 from saml2 import BINDING_SOAP
-from saml2 import BINDING_URI
 from saml2.saml import NAME_FORMAT_URI
-from saml2.saml import NAMEID_FORMAT_PERSISTENT
 from saml2.saml import NAMEID_FORMAT_TRANSIENT
-
+from saml2.saml import NAMEID_FORMAT_PERSISTENT
 
 try:
     from saml2.sigver import get_xmlsec_binary
@@ -71,6 +69,8 @@
         },
         "idp": {
             "name": "Rolands IdP",
+            "sign_response": True,
+            "sign_assertion": True,
             "endpoints": {
                 "single_sign_on_service": [
                     ("%s/sso/redirect" % BASE, BINDING_HTTP_REDIRECT),
@@ -113,10 +113,10 @@
         },
     },
     "debug": 1,
-    "key_file": full_path("pki/mykey.pem"),
-    "cert_file": full_path("pki/mycert.pem"),
+    "key_file": full_path("./server.key"),
+    "cert_file": full_path("./server.pem"),
     "metadata": {
-        "local": [full_path("../sp-wsgi/sp.xml")],
+        "local": [full_path("./backend.xml")],
     },
     "organization": {
         "display_name": "Rolands Identiteter",

We can then start the IdP server on port 8088.

$ python idp.py idp_conf

Setting up the service provider

To make things easier, feel free to clone the saml-examples repository, and then look at the sp3 directory.

We copied over the frontend.xml as the metadata from the proxy service, this will be used as IdP's metadata in the Flask based service provider.

--- ../sp2/saml2_backend.yaml	2022-07-21 14:02:10.464265209 +0200
+++ saml2_backend.yaml	2023-11-21 16:32:31.219046414 +0100
@@ -29,7 +29,7 @@
     - {contact_type: support, email_address: support@example.com, given_name: Support}
 
     metadata:
-      local: [idp.xml]
+      local: [frontend.xml]
 
     entityid: http://localhost:5000/proxy_saml2_backend.xml
     accepted_time_diff: 60

We can start the service next.

$ flask run

Then we can login to the server. If you notice the address bar, you can see that we fist went to the SATOSA proxy and then to the IdP server.

SAML to SAML