Since I've been able to answer my own question about manual client
registration (w/o MongoDB) in another thread (now resolved)
https://lists.sunet.se/pipermail/satosa-users/2020-March/000120.html
I'm starting a new thread about the latter (unrelated) issue:
Starting at the oidc-enabled app I'm sent to satosa with an auth
request, the client is now known/found (client_db details shared at
the above URL), the saml backend is involked, SAML WebSSO happens,
attributes are mapped and I am back "Routing to frontend: oidc".
Then satosa raises an InvalidAuthorizationCode exception:
[pyop.authz_state.create_authorization_code] creating authz code for scope=openid email profile
[pyop.authz_state.create_authorization_code] new authz_code=eff...cd79 to client_id=someClientId for sub=someid at example.org valid_until=1585612419
...
[satosa.proxy_server.unpack_request] read request data: {'grant_type': 'authorization_code', 'code': 'eff...cd79', 'redirect_uri': 'https://some.example.org/auth/callback'}
...
[pyop.client_authentication.verify_client_authentication] client authentication in Authorization header Basic base64-encoded-client_id_colon_client_secret
[satosa.frontends.openid_connect.token_endpoint] invalid request: eff...cd79 unknown
Traceback (most recent call last):
File "/usr/local/venv/SATOSA/lib/python3.7/site-packages/satosa/frontends/openid_connect.py", line 363, in token_endpoint
response = self.provider.handle_token_request(urlencode(context.request), headers)
File "/usr/local/venv/SATOSA/lib/python3.7/site-packages/pyop/provider.py", line 324, in handle_token_request
return self._do_code_exchange(token_request, extra_id_token_claims)
File "/usr/local/venv/SATOSA/lib/python3.7/site-packages/pyop/provider.py", line 352, in _do_code_exchange
authentication_request = self.authz_state.get_authorization_request_for_code(token_request['code'])
File "/usr/local/venv/SATOSA/lib/python3.7/site-packages/pyop/authz_state.py", line 320, in get_authorization_request_for_code
raise InvalidAuthorizationCode('{} unknown'.format(authorization_code))
pyop.exceptions.InvalidAuthorizationCode: eff...cd79 unknown
So the authz code created above (first line) is now unkown (last line).
Why would that happen and what can I do to avoid it?
On the RP side (seemingly using
https://www.npmjs.com/package/openid-client) I currently only see the
same thing as RP is merely relaying the OP error, it seems. And this
being an OP error I probably don't have to dig into the RP side to get
more/better logging:
OPError: invalid_grant (eff...cd79 unknown)
at processResponse (/opt/edumeet/mm/server/node_modules/openid-client/lib/helpers/process_response.js:45:13)
at Client.grant (/opt/edumeet/mm/server/node_modules/openid-client/lib/client.js:1235:26)
at process._tickCallback (internal/process/next_tick.js:68:7)
I'd appreciate suggestions on what I could have done wrong following
the satosa documentation where available, or how to further debug this
issue.
If other/more information (config details, logs, etc.) are needed or
my obscuring of details above is unclear I'm happy to provide those.
-peter
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
Not knowing whether my satosa instance is fully working yet (see my
other thread) I'm now continuing to try to get the application
(eduMEET) to work with satosa's oidc frontend, as per the app's
published config example:
https://github.com/havfo/multiparty-meeting/blob/master/server/config/confi…
So I've made up a client_id and client_secret on the RP side and
provided the client with an issuerURL (base URL of satosa), let it
request all the scopes in the world and set its own redirect_uri.
With those all set I do see requests to satosa's .well-known endpoints
from the application in satosa logs, e.g.
Found registered endpoint: module name:'oidc', endpoint: .well-known/openid-configuration
(And of course accessing the endpoint myself I can see that it works
and produces JSON with its config.)
Now on the OP side (satosa oidc frontend) I haven't done any setup
for the client yet, so I guess the error in the log is to be expected:
Error in authn req: Unknown client_id
Now what would be the next steps to register that client?
The request from the client (according to satosa's logs) has these
query parameters (where cid and csec are the correct client_id and
client_secret, respectively):
client_id=cid&scope=openid+email+profile&response_type=code&redirect_uri=https%3A%2F%2Fexample.org%2Fauth%2Fcallback&state=e30%3D&client_secret=csec
My plugins/frontends/openid_connect_frontend.yaml looks like the
published example, essentially:
module: satosa.frontends.openid_connect.OpenIDConnectFrontend
name: oidc
config:
signing_key_path: /etc/satosa/oidc-provider.key
#db_uri: mongodb://db.example.com # optional: only support MongoDB, will default to in-memory storage if not specified
client_db_path: /etc/satosa/oidc-clients.json
provider:
client_registration_supported: True
response_types_supported: ['code', 'token', 'id_token']
subject_types_supported: ['public', 'pairwise']
scopes_supported: ['openid', 'email', 'profile']
Only that I tried to enable pretty much everything (all repose and
subject types, all scopes, client registration) since I had no idea
what the RP side wants, yet. (Seems I can remove all response types
except 'code', as per the log shown above.)
I don't have MongoDB set up yet since the comment above suggests an
in-memory store would be used, which is fine for my current testing.
And looking at _create_provider() at frontends/openid_connect.py the
code would use the file referenced by client_db_path if db_uri isn't
set even before falling back to storing it in a variable.
The file referenced in client_db_path exists, is writable by the user
satosa runs as, and currently contains only '{}' (without the quotes).
So IMO that should be sufficient.
Any hints on how to register the application?
The documenation is a bit sparse here
https://github.com/IdentityPython/SATOSA/blob/master/doc/README.md#frontend…
only mentioning that *without* dynamic client registration (which I
have enabled for now, but maybe the RP doesn't support it) I'd have to
manually create the data structures in MongoDB (or the file in
client_db_path) for my client, as per the oidc spec for Client
Registration Responses.
Could someone share a json sample to put into the file referenced by
client_db_path (if that's how it's supposed to work)?
Cheers,
-peter