- Issue created by @c. s. comfort
- π³π±Netherlands roderik Amsterdam,NL / Budapest,HU
isAuthenticated() does not exist, because it addresses an issue that is specific to SimpleSAMLphp / does not exist with SamlAuth.
See the two images at https://www.drupal.org/docs/contributed-modules/saml-authentication/usin... β if necessary:
- with SimpleSAMLphp, SAML auth happens outside of Drupal. Then the user is redirected to Drupal, with a cookie set -- and Drupal still needs to figure out whether the at-that-moment-anonymous user is allowed to be logged in. (using isAuthenticated(), which -from my memory- checks the cookie.)
- with SamlAuth, SAML auth happens inside Drupal, during the POST request to /saml/acs. And the SamlAuth module immediately logs the user in, during the same POST request. Either the user is logged in, or the user is presented with a login error. There is no other 'vague in-between state' like with SimpleSAMLphp auth.
Is it possible that the array is empty due to the IdP configuration? Or, am I perhaps misunderstanding at which point the array is actually populated given the current state of the SAML authentication flow?
getAttributes() only returns data while processing the /saml/acs POST request, not on any other page load -- and only after SAML authentication has already happened and was successful.
Without knowing the specifics of what you are solving, I am guessing:
- you're trying to do something during some event very early in the page load -- which is not a concept that works anymore.
- you should be doing the same thing immediately after successful SAML authentication. There's an event for that: SamlAuthEvents::USER_SYNC. See the comments there. See UserSyncEventSubscriber for an example implementation.
Note on this event, SAML authentication has already happened and your user ($event->getAccount()) is going to be logged in (except if you or some other event subscriber throws an exception or something horrible happens while saving the user account). So you don't need to do an isAuthenticated() check.
Or, alternatively, if you want to do something after authentication and Drupal user login has happened, and you cannot cancel it in any way anymore: check the ExternalAuthEvents::LOGIN event. SamlService->getAttributes() should work there always, if you need the attribute values (though the service isn't injected so it's slightly ugly).
This means you need to do some rewrite work, for this different concept. But the result will probably be (conceptually) simpler, I'm guessing.
Hi @roderik, thanks for the thorough replyβand for speaking to some of the inherent differences in the modules' approaches. Our use case is one where we're limiting access to specific paths based on a user's affiliation, retrieved from their attributes provided by the IdP (eg, a "staff" affiliation). We don't, however, map these users to individual Drupal accounts as there's no need (or desire) for the users to be registered locally: if they have the requisite affiliation, the page is returned; and, if not, they're redirected.
I'll return my attention to the events to see what I can shake out. Thanks again!
- π³π±Netherlands roderik Amsterdam,NL / Budapest,HU
We don't, however, map these users to individual Drupal accounts as there's no need (or desire) for the users to be registered locally
Oof! That makes things harder. I haven't heard yet, of a use case like this.
To summarize my previous response: samlauth intrinsically links "Idp authentication" to "Drupal user login". That's easier for the common use case.
But in your case,
- you need to peel those things apart again
- you likely need to store some (extra) status/data in a 'user session' that is separate from a logged-in Drupal user (which simpleSAMLphp did, and which samlauth doesn't do), in order to do this access check on those paths.
I think it's possible, though, to use just the "SAML authentication" part of this module and to remove the "Drupal user login" part, without making things too complicated. (I'm going to assume, for simplicity, that you never want to have a Drupal user login after someone returns from the IdP.)
- You'll need to overwrite the samlauth.saml service with a custom service that extends SamlService
- Your extending class can 'empty out'
doLogin()
(or changeacs()
, which is the only caller ofdoLogin()
. But I assume leavingacs()
is easier). - This is assuming that you don't want anything registered in the authmap table. (Also, I am not going into the horribble piece of spaghetti that is the
doLogin()
execution path... because you won't need it / will remove it.) - Then I advise experimenting with
saveSamlSession()
:- There is a concept of a "Saml session", separate from the Drupal login. But ss you can see from the horribly large comments, it's an afterthought / code that has just stuck around since v1.0 and not (to my knowledge) been used well.
- Decide what data you need, in an access check that you do on the other page loads.
- Then store that data somewhere you can get to it. (getAttributes() is available here if you need it)
- As you can see, currently the 'session data' is stored in PrivateTempStore (and you can just add your data next to it). I'm personally not convinced that this is better than just storing this data in $_SESSION -- because as soon as you store something in PrivateTempStore, you automatically/necessarily get a session anyway. I guess it depends on the nature of your data.
I.... think that works without further complications?
If you discover things that need to be patched along the way, I'm open to it. Although, until other people come along who want the same thing, I can imagine this is not going to turn into a configurable option to "skip user creation/login", but instead just a note in the README that this can be achieved with the above.
- π³π±Netherlands roderik Amsterdam,NL / Budapest,HU
I'm going to turn this into a reminder for me to, long-term, add something to the README and/or add a config option to skip user login (that might not be exposed in the UI).
It would be good to know if the current saveSamlSession() code is adequate for implementing such a use case.
Again, thanks for taking the time to think this through and share some possible solutions for consideration. The wrinkle is that we do have some users that authenticate with the IdP for Drupal user logins (eg, our admins, content editors), so we can't ditch that portion of the module as you outlined. I'm starting to foresee a path down which we may refactor our approach to handling the attribute-restricted paths in a way that relies on normal Drupal user sessions/entities.