djangosaml2 icon indicating copy to clipboard operation
djangosaml2 copied to clipboard

Question : Multiple tenant SP has to offer ACS dynamically

Open Malshtur opened this issue 3 years ago • 5 comments

Hello,

I am working to port SAML to a multi tenant application where each tenant has its own database. So every tenant manage its own users, objects, etc.

The issue I am trying to resolve has to do with our authentication scheme requiring to specify what tenant the user authenticates to. I have considered the three following approaches :

  • Use RelayState : I would rather have all the informations packed in the AuthnRequest and Response. Security can be an issue and it feels somehow not natural.
  • Use different AssertionConsumerService : At metadata level it is an issue. The application could create a new tenant leading to obsolete metadata not referencing the new ACS conresponding to the new tenant. Each tenant creation leads to metadata changes. Not acceptable in my case.
  • Use different AssertionConsumerServiceUrl : in AuthnRequest with mandatory signature and checking that urls are pertinent offers me the flexibility I hope to have. It would lead to the least amount of modification in configuration. No metadata modification

The latter is my preffered way to go but I can't wrap my finger around if it is possible with djangosaml2. Could you point me in the right direction if you support it ? If it is not the case I am only trying to find how to do it at pysaml2 level but I have no luck so far.

Thanks for your time.

Malshtur avatar Mar 02 '23 13:03 Malshtur

Yes, option 3 is very good

you just have to inherit https://github.com/IdentityPython/djangosaml2/blob/master/djangosaml2/views.py#L408 and then you can do overload of the method post_login, custom_redirect or whatever

then you have to map your new ACS to a specific urls (urls.py of your project) and also map it in the metadata, defining its url/webpath in the pysaml2 configuration, here (to get signed metadata automatically):

https://github.com/IdentityPython/djangosaml2/blob/master/docs/source/contents/setup.rst#pysaml2-specific-files-and-configuration

peppelinux avatar Mar 02 '23 13:03 peppelinux

Thanks for your reactivity and the details, truly fast !

Just to be sure we are talking about the same thing, in saml-core : AssertionConsumerServiceURL [Optional] Specifies by value the location to which the <Response> message MUST be returned to the requester. The responder MUST ensure by some means that the value specified is in fact associated with the requester. [SAMLMeta] provides one possible mechanism; signing the enclosing <AuthnRequest> message is another. This attribute is mutually exclusive with the AssertionConsumerServiceIndex attribute and is typically accompanied by the ProtocolBinding attribute.

From your response, I guess that it would lead to metadata modification on SP side and to update them on the IDP too. This is problematic in many deployment. So that is why I wanted to use the second option : signing the enclosing AuthnRequest and have the AssertionConsumerServiceUrl dynamically set in the request without changing the metadata.

I hope that I am a bit clearer and please forgive me if I did not understand you the first time.

EDIT: Did you mention the hook or overload to do something like selecting the tenant right after reponse is received in order to pass it to the application level ?

EDIT 2 : For clarity, what I was thinking is having a new AssertionConsumerService without altering the <SPSSODescriptor> in metadata as offers the AssertionConsumerServiceUrl field in AuthnRequest.

Malshtur avatar Mar 02 '23 15:03 Malshtur

for the security of the solution the IDP should only response to a known ACS, taken from the metadata of the requester

peppelinux avatar Mar 02 '23 17:03 peppelinux

In general, i completly agree but if and only if the AuthnRequest is signed then the underlying security is the same because it is based on the same cryptographic keys.

The only case i could think of is that the underlying SP is vulnerable to injections that could lead to sign an AuthnRequest with a malicious AssertionConsumerServiceUrl. This could also modify metadata nonetheless.

The standard allows both as I mentionned above, but if I were to use djangosaml2 as you explained I have to share metadata dynamically between SP and IDP to refresh the list of AssertionConsumerService, right ?

Malshtur avatar Mar 03 '23 13:03 Malshtur

right

peppelinux avatar Mar 03 '23 16:03 peppelinux