Dear all,
I need help understanding why SATOSA isn't passing the IdP assertions
through to an SP. SATOSA sends it a successful authentication response,
but it's devoid of any attributes.
I know that SATOSA gets the right assertion from the IdP because there's
a "backend received attributes" log entry that includes the expected
values.
I see that the PrimaryIdentifier plugin correctly identifies the ePPN
because there's a "PRIMARY_IDENTIFIER: Setting attribute uid" log entry.
I also see the LdapAttributeStore plugin skip processing, as expected.
But when SATOSA routes the request to the Saml2IDP frontend, it logs the
following:
```
Filter: []
returning attributes {}
```
And then the SAML response doesn't include any attributes.
Here's my complete configuration except for passwords and keying
material:
https://gist.github.com/xenophonf/d07ab00a30e5559674936e3a549d0141
What am I missing?
The important detail in the log output is this line:
[Fri Mar 30 23:11:59.988888 2018] [wsgi:error] [pid 28459] [remote 10.63.1.50:57163]
[2018-03-30 23:11:59,988] [DEBUG] [satosa.frontends.saml2]:
[urn:uuid:3894b3ac-843b-43c0-a17a-c5d52d0d6f2a] Filter: []
The 'Filter' used by the SAML2 IdP frontend for filtering attributes
that it is going to send to the consuming SP is empty.
It should instead be the list of SATOSA internal attributes that it has
determined are appropriate to send to the consuming SP. Something like
this (taken from a log entry for one of my deployments):
[2018-03-31 13:55:45,657] [DEBUG] [satosa.frontends.saml2]:
[urn:uuid:de534890-9cce-40e3-bbee-2062816bee42] Filter: ['role',
'emailaddress', 'idporgdisplayname', 'employeenumber',
'upn', 'name', 'mail', 'awssessionduration',
'awsrole', 'eppn', 'awsrolesessionname', 'idpdisplayname',
'edupersontargetedid', 'uid', 'commonname', 'displayname',
'ismemberof', 'surname', 'givenname', 'idporgname']
So why is your Filter empty?
SATOSA creates the filter by examining the IdP attribute policy (default
and any specific override for the consuming SP), the metadata for the
consuming SP, and the mappings you have configured. Here the mappings
include those in internal_attributes.yaml, but also the mappings used
by pysaml2 to convert to and from the "on the wire" SAML representation
to the short or "friendly" SAML name.
It is probably easiest to just follow an attribute through the flow.
Consider given name.
I am guessing that the IdP you are using sends an assertion with an
element like this:
<saml2:Attribute
FriendlyName="givenName"
Name="urn:oid:2.5.4.42"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:AttributeValue>Matthew</saml2:AttributeValue>
</saml2:Attribute>
SATOSA/pysaml2 sees that and sees that it has
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
It then looks at the SAML attribute maps it has for attributes with that name
format.
Your SATOSA configuration does not specify 'attribute_map_dir' so the
defaults provided by pysaml2 are being used. You can see those at
https://github.com/IdentityPython/pysaml2/tree/master/src/saml2/attributema…
In the file saml_uri.py we find
MAP = {'identifier': 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
'fro': {'urn:oid:2.5.4.42' : 'givenName'},
'to' : {'givenName' : 'urn:oid:2.5.4.42'}
}
That is the only mapping that applies. All of the other mappings defined
in files in that directory applied for different values of
NameFormat.
So the given name attribute asserted by your IdP is mapped from
'urn:oid:2.5.4.42' to 'givenName' by the SATOSA SP.
Next SATOSA uses your mappings in internal_attributes.yaml to map the
SAML protocol 'givenName' to the internal SATOSA attribute 'givenname'
as you have configured it.
After passing through the microservices the internal SATOSA
attribute 'givenname' has the value 'Matthew'.
Then control passes to the SAML2 IdP frontend. It is responsible for
filtering the attributes and only sending those allowed by "policy".
Here "policy" includes the configuration for the SATOSA IdP frontend and
what the consuming SP signals it wants in metadata. It also makes sure that
the attributes sent use the "right" NameFormat.
In your case the consuming SP does not signal anything about attributes
in metadata.
SATOSA sees that the configuration for the IdP front end includes this
policy:
config:
idp_config:
service:
idp:
"policy":
default:
name_form:
urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified
That says that in lieu of an override for the particular consuming SP,
the SAML assertion sent should use <Attribute> elements with the
attribute NameFormat set to that value for name_form, ie.
NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
SATOSA/pysaml2 again consults internal_attributes.yaml and sees that the
internal attribute 'givenname' should be converted for the SAML protocol to
the SAML friendly or short name 'givenName'. It then consults the SAML
attribute maps looking for a mapping to map the short/friendly
'givenName' to an "on the wire" SAML name.
Here is the issue: since you have not configured 'attribute_map_dir'
SATOSA/pysaml2 is using the defaults for SAML attribute maps, and the
defaults at
https://github.com/IdentityPython/pysaml2/tree/master/src/saml2/attributema…
have no mapping for 'givenName' with the NameFormat
NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
The only mappings for that NameFormat are in adfs_v1x.py and adfs_v20.py
and you will not find 'givenName' in them.
So SATOSA cannot find any way to map the internal attribute 'givenname'
to on the wire SAML and hence it is left out of the Filter that is
constructed and later applied.
This is going to be true for all the mappings you have in
internal_attributes.yaml. None of the SAML short/friendly names appear
in a mapping for
NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
The exception should have been
"mail":
"saml": [email, emailAdress, mail]
but you have a typo: 'emailAdress' (one 'd') does not appear but
'emailAddress' does.
To get the SATOSA IdP frontend to assert the attributes, you have three
choices:
1) Change the policy, either the default or with an SP override, so that
the IdP frontend wants to use
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
instead of
NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
2) Change the SP metadata so that it includes <RequestedAttribute>
elements with Name and NameFormat combinations that SATOSA/pysaml2 can
map to and from
3) Configure 'attribute_map_dir' to point to a set of mappings that tell
SATOSA/pysaml2 how to map to and from for
NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
Option (2) is not always going to be possible with your deployments so
it is probably not the best choice.
Option (1) would make your SATOSA IdP frontend SAML2Int compliant and
would probably work with most consuming SPs.
But since you often have to work with "interesting" cloud service SPs
that sometimes have interesting requirements on what they will consume,
you might want the full control that (3) gives you.
Probably the best approach is to change the default policy to use
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
but also specify a particular set of mappings that you control, rather
than the defaults, so that you can accommodate whatever needs some
consuming SP has.
Thanks,
Scott