From bbc9df788e9c365e50b21b40b2eb084670cdabcb Mon Sep 17 00:00:00 2001 From: Art Rhyno Date: Fri, 8 Mar 2013 07:55:06 -0500 Subject: [PATCH] Fix CAS to handle dynamic auth links CAS uses a "service" URL to redirect a user back to where an application wants them to go if authentication is passed. This works well for simple URLs but becomes problematic for complex URLs, which can get mangled or, worse, truncated. This doesn't seem to be unique to Windsor's implmentation of CAS. I tried a few tricks to encode the URLs in strange ways to get the same URL back from CAS, but I think a better approach is to stuff the URL into a cookie, and invoke when the request comes back from CAS. Any other approach seems to result in horrid URLs and there is always the chance that some character will break the scheme. One flaw in my approach is that if a TPAC user selects "email" or "place hold" and invokes the logon screen, the cookie gets set for the "redirect" URL. If, for some reason, a user decides to do another search and chooses to log in to their account from a different screen, the CAS URL can be invoked. This would only happen for CAS, and the cookie itself is only set for 10 minutes, so I don't think this is a major concession. I also try to invalidate the cookie wherever it is possible to know that the authentication has not been invoked. The assumption is that there is a CAS link added to the login form (login/form.tt2), for example: [% l('Log in to Your Account (UWind ID)') %] I had become so used to testing CAS by logging in first, that I totally missed the links that support authentication at the time of need, e.g. the "email" or "place hold" links that are displayed prior to authentication. Hopefully, this branch will address what is probably a common scenario. Signed-off-by: Art Rhyno --- .../src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm index 9e30cfd90c..b38a9a8d28 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm @@ -29,6 +29,7 @@ my $U = 'OpenILS::Application::AppUtils'; use constant COOKIE_SES => 'ses'; use constant COOKIE_LOGGEDIN => 'eg_loggedin'; use constant COOKIE_LOGGEDIN_CAS => 'eg_CAS'; +use constant COOKIE_URL_CAS => 'eg_CAS_URL'; use constant COOKIE_PHYSICAL_LOC => 'eg_physical_loc'; use constant COOKIE_SSS_EXPAND => 'eg_sss_expand'; @@ -360,6 +361,10 @@ sub load_login { my $org_unit = $ctx->{physical_loc} || $ctx->{aou_tree}->()->id; my $persist = $cgi->param('persist'); my $ticket = $cgi->param('ticket'); + my $cas_redirect_to = $cgi->param('redirect_to'); + if ($cgi->cookie(COOKIE_URL_CAS)) { + $cas_redirect_to = $cgi->cookie(COOKIE_URL_CAS); + } my $cas_flag = '0'; # initial log form only @@ -368,7 +373,28 @@ sub load_login { # values for the other checks $username = '_CAS_'; $password = '_CAS_'; + } + + my $login_page = sprintf('%s://%s%s/login',($self->ctx->{is_staff} ? 'oils' : 'https'), $self->ctx->{hostname}, $self->ctx->{opac_root}); + + # CAS does not handle complex URLs, so we put the URL in a cookie + if (!$cgi->cookie(COOKIE_URL_CAS) && $cas_redirect_to && !$username && !$password) { + return $self->generic_redirect( + "$login_page?redirect_to=$cas_redirect_to", + [ + # contains the service url for CAS + $cgi->cookie( + -name => COOKIE_URL_CAS, + -path => '/', + -secure => 0, + -value => $cas_redirect_to, + -expires => '+10m' + ) + ] + ); + } + return Apache2::Const::OK unless $username and $password; # Should we append an email hostname to the username? @@ -420,6 +446,9 @@ sub load_login { if ($ticket) { $args->{ticket} = $ticket; $cas_flag = '1'; + } else { + # zap CAS redirect if not CAS request + $cas_redirect_to = undef; } $response = $U->simplereq( 'open-ils.auth_proxy', @@ -442,6 +471,7 @@ sub load_login { my $login_cookie_expires = ($persist) ? CORE::time + $response->{payload}->{authtime} : undef; return $self->generic_redirect( + $cas_redirect_to || $cgi->param('redirect_to') || $acct, [ # contains the actual auth token and should be sent only over https @@ -461,6 +491,14 @@ sub load_login { -value => '1', -expires => $login_cookie_expires ), + # invalidate CAS url since it is only needed at point of authentication + # if it is used, have it go to login page + $cgi->cookie( + -name => COOKIE_URL_CAS, + -path => '/', + -value => $login_page, + -expires => '-1h' + ), # contains only a hint that we are using CAS $cgi->cookie( -name => COOKIE_LOGGEDIN_CAS, @@ -480,6 +518,9 @@ sub load_logout { my $self = shift; my $redirect_to = shift || $self->cgi->param('redirect_to'); + my $login_page = sprintf('%s://%s%s/login',($self->ctx->{is_staff} ? 'oils' : 'https'), + $self->ctx->{hostname}, $self->ctx->{opac_root}); + # If the user was adding anyting to an anonymous cache # while logged in, go ahead and clear it out. $self->clear_anon_cache; @@ -501,6 +542,12 @@ sub load_logout { -expires => '-1h' ), $self->cgi->cookie( + -name => COOKIE_URL_CAS, + -path => '/', + -value => $login_page, + -expires => '-1h' + ), + $self->cgi->cookie( -name => COOKIE_LOGGEDIN_CAS, -path => '/', -value => '', -- 2.11.0