I realise that a site cannot tell whether a user is logged into the
IdP without sending the user's browser to the IdP in a round-trip
"passive login". I would only do this once when a user switches
between any federation sites, so if the user is logged into the main
site, then clicks "shop" from the menu, which takes them to the shop
site, then upon first landing on the shop a passive login would be
attempted to log the user into the shop *if* there were already logged
into the IdP.
Now the problem comes if the user is *not* logged into the IdP. This
seems to be treated by SSP (or maybe SAML in general?) as an error
condition. For my application it is not an error - the shop would just
say, "Not logged in? Whatever!" and carry on.
When requesting a passive login, I need to pass the return URL and an
error URL. I have set both of these to the current URL. This appears
to work. If the user is logged into the IdP they are returned to the
page they landed on (now nicely logged into the local application
too). However, if the user it *not* logged into the IdP, they are
returned to their landing page (now treated as the "error page") but
with a bunch of parameters added to the URL:
?SimpleSAML_Auth_State_exceptionId=_71a11688aaf0f79...2977bc558%3Ahttp
%3A%2F%2Fwww.example.com%2Fauth%2Fmodule.php%2Fcore%2Fas_login.php
%3FAuthId%3Ddefault-sp%26ReturnTo%3D%252Ffoo%252F
How do I ask SSP passive login not to do this? How do I tell it an
"error" is NOT an error?
-- Jason
If there is no way to avoid having to use an "error URL", then maybe
the passive login needs to go into an iframe, with the iframe
redirecting the top page with a second passive login if it sees the
user is logged into the IdP. This is not ideal as it would involve
screen flicker, as the redirect would not happen until after the page
is rendered and the iframe does its passive login check. In fact, it
is so not ideal that I am going to avoid going down that route.
-- Jason
The final destination page is passed as a parameter to the error page.
All I need is an error page that takes that parameter then redirects
to that final page. It means an extra URL hop for no real reason (i.e.
going to the error page in order to leave it immediately), but I
suspect that is how it has to be treated? If only the passive login
request would take a parameter to indicate "don't bother sending all
that error state stuff"...
-- Jason
But it is an error :)
The NoPassive error is sent back as a SAML 2.0 error, and you need to
handle it in some way. E.g.:
$errorState = SimpleSAML_Auth_State::loadExceptionState();
if ($errorState !== NULL) {
/* We have an error. */
$error = $errorState[SimpleSAML_Auth_State::EXCEPTION_DATA];
if ($error instance of SimpleSAML_Error_NoPassive) {
/* Passive authentication failed. Don't try that again. */
$SESSION['PassiveFailed'] = TRUE;
SimpleSAML_Utilities::redirect('SOMEURL');
}
/* Some other error occured. */
die('Login failed!');
}
(Note that this code is untested.)
Best regards,
Olav Morken
UNINETT / Feide
Since it is only one parameter added, a simple redirect to the current
URL with that one parameter (SimpleSAML_Auth_State_exceptionId)
removed is probably all I need.
I'll stop whittering to myself now. Any feedback or comments on this
approach much appreciated.
-- Jason
A slightly more robust way to get it is to get it from $errorState
(see my previous email). I believe it will be in:
$errorState['SimpleSAML_Auth_Default.ReturnURL']
We are not trying to completely hide resources behind authentication
here. The login state of the user may provide *additional* resources,
such as a different set of prices on the products, but it is no error
trying to look at those products while not logged in.
I could imaging there are times when trying to access a resource when
not logged in *is* an error, and this is how passive login seems to
have been set up, but my application does not fall into that pattern.
So - is this "error" a SimpleSAMLphp thing, or is it a requirement of
the SAML protocol as a whole? I'm guessing it is just an
implementation of SSP, since the error parameter passed back is very
much specific to SSP.
-- Jason
That error parameter is just simpleSAMLphp's way of passing back errors
to applications. In SAML 2.0, it is represented as an error response
with a "top level" status code of:
urn:oasis:names:tc:SAML:2.0:status:Responder
And a second-level status code:
urn:oasis:names:tc:SAML:2.0:status:NoPassive
E.g. (from a simpleSAMLphp IdP):
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder">
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:NoPassive"/>
</samlp:StatusCode>
<samlp:StatusMessage>Passive authentication not supported.</samlp:StatusMessage>
</samlp:Status>
We parse that error into a SimpleSAML_Error_NoPassive error, and then
pass it off through the error-handling path. If no error handler is
defined, it will be displayed to the user.
$url = $errorState['SimpleSAML_Auth_Default.ReturnURL'];
Thanks. This should work as a solution. It works nicely with my test
pages, though the address bar does flash the redirects up briefly.
Since it will only be invoked once when switching between federation
sites, and only then if the destination site is not aware of the user
logged in locally, this will not be a problem.
Like all things SSP - the solutions generally come down in the end to
just a few choice lines of code, with the hard bit finding out what
those lines are.
-- Jason
I suspect there are more serious error types that need to be caught
anyway, so the solution you have given me (which works more-or-less as
you have posted it) is the way to go. It was not until I dumped out
the contents of the error object that I realised just how much data
has been exchanged between my app and the IdP and stored in the
session. There is a lot going on behind the scenes that I have no
inkling of ;-)
To be fair - a lot of that data is likely to be locally generated in
order to keep track of various parts of the login, how it should be
completed and that sort of stuff :)
What you really want is special handling of the NoPassive error. I
don't think there is any other SAML 2.0 error that can be ignored. Even
the NoPassive error cannot be ignored completely - just proceeding as
normal can easily put the user into a redirect loop. (Unless the
developer takes care to always send the user to a different page than
the one they start NoPassive authentication from, which isn't
necessarily true.)