TL;DR: How can I get SaToSa to select one attribute's value from a
list of attribute names, not all of which may be present?
Ivan's recommendation from PR 222 doesn't work for me:
https://github.com/IdentityPython/SATOSA/pull/222#issuecomment-533238061
Context: I'm trying to use SaToSa as a SAML SP registered in a
saml2int identity federation (SAML2 backend module plugin) protecting
a bunch of OIDC RPs (openid connect frontend module plugin).
In the field not all SAML IDPs support all of the common identifier
attributes: Some may only support e.g. eduPersonPrincipalName while
others will also (or in an hypothetical future maybe: only) support
the "new" SAML standard identifier attributes Subject-ID and/or
Pairwise-ID. (And while I could hard-code 'eppn' as the lowest common
denominator for everyone that would nullify any benefits the new
standard identifier attributes might offer.)
FWIW, the Shibboleth SP calls its own support for this the REMOTE_USER
precedence list: The first attribute from a list of given attribute
names that has a value is chosen as the value for REMOTE_USER.
Implementing Ivan's recommendation from PR 222 (link above) doesn't
work for me, though. This fails:
attributes:
id:
openid: [sub]
saml: [subject-id, pairwise-id, eppn]
eppn:
openid: [eppn]
saml: [eduPersonPrincipalName]
user_id_from_attrs: [id]
The relevant log lines being:
skipped backend attribute ['subject-id', 'pairwise-id', 'eppn']: no value found
backend attribute ['eduPersonPrincipalName'] mapped to eppn (['foo(a)example.org'])
...
KeyError: 'id'
[ERROR] [satosa.proxy_server.__call__] Unknown error
I.e., eppn is available/mapped but generating the userid from the 'id'
attribute fails, seemingly because there is no 'id' attribute because
according to SaToSa the list ['eppn', 'subject-id', 'pairwise-id'] has
"no value found".
The available behaviour is unhelpful in two regards, AFAICT:
https://github.com/IdentityPython/SATOSA/pull/222#issuecomment-533240357
* It implements "all those attributes need to have a value (what
currently happens)" (Ivan's words from PR 222) when I've only ever
needed "at least one of these attributes needs to have a value" in
over a decade of running federations and federated services.
* The attributes I care about and would list as possible attribute
names are also *not* mutually exclusive, i.e., there may be none
(failure), some or all of them available from an IDP. In any case
I'd want the user id to only ever have the value of **one** such
attribute at maximum, even if multiple attributes may have values.
TBH, I can't see how the documented behaviour:
https://github.com/IdentityPython/SATOSA/tree/master/doc#user_id_from_attrs
> The attribute values of the attributes specified in this list will
> be concatenated and used as the subject identifier.
could ever be useful to anyone? What good would be the concatenation
of multiple attributes' values (e.g. ['subject-id', 'pairwise-id',
'eppn']) provided several of them were available?
"foobar@example.orgFOO987654321@example.orgFOO@example.org"
Whereas from my experience it's often necessary to support multiple
"acceptable alternatives" (different attributes for essentially the
same purpose/data) and therefore desireble to have the software pick
*one* attribute's value(s) from an ordered-by-preference list.
E.g. given ['subject-id', 'pairwise-id', 'eppn'] that would try
subject-id, then pairwise-id, then eppn and the first one that has a
value would be the one attribute whose values we'd return.
(I'd fail if none of the above were present/had a value.)
Is there a way to get that behaviour? I'm probably biased but to me that
would make a much saner default behaviour than what's available now.
Best regards,
-peter
I am writing to request assistance with releasing a custom attribute that is not listed as a requested attribute by one of our InCommon Service Providers (SPs). The attribute is present in the IDP response, but it appears that it is not being returned to the InCommon SP.
I have attempted to set the attribute as default for all SPs, but I would like to limit its release to specific SP if needed.
I have made some changes to the configuration files and observed the following log messages:
Filter: ['edupersonprincipalname', 'edupersonaffiliation', 'givenname', 'edupersonscopedaffiliation', 'mail', 'edupersontargetedid']
Attribute Statement: <ns0:AttributeStatement xmlns:ns0="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ns0:Attribute FriendlyName="mail" Name="urn:oid:0.9.2342.19200300.100.1.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<ns0:Attribute FriendlyName="abcID" Name="urn:oid:1.3.6.1.4.18941.1.2.1.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><ns0:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">8989898</ns0:AttributeValue></ns0:Attribute>
<ns0:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">99999</ns0:NameID></ns0:AttributeValue></ns0:Attribute></ns0:AttributeStatement>
Unknown attribute name: <ns0:Attribute xmlns:ns0="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" FriendlyName="abcID" Name="urn:oid:1.3.6.1.4.18941.1.2.1.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><ns0:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">8989898</ns0:AttributeValue></ns0:Attribute>
skipped backend attribute ['abcID']: no value found
I have made the following changes to the configuration files:
Internal_attributes.yaml
Added
abcid:
saml: [abcID]
Backend.yaml
Added
custom_attribute_release:
"default":
include: ["abcID"]
allow_unknown_attributes: true
attribute_map_dir: [/etc/satosa/attributemaps]
Frontend.yaml
-No specific changes made
Saml_url.py
From area:
'urn:oid:1.3.6.1.4.18941.1.2.1.1': 'abcID',
To area:
'abcID': 'urn:oid:1.3.6.1.4.18941.1.2.1.1',
Could you please help me troubleshoot this issue and provide guidance on how to release the custom attribute as needed?
Also how could I release this attribute as the NameID for just the specific SP that requires it?
When configuring a saml2 frontend or backend plugin with remote
metadata (url, cert) will that metadata be automatically regularly
refreshed from the configured url?
If yes, is the purpose of the metadata reload endpoint (which can be
enabled with enable_metadata_reload) solely to reload that metadata
immediately instead of automatically refreshing it later?
(I.e., nice to have but not essential.)
If no, does that mean I'll always have to set enable_metadata_reload
to a truthy value *and* protect that URL with web server ACLs (to
avoid having my service DoS'ed remotely by triggering reload of remote
metadata) *and* have to implement a cronjob or systemd timer that
regularly accesses the metadata reload endpoint?
I don't find anything that would trigger automatic metadata refresh in
satosa, so I guess that must come from pysaml2. There's a statement
in pysaml2/docs/howto/config.rst about metadata refresh when using MDQ
but nothing about aggregates (metadata.remote.url).
I see a reload() function defined in pysaml2/src/saml2/mdstore.py but
I basically only see that being used in saml2.Entity and the changelog
for 7.1.1 says "This method is to be externally invoked".
Any pointers?
-peter
I have deployed Satosa with a saml2 backend (SP) plugin loading
multiple IDPs via remote metadata and oidc "frontend" (OP) plugin with
currently one configured RP (client_db_path).
Now it seems the ressource/application to be protected (using OIDC)
may be more of a multi-tenant system, meaning there are separate
application instances (to be connected to the OIDC OP side), exactly
one per SAML IDP hooked up to Satosa on the saml2 backend side. I.e.,
each SAML IDP has its own OIDC RP.
So a given application instance / OIDC RP would send an OIDC authn req
to Satosa as OP (single frontend, configured and shared across all RPs)
and that would invoke a single saml2 backend to send SAML authn reqs
to the various IDPs known via remote metadata.
It seems to me that a single Satosa instance with a single oidc
frontend and a single saml2 backend should be able to handle this just
fine, by merely adding all applications as individual OIDC RPs (and
all IDPs to the remote metadata)? There's nothing "multi-tenanty"
about such a setup, yet: Just multiple OIDC RPs and SAML IDPs sharing
a single protocol converting proxy.
I think the next piece missing then would be avoiding SAML IDP
Disovery, since this information could already be derived from each
application/RP/client_id, so asking the subject should be avoided.
Would anyone have a suggestion on how to achieve this? I can assign
client_id values as needed so with carefully chosen values (for
automated mapping probably string/regex comparison, for
manual/explicit/static mapping a dictionary object) it should be
possible to get from OIDC RP (client_id) to SAML IDP (entityID)
without having to involve the subject?
Best regards,
-peter
Can I (pre-)select a single/specific IDP to use with a saml2 backend
plugin even if that backend loads multiple IDPs from remote metadata?
The documentation[1] seems to say that I can't avoid IDP Discovery
whenever multiple IDPs are available:
> To allow the user to choose which target provider they want to
> authenticate with, the configuration parameter disco_srv, must be
> specified if the metadata given to the backend module contains more
> than one IdP.
(Why load multiple IDPs from remote metadata then when you want to
avoid IDP Discovery? Because those IDPs may be available in remotely
managed and regularly re-signed metadata. And there's no MDQ service
available to hand out an up-to-date, signed copy of only a single IDP
for Satosa to consume.)
Related to this question: Setting the 'idp' configuration parameter in
service -> sp within the saml2 backend plugin (as shown in the pysaml2
docs[2]) resulted in no observable change for Satosa (running 8.4.0
from the official docker image). Is that to be expected? Other
parameters from pysaml2 are included in Satosa's saml2 backend plugin
at the same level as the 'idp' parameter,
e.g. 'authn_requests_signed'. But maybe I'm imagining a relationship
here between Satosa and pysaml2 config parameters that doesn't exist?
```yaml```
module: satosa.backends.saml2.SAMLBackend
name: sp
config:
sp_config:
service:
sp:
idp: ['https://idp.example.org/entity']
```
Anyway, here's the behaviour I (don't) see:
With exactly one IDP as list member (as in the YAML above and also the
pysaml2 docs[2]) this did not circumvent IDP Discovery as I had
expected and would have been useful: With only a single IDP allowed
there's no point in offering other IDPs to the subject.
(See above for why it may be useful to have multiple IDPs known via
metadata but still circumvent IDP discovery by configuration.)
But also when configuring one IDP (still as per above) and picking
*another* IDP during IDP Discovery access to the configured RP (oidc
frontend) was granted just the same. I.e., I could not determine how
the selected IDP was somehow "not allowed to be used" (as per the
pysaml2 docs, not Satosa's).
So unless I'm Doing Things Wrong™ it seems there's no use being made
of the 'idp' parameter within the SAML SP config (saml2 backend
plugin) within Satosa? If so, could or should there be?
Best,
-peter
[1] https://github.com/IdentityPython/SATOSA/blob/master/doc/README.md#use-a-di…
[2] https://pysaml2.readthedocs.io/en/latest/howto/config.html#idp
We have an Incommon Application that is sending a list of three (3) requested attributes. Even though KeyCloak is passing all of the attributes we have configured, once it is filtered out by Satosa it is only passing on the attributes that the actual SP from InCommon requested. Is there a way to override this?
Dear everyone,
I have a working SAML2-SAML2 proxy accessing the DFN-AAI, using the
DFN-AAI WAYF. This works as expected. Now I was wondering if it is
possible to add additional frontends, where each frontend has a DFN-AAI
IDP hardcoded it directly proxies to?
Thank you for your help!
Best regards,
Jonas Schwab
Dear all,
I am currently trying to set up a saml2-saml2 proxy and have come to an
impasse: It seems that I have incorrectly/incompletely set up the
frontend. When trying to log in satosa logs "configuration error:
unknown system entity <entityID of SP>". I thought the entityID would be
set in the frontend plugin configuration through
config.idp_config.metadata.local = <file containing SP metadata>. Do I
have to set the SP entityID somewhere else?
Thank you for your help!
Best regards,
Jonas Schwab
I'm trying to test my SATOSA OIDC OP using the OpenID Connect
Playground, but it looks like the client isn't registering itself with
SATOSA properly. I don't know how to fix this and would be grateful for
any help!
I have installed satosa-oidcop
(https://github.com/UniversitaDellaCalabria/SATOSA-oidcop) and
configured it to use Amazon DocumentDB (MongoDB-compatible).
On https://openidconnect.net/:
- I select the "OpenID Connect + OAuth2" mode (default and only option).
- I click "Configuration".
- I select the "Custom" server template.
- I enter the discovery document URL generated by SATOSA
($BASE_URL/.well-known/openid-configuration), click "Use Discovery
Document", and click "Save".
The configuration tool sets the authorization token endpoint to
$BASE_URL/Saml2/OIDC/authorization, the token endpoint to
$BASE_URL/OIDC/token, and the token keys endpoint to
$BASE_URL/OIDC/jwks. This looks correct.
The configuration tool tells me to set
"https://openidconnect.net/callback" as an allowed callback within my
application, and it shows me its OIDC Client ID, OIDC client secret,
scopes (defaults to "openid profile email phone address"), and optional
audience (blank).
When I click "Start" to begin the OIDC authentication process, I get the
following error:
https://openidconnect.net/callback?error=invalid_request&error_message=Resp…...
SATOSA logs the following at client configuration time:
```
[DEBUG] [satosa.routing.endpoint_routing] [urn:uuid:..1] Routing path:
.well-known/openid-configuration
[DEBUG] [satosa.routing.endpoint_routing] [urn:uuid:..1] Unknown backend
.well-known
[DEBUG] [satosa.routing._find_registered_endpoint_for_module]
[urn:uuid:..1] Found registered endpoint: module name:'OIDC', endpoint:
.well-known/openid-configuration
Then it logs the following when I start the OIDC request process:
```
[ERROR]
[pyop.request_validator.response_type_is_in_registered_response_types]
client metadata is missing response_types
[ERROR] [satosa.frontends.openid_connect._handle_authn_request]
[urn:uuid:..2] Error in authn req: Response type is not registered
```
When I look at DocumentDB, I see the "satosa" database and accompanying
collections, but the clients collection appears to be empty:
```
rs0:PRIMARY> show dbs
sample_database 0.000GB
satosa 0.000GB
rs0:PRIMARY> use satosa
switched to db satosa
rs0:PRIMARY> show collections
access_tokens
authz_codes
clients
refresh_tokens
subject_identifiers
rs0:PRIMARY> db.clients.find()
rs0:PRIMARY>
```
What am I missing?
--
"The reason that ed is the standard editor is to remind you that
things could be worse, and once were." -- Tim Lavoie in comp.lang.lisp
Dear all,
I’m pleased to announce a long overdue update to the Docker Official
Image for SATOSA, which includes several significant changes:
- SATOSA 8.4
- Python 3.12
- Debian 12 “bookworm”
- Alpine Linux 3.19
The updated container image is now available from Docker Hub. For more
information, see https://hub.docker.com/_/satosa.
Happy holidays!
Matthew
--
"The reason that ed is the standard editor is to remind you that
things could be worse, and once were." -- Tim Lavoie in comp.lang.lisp