Dear all,
Is it possible to use a different discovery service depending on the SP
that sent a SAML AuthnRequest to SATOSA, or do I have to do that in the
discovery service's frontend somehow?
Best wishes,
Matthew
--
"The lyf so short, the craft so longe to lerne."
I want to again say "thanks" to Ioannis, Rainer, Scott, and everyone
else for their help and instruction during the various IdentityPython
and SATOSA meetings at TIIME this week. Chris Phillips and I were able
to get a SATOSA 3.4.8 deployment working in Chris's idp-installer test
bed. To that end I want to share my notes from the process, at the end
of which an interested party could perform a basic, end-to-end test of
the current SATOSA release using SAMLtest (https://samltest.id/)
1. I installed Ubuntu Server 18.04.1; run the following commands as root
to install the prerequisites:
```sh
apt update
apt dist-upgrade -y
apt install -y git python3-dev build-essential python3-pip libffi-dev
libssl-dev xmlsec1 libyaml-dev libxml2-utils
pip3 install --upgrade virtualenv
virtualenv -p python3 /opt/satosa
/opt/satosa/bin/pip install --upgrade pip setuptools
/opt/satosa/bin/pip install SATOSA
```
This is essentially the Docker image build process, only it uses the
current SATOSA release (etc.) on PyPI.
2. Copy
https://github.com/IdentityPython/SATOSA/tree/v3.4.8/docker/attributemap
s to /opt/satosa/attributemaps.
I'm not sure this is strictly necessary as the built-in pysaml2
attribute maps should be used by default, but it's what the Docker image
build process does.
3. Copy https://github.com/IdentityPython/SATOSA/tree/v3.4.8/example to
/opt/satosa/etc.
4. SATOSA doesn't have a default configuration, so you must provide it
yourself.
```sh
cp /opt/satosa/etc/proxy_conf.yaml.example \
/opt/satosa/etc/proxy_conf.yaml
cp /opt/satosa/etc/internal_attributes.yaml.example \
/opt/satosa/etc/internal_attributes.yaml
cp /opt/satosa/etc/plugins/frontends/saml2_frontend.yaml.example \
/opt/satosa/etc/plugins/frontends/saml2_frontend.yaml
cp /opt/satosa/etc/plugins/backends/saml2_backend.yaml.example \
/opt/satosa/etc/plugins/backends/saml2_backend.yaml
cp /opt/satosa/etc/plugins/microservices/static_attributes.yaml.example
\
/opt/satosa/etc/plugins/microservices/static_attributes.yaml
```
5. You may change the proxy URL (the value of BASE in
/opt/satosa/etc/proxy_conf.yaml), but it _must_ be a method plus
hostname without any trailing slash or path components, e.g.,
`https://proxy.example.com`, not `https://proxy.example.com/` nor
`https://proxy.example.com/satosa`. SATOSA must be hosted at the root
of your web site.
6. Comment out the `idp_blacklist_file` and `disco_srv` settings in
/opt/satosa/etc/plugins/backends/saml2_backend.yaml.
7. Generate IdP, SP, metadata signing, and web site keying material:
```sh
for i in frontend backend metadata https; do
openssl req -batch -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /opt/satosa/etc/$i.key -out /opt/satosa/etc/$i.crt \
-subj /CN=proxy.example.com
done
```
8. Download the SAMLtest metadata.
```sh
curl https://samltest.id/saml/sp > /opt/satosa/etc/sp.xml
curl https://samltest.id/saml/idp > /opt/satosa/etc/idp.xml
```
9. Generate the proxy metadata. (How you do this changes in future
releases of SATOSA.)
```sh
. /opt/satosa/bin/activate
cd /opt/satosa/etc
satosa-saml-metadata proxy_conf.yaml metadata.key metadata.crt
--split-frontend --split-backend --dir /opt/satosa/etc
xmllint --format /opt/satosa/etc/Saml2IDP_0.xml >
/opt/satosa/etc/proxy-idp.xml
xmllint --format /opt/satosa/etc/Saml2_0.xml >
/opt/satosa/etc/proxy-sp.xml
```
10. Edit the proxy metadata files to remove the `<ns1:Signature>`
element, else SAMLtest will be unable to load them due to an invalid
signature.
11. Upload the proxy metadata to SAMLtest
(https://samltest.id/upload.php)
12. SAMLtest doesn't release the eduPerson Targeted ID attribute, so
you'll need to change the last three lines of
/opt/satosa/etc/internal_attributes.yaml to the following (and before
anyone says anything, NEVER USE AN EMAIL ADDRESS AS AN IDENTIFIER---this
is just a quick hack to get SATOSA working):
```
hash: [mail]
user_id_from_attrs: [mail]
user_id_to_attr: mail
```
13. Start SATOSA:
```sh
. /opt/satosa/bin/activate
cd /opt/satosa/etc
gunicorn -b0.0.0.0:443 --keyfile https.key --certfile https.crt
satosa.wsgi:app
```
14. At this point you should be able to perform an IdP test
(https://samltest.id/start-idp-test/) by specifying the entity ID of the
proxy's front end, e.g., https://example.com/Saml2IDP/proxy.xml. The
SAMLtest SP will request authentication by your proxy IdP, causing your
proxy SP to request authentication by the SAMLtest IdP. If everything
works right, you will end up back at the SAMLtest SP:
SAMLtest SP ---AuthnRequest---> SATOSA front end (IdP)/back end (SP)
---AuthnRequest---> SAMLtest IdP
SAMLtest SP <---AuthnResponse--- SATOSA front end (IdP)/back end (SP)
<---AuthnResponse--- SAMLtest IdP
I hope this helps other adopters. If you have any questions, please
reply on list so everyone can benefit from the discussion.
Best wishes,
Matthew
--
"The lyf so short, the craft so longe to lerne."
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
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?
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