Hej,
I'm looking at an application (eduMEET, a custom frontend for
mediasoup, AFAICT) that comes with OIDC support but needs to be made
available to our SAML federation members, of course.
satosa seems to be a common choice for this (though I wouldn't be
unhappy if I could avoid protocol translation, e.g. by proxying from
httpd+mod_shib).
I'm going with the current (6.1.0) satosa release from the cheeseshop.
Ignoring my failed attempts to deploy this in uwsgi for now, I start
the application and everything seems to be going well (using
Gunicorn plus HTTP proxying and TLS-offloading):
* I've configured the SAML backend including a remote metadata url and
cert and the logs indicate the metadata is being consumed.
* I've "configured" (guessed at a few things) but not yet used the OIDC
frontend.
* No microservices as of yet.
[2020-03-26 11:43:13 +0000] [7135] [INFO] Starting gunicorn 20.0.4
[2020-03-26 11:43:13 +0000] [7135] [INFO] Listening at:
http://127.0.0.1:8080 (7135)
[2020-03-26 11:43:13 +0000] [7135] [INFO] Using worker: sync
[2020-03-26 11:43:13 +0000] [7138] [INFO] Booting worker with pid: 7138
[2020-03-26 11:43:13,860] [INFO] [satosa.base.__init__] Loading backend modules...
[2020-03-26 11:43:13,936] [DEBUG] [saml2.httpbase.send] GET to
https://eduid.at/md/aconet-registered.xml
[2020-03-26 11:43:14,003] [DEBUG] [saml2.httpbase.send] Response status: 200
[2020-03-26 11:43:14,003] [DEBUG] [saml2.httpbase.set_cookie] eduid.at: 'Set-Cookie:
...'
[2020-03-26 11:43:14,606] [DEBUG] [saml2.sigver._run_xmlsec] xmlsec command:
/usr/bin/xmlsec1 --verify --enabled-reference-uris empty,same-doc --pubkey-cert-pem
aconet-metadata-signing.crt --id-attr:ID
urn:oasis:names:tc:SAML:2.0:metadata:EntitiesDescriptor --output /tmp/tmp9gt_vrc6.xml
/tmp/tmpmhnh96n3.xml
[2020-03-26 11:43:14,681] [INFO] [satosa.plugin_loader.load_backends] Setup backends:
['saml']
[2020-03-26 11:43:14,681] [INFO] [satosa.base.__init__] Loading frontend modules...
[2020-03-26 11:43:14,804] [INFO] [satosa.plugin_loader.load_frontends] Setup frontends:
['oidc']
[2020-03-26 11:43:14,804] [INFO] [satosa.base.__init__] Loading micro services...
[2020-03-26 11:43:14,804] [INFO] [satosa.plugin_loader.load_request_microservices] Loaded
request micro services: []
[2020-03-26 11:43:14,804] [INFO] [satosa.plugin_loader.load_response_microservices] Loaded
response micro services:[]
[2020-03-26 11:43:14,805] [DEBUG] [satosa.routing.__init__] Loaded backends with
endpoints: [<satosa.backends.saml2.SAMLBackend object at 0x7f45e59ad0b8>]
[2020-03-26 11:43:14,805] [DEBUG] [satosa.routing.__init__] Loaded frontends with
endpoints: [<satosa.frontends.openid_connect.OpenIDConnectFrontend object at
0x7f45e54d3b70>]
[2020-03-26 11:43:14,806] [DEBUG] [satosa.routing.__init__] Loaded micro services with
endpoints: []
So far so good.
I've also used `satosa-saml-metadata` to generate backend.xml. That
contained a copy of the provided SAML SP certificate, though with a
use="signing" restriction. (I.e., the metadata generated that way
would fail with any default Shibboleth IDP. Unless pysaml2 doesn't
support encrypted assertions or reponses I consider this a bug. At
least neither the satosa nor the pysaml2 docs had anything on this.)
So I've removed that 'use' restriction to cause the IDP to send
encrypted assertions but later also /disabled/ that in the IDP again:
I get the same exception either way, so this may not in fact be
related.
With no idea how to test the SAML side of things (I know nothing about
OIDC and so left the OP setup and RP integration for later) I sent the
SP an unsolilcited response from my IDP. ('allow_unsolicited: True' is
set in the SAML backend config) which ultimately fails with an
"Unknown error". Stdout from Gunicorn below:
[2020-03-26 11:43:41,080] [DEBUG] [satosa.proxy_server.unpack_post] unpack_post::
{'SAMLResponse': ...
[2020-03-26 11:43:41,081] [DEBUG] [satosa.proxy_server.unpack_request] read request data:
{'SAMLResponse': ...
[2020-03-26 11:43:41,081] [INFO] [satosa.base._load_state]
[urn:uuid:b370f69a-d7e2-49b6-9e32-e31920b89d59] Loaded state {'SESSION_ID':
'urn:uuid:b370f69a-d7e2-49b6-9e32-e31920b89d59'} from cookie
[2020-03-26 11:43:41,081] [DEBUG] [satosa.routing.endpoint_routing]
[urn:uuid:b370f69a-d7e2-49b6-9e32-e31920b89d59] Routing path: saml/acs/post
[2020-03-26 11:43:41,082] [DEBUG] [satosa.routing._find_registered_endpoint_for_module]
[urn:uuid:b370f69a-d7e2-49b6-9e32-e31920b89d59] Found registered endpoint: module
name:'saml', endpoint: saml/acs/post
[2020-03-26 11:43:41,083] [DEBUG] [saml2.response._loads] xmlstr: ...
[2020-03-26 11:43:41,086] [DEBUG] [saml2.sigver._check_signature] ==== Certs from metadata
====
https://idp.example.edu/saml: [<tempfile._TemporaryFileWrapper object at
0x7f45e67d67b8>, <tempfile._TemporaryFileWrapper object at 0x7f45e67d67f0>] ====
[2020-03-26 11:43:41,086] [DEBUG] [saml2.sigver._run_xmlsec] xmlsec command:
/usr/bin/xmlsec1 --verify --enabled-reference-uris empty,same-doc --pubkey-cert-pem
/tmp/tmpqaj6buom.pem --id-attr:ID urn:oasis:names:tc:SAML:2.0:protocol:Response --node-id
_b2ea47f03f30638517a9649f8baf4e1f --output /tmp/tmphc_hm0cw.xml /tmp/tmp8mavdoev.xml
[2020-03-26 11:43:41,098] [DEBUG] [saml2.response._postamble] response: ...
[2020-03-26 11:43:41,103] [DEBUG] [saml2.entity._parse_response] XMLSTR: b'...'
[2020-03-26 11:43:41,103] [INFO] [saml2.response.status_ok] status: <ns0:Status
xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol"><ns0:StatusCode
Value="urn:oasis:names:tc:SAML:2.0:status:Success" /></ns0:Status>
[2020-03-26 11:43:41,104] [DEBUG] [saml2.response.parse_assertion] ***Encrypted
assertion/-s***
[2020-03-26 11:43:41,105] [DEBUG] [saml2.response.parse_assertion] --- AVA: {}
[2020-03-26 11:43:41,105] [ERROR] [satosa.base.run]
[urn:uuid:b370f69a-d7e2-49b6-9e32-e31920b89d59] Uncaught exception
Traceback (most recent call last):
File "/usr/local/venv/SATOSA/lib/python3.7/site-packages/satosa/base.py", line
289, in run
resp = self._run_bound_endpoint(context, spec)
File "/usr/local/venv/SATOSA/lib/python3.7/site-packages/satosa/base.py", line
229, in _run_bound_endpoint
return spec(context)
File
"/usr/local/venv/SATOSA/lib/python3.7/site-packages/satosa/backends/saml2.py",
line 341, in authn_response
if context.state[self.name]["relay_state"] !=
context.request["RelayState"]:
File "/usr/local/venv/SATOSA/lib/python3.7/collections/__init__.py", line
1025, in __getitem__
raise KeyError(key)
KeyError: 'saml'
[2020-03-26 11:43:41,106] [ERROR] [satosa.proxy_server.__call__] Unknown error
Traceback (most recent call last):
File "/usr/local/venv/SATOSA/lib/python3.7/site-packages/satosa/base.py", line
289, in run
resp = self._run_bound_endpoint(context, spec)
File "/usr/local/venv/SATOSA/lib/python3.7/site-packages/satosa/base.py", line
229, in _run_bound_endpoint
return spec(context)
File
"/usr/local/venv/SATOSA/lib/python3.7/site-packages/satosa/backends/saml2.py",
line 341, in authn_response
if context.state[self.name]["relay_state"] !=
context.request["RelayState"]:
File "/usr/local/venv/SATOSA/lib/python3.7/collections/__init__.py", line
1025, in __getitem__
raise KeyError(key)
KeyError: 'saml'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File
"/usr/local/venv/SATOSA/lib/python3.7/site-packages/satosa/proxy_server.py",
line 117, in __call__
resp = self.run(context)
File "/usr/local/venv/SATOSA/lib/python3.7/site-packages/satosa/base.py", line
307, in run
raise SATOSAUnknownError("Unknown error") from err
satosa.exception.SATOSAUnknownError: Unknown error
Now, the KeyError comes from the 'name' of my SAML backend plugin config:
module: satosa.backends.saml2.SAMLBackend
name: saml
So when context.state[self.name] doesn't exist (or doesn't have a
"relay_state" key itself) in authn_response() from
satosa/backends/saml2.py I guess something about the relaystate of
COOKIE_STATE_NAME or my deployment could be off?
Here's that part from my proxy_conf.yaml (I haven't checked the code
yet what the defaults are, the documentation doesn't mention any):
BASE:
https://test.example.edu
COOKIE_STATE_NAME: satosa_state
# Also tried with delete set to False
CONTEXT_STATE_DELETE: True
STATE_ENCRYPTION_KEY: somestring
cookies_samesite_compat:
- [satosa_state, "SATOSA_STATE_LEGACY"]
Another data point: When trying to start SAML SSO by accessing the
discovery_response endpoint at <base>/<name>/disco I end up with the
exception raised in disco_response() from satosa/backends/saml2.py
("No IDP chosen for state" / "No IDP chosen")
Any pointers?
Should I post (even) more config snippets?
Logs from the other exception too, when accessing the disco endpoint?
Cheers,
-peter