Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proxy requires a seperate URL for the pgtUrl #19

Closed
ravids opened this issue Jan 12, 2012 · 23 comments
Closed

Proxy requires a seperate URL for the pgtUrl #19

ravids opened this issue Jan 12, 2012 · 23 comments

Comments

@ravids
Copy link

ravids commented Jan 12, 2012

We tried to use the following method in CAS-1.2.2 as well in the commit number in the latest github code (commit number : SHA: ec3e935)


In this case, we had the above code in client.example.com/proxy.php and the CAS server is cas.example.com. By default phpCAS constructs client.example.com/proxy.php as the pgtUrl. The process failed when the CAS server tried to validate the pgtUrl.

We finally got it working by giving a different pgtUrl, client.example.com/proxycallback.php, and using the phpCAS::setFixedCallbackURL method.

We also debugged why phpCAS default behavior does not work. Following is the apache log extract from the server that is serving client.example.com, with the working solution using a different pgtUrl.


192.168.1.21 - - [11/Jan/2012:14:10:12 -0500] "GET /proxy.php HTTP/1.1" 302 476
"-" "Mozilla/5.0 (Windows NT 5.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1"
192.168.1.247 - - [11/Jan/2012:14:10:37 -0500] "GET /proxycallback.php HTTP/1.1" 200 581
"-" "Java/1.6.0_24"
192.168.1.247 - - [11/Jan/2012:14:10:37 -0500] "GET /proxycallback.php?pgtIou=PGTIOU-22-ndDLo0Zs4JIeeDFrXNK9-cas&pgtId=TGT-60-BOmnxU0OvQkcyexOMBvbXYdOcZwiapSERiAjvDMw4nwncOxP75-cas HTTP/1.1" 200 294 "-" "Java/1.6.0_24"
192.168.1.21 - - [11/Jan/2012:14:10:36 -0500] "GET /proxy.php?ticket=ST-56-zDai54pHmOoZN9IdDdZW-cas HTTP/1.1" 200 229 "https://cas.example.com:8443/cas/login?service=https%3A%2F%2Fclient.example.com%2Fproxy.php" "Mozilla/5.0 (Windows NT 5.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1

The first call is where my browser tries to access the proxy.php. It redirects me to the CAS server, where I provide my login credentials. Then CAS server tries to validate the pgtUrl. This is where the bug is. If CAS server calls back proxy.php as in the default behavior of phpCAS, phpCAS would redirect back to the CAS server to login. why? because phpCAS isAuthenticated() method return false. Since phpCAS has not received any service ticket back from the CAS server isAuthenticated() returning false is justifiable. As I see there are two solutions

  1. Use a different fixed pgtUrl (proxycallback.php) as we did. The script at this URL retrieved the pgtId and pgtIou and saved to the pgt storage. Later when CAS calls the calling url (proxy.php) with the pgtIou , the pgtId is present in the pgt storage for the next steps.

  2. Modify phpCAS to return a 200 response, bypassing every other code when the CAS server simply calls it to validate the pgtUrl.

May be there is a configuration we are missing. But we have phpCAS working using both the above two solutions. Please let us know if it is just a missing configuration or what we are reporting is a known issue.

@adamfranco
Copy link
Contributor

Hello Ravindra,

As I understand it, here is what should be happening when a request comes in with a PGTIOU:

  1. In CAS_Client::__construct() (line 861) if in proxy mode, the 'callback mode' is set based on there being both a pgtIou and a pgtId in the request.

    if ( $this->isProxy() ) {
    $this->_setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
    }

  2. When CAS_Client::isAuthenticated() is called and the client is now in 'callback mode', CAS_Client::_callback() should be called to store the PGTIOU and exit:

    if ( $this->_isCallbackMode()) {
    $this->_callback();
    }

I'm not sure what is going on that would prevent your initial proxy.php script from not working while a different script name would work. Here are a couple of common configuration issues that might be worth checking:

  • Is your host available under SSL? To create the default callback URL phpCAS uses the current host and path, but with https:// instead of http://. If you are specifying a different hostname for the fixed callback URL, that could be what is allowing the manual configuration to work.
  • Similarly to the first issue, if you have different hostnames to the machine, is the SSL cert used by the auto-built path trusted by your CAS server?

If you are still stuck try using phpCAS::setDebug('/tmp/phpcas.log'); to capture a single authentication sequence and post it here. The phpCAS logging is pretty detailed and should help to give at least an idea of what is going on.

@jfritschi
Copy link
Contributor

Are you using the examples we are supplying with phpCAS? If not please share the code with us. Please post the debug log as Adam has already suggested. This is pretty much the only way we might be able to track this issue down and may even be able to reproduce the error on our end.

Have you tried running the examples we ship with phpCAS?

@ravids
Copy link
Author

ravids commented Jan 12, 2012

Thanks to both of you for the quick response. I think I may not have explained my issue correctly.

phpCAS works properly when it receives the PGTIOU. But it does not get to that step under the default scenario. Earlier I posted the apache log for the custom solution. Following is the apache log for the default phpCAS behaviour .

192.168.1.21 - - [12/Jan/2012:15:06:21 -0500] "GET /proxy.php HTTP/1.1" 302 476
"-" "Mozilla/5.0 (Windows NT 5.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1"
192.168.1.247 - - [12/Jan/2012:15:06:21 -0500] "GET /proxy.php HTTP/1.1" 302 476
 "-" "Java/1.6.0_24"
192.168.1.21 - - [12/Jan/2012:15:06:21 -0500] "GET /proxy.php?ticket=ST-211-v7zbnaeVfEyePADTWAg5-cas HTTP/1.1" 200 1240 "-" "Mozilla/5.0 (Windows NT 5.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1" 

The culprit is the second call which is

192.168.1.247 - - [12/Jan/2012:15:06:21 -0500] "GET /proxy.php HTTP/1.1" 302 476
 "-" "Java/1.6.0_24"

This call is made by the CAS server to validate that the proxy exists and is having a valid SSL certificate. Instead of sending a 200 response back to the CAS server, phpCAS does another redirection (note 302) to CAS server.

The issue is not with SSL certificates. Because when I patched the phpCAS code to send a 200 response to this CAS validation request, everything works fine. Therefore, it is at the PHP level.

Following is an extract from http://www.jasig.org/cas/protocol

The proxy callback mechanism works as follows:
    The service that is requesting a proxy-granting ticket specifies upon initial service ticket or proxy ticket validation the HTTP request parameter "pgtUrl" to /serviceValidate (or /proxyValidate). This is a callback URL of the service to which CAS will connect to verify the service's identity. This URL MUST be HTTPS, and CAS MUST verify both that the SSL certificate is valid and that its name matches that of the service.

We also ran the step by step CAS instructions at https://wiki.jasig.org/display/CAS/Proxy+CAS+Walkthrough, and again when the CAS server tried to do a simple GET request to the pgtUrl, phpCAS did the redirect, and the process fails.

The code that does not work is the example that is supplied with phpCAS. I will trim the real server names from the phpCAS log and attach. We are using CAS 2 protocol with a CAS 3.4.11 server.

@ravids ravids closed this as completed Jan 12, 2012
@ravids ravids reopened this Jan 12, 2012
@ravids
Copy link
Author

ravids commented Jan 12, 2012

I apologize, by mistake I closed the issue. Reopening now.

@ravids
Copy link
Author

ravids commented Jan 12, 2012

Please find the phpCAS debug log below. Thank for the support and your effort in developing and maintaining a php library for CAS.

5075 .START phpCAS-1.2.2+ ****************** [CAS.php:449]
5075 .=> phpCAS::proxy('2.0', 'cas.example.com', 8443, 'cas/') [proxy.php:18]
5075 .|    => CAS_Client::__construct('2.0', true, 'cas.example.com', 8443, 'cas/', true) [CAS.php:398]
5075 .|    |    Starting a new session [Client.php:797]
5075 .|    <= ''
5075 .<= ''
5075 .=> phpCAS::setCasServerCACert('/etc/httpd/conf.d/ssl.crt/STAR_example_com.crt') [proxy.php:22]
5075 .<= ''
5075 .=> phpCAS::setPGTStorageFile('/var/lib/php/session') [proxy.php:26]
5075 .|    => CAS_PGTStorage_File::__construct(CAS_Client, '/var/lib/php/session') [Client.php:2219]
5075 .|    |    => CAS_PGTStorage_AbstractStorage::__construct(CAS_Client) [File.php:119]
5075 .|    |    <= ''
5075 .|    <= ''
5075 .<= ''
5075 .=> phpCAS::forceAuthentication() [proxy.php:28]
5075 .|    => CAS_Client::forceAuthentication() [CAS.php:1088]
5075 .|    |    => CAS_Client::isAuthenticated() [Client.php:1088]
5075 .|    |    |    => CAS_Client::_wasPreviouslyAuthenticated() [Client.php:1195]
5075 .|    |    |    |    neither user not PGT found [Client.php:1361]
5075 .|    |    |    <= false
5075 .|    |    |    no ticket found [Client.php:1264]
5075 .|    |    <= false
5075 .|    |    => CAS_Client::redirectToCas(false) [Client.php:1097]
5075 .|    |    |    => CAS_Client::getServerLoginURL(false, false) [Client.php:1402]
5075 .|    |    |    |    => CAS_Client::getURL() [Client.php:326]
5075 .|    |    |    |    |    Final URI: https://client.example.com/proxy.php [Client.php:3064]
5075 .|    |    |    |    <= 'https://client.example.com/proxy.php'
5075 .|    |    |    <= 'https://cas.example.com:8443/cas/login?service=https%3A%2F%2Fclient.example.com%2Fproxy.php'
5075 .|    |    |    Redirect to : https://cas.example.com:8443/cas/login?service=https%3A%2F%2Fclient.example.com%2Fproxy.php [Client.php:1408]
5075 .|    |    |    exit()
5075 .|    |    |    -
5075 .|    |    -
5075 .|    -
87E1 .START phpCAS-1.2.2+ ****************** [CAS.php:449]
87E1 .=> phpCAS::proxy('2.0', 'cas.example.com', 8443, 'cas/') [proxy.php:18]
87E1 .|    => CAS_Client::__construct('2.0', true, 'cas.example.com', 8443, 'cas/', true) [CAS.php:398]
87E1 .|    |    Starting a new session [Client.php:797]
87E1 .|    |    Ticket 'ST-211-v7zbnaeVfEyePADTWAg5-cas' found [Client.php:875]
87E1 .|    <= ''
87E1 .<= ''
87E1 .=> phpCAS::setCasServerCACert('/etc/httpd/conf.d/ssl.crt/STAR_example_com.crt') [proxy.php:22]
87E1 .<= ''
87E1 .=> phpCAS::setPGTStorageFile('/var/lib/php/session') [proxy.php:26]
87E1 .|    => CAS_PGTStorage_File::__construct(CAS_Client, '/var/lib/php/session') [Client.php:2219]
87E1 .|    |    => CAS_PGTStorage_AbstractStorage::__construct(CAS_Client) [File.php:119]
87E1 .|    |    <= ''
87E1 .|    <= ''
87E1 .<= ''
87E1 .=> phpCAS::forceAuthentication() [proxy.php:28]
87E1 .|    => CAS_Client::forceAuthentication() [CAS.php:1088]
87E1 .|    |    => CAS_Client::isAuthenticated() [Client.php:1088]
87E1 .|    |    |    => CAS_Client::_wasPreviouslyAuthenticated() [Client.php:1195]
87E1 .|    |    |    |    neither user not PGT found [Client.php:1361]
87E1 .|    |    |    <= false
87E1 .|    |    |    CAS 2.0 ticket `ST-211-v7zbnaeVfEyePADTWAg5-cas' is present [Client.php:1229]
87E1 .|    |    |    => CAS_Client::validateCAS20('', NULL, NULL) [Client.php:1230]
87E1 .|    |    |    |     [Client.php:2740]
87E1 .|    |    |    |    => CAS_Client::getServerServiceValidateURL() [Client.php:2746]
87E1 .|    |    |    |    |    => CAS_Client::getURL() [Client.php:415]
87E1 .|    |    |    |    |    |    Final URI: https://client.example.com/proxy.php [Client.php:3064]
87E1 .|    |    |    |    |    <= 'https://client.example.com/proxy.php'
87E1 .|    |    |    |    <= 'https://cas.example.com:8443/cas/serviceValidate?service=https%3A%2F%2Fclient.example.com%2Fproxy.php'
87E1 .|    |    |    |    => CAS_Request_CurlRequest::sendRequest() [AbstractRequest.php:218]
87E1 .|    |    |    |    |    CURL: Set CURLOPT_CAINFO [CurlRequest.php:123]
0CA7 .START phpCAS-1.2.2+ ****************** [CAS.php:449]
0CA7 .=> phpCAS::proxy('2.0', 'cas.example.com', 8443, 'cas/') [proxy.php:18]
0CA7 .|    => CAS_Client::__construct('2.0', true, 'cas.example.com', 8443, 'cas/', true) [CAS.php:398]
0CA7 .|    |    Starting a new session [Client.php:797]
0CA7 .|    <= ''
0CA7 .<= ''
0CA7 .=> phpCAS::setCasServerCACert('/etc/httpd/conf.d/ssl.crt/STAR_example_com.crt') [proxy.php:22]
0CA7 .<= ''
0CA7 .=> phpCAS::setPGTStorageFile('/var/lib/php/session') [proxy.php:26]
0CA7 .|    => CAS_PGTStorage_File::__construct(CAS_Client, '/var/lib/php/session') [Client.php:2219]
0CA7 .|    |    => CAS_PGTStorage_AbstractStorage::__construct(CAS_Client) [File.php:119]
0CA7 .|    |    <= ''
0CA7 .|    <= ''
0CA7 .<= ''
0CA7 .=> phpCAS::forceAuthentication() [proxy.php:28]
0CA7 .|    => CAS_Client::forceAuthentication() [CAS.php:1088]
0CA7 .|    |    => CAS_Client::isAuthenticated() [Client.php:1088]
0CA7 .|    |    |    => CAS_Client::_wasPreviouslyAuthenticated() [Client.php:1195]
0CA7 .|    |    |    |    neither user not PGT found [Client.php:1361]
0CA7 .|    |    |    <= false
0CA7 .|    |    |    no ticket found [Client.php:1264]
0CA7 .|    |    <= false
0CA7 .|    |    => CAS_Client::redirectToCas(false) [Client.php:1097]
0CA7 .|    |    |    => CAS_Client::getServerLoginURL(false, false) [Client.php:1402]
0CA7 .|    |    |    |    => CAS_Client::getURL() [Client.php:326]
0CA7 .|    |    |    |    |    Final URI: https://client.example.com/proxy.php [Client.php:3064]
0CA7 .|    |    |    |    <= 'https://client.example.com/proxy.php'
0CA7 .|    |    |    <= 'https://cas.example.com:8443/cas/login?service=https%3A%2F%2Fclient.example.com%2Fproxy.php'
0CA7 .|    |    |    Redirect to : https://cas.example.com:8443/cas/login?service=https%3A%2F%2Fclient.example.com%2Fproxy.php [Client.php:1408]
0CA7 .|    |    |    exit()
0CA7 .|    |    |    -
0CA7 .|    |    -
0CA7 .|    -
87E1 .|    |    |    |    |    Response Body: 
87E1 .|    |    |    |    |    <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
87E1 .|    |    |    |    |     <cas:authenticationSuccess>
87E1 .|    |    |    |    |         <cas:user>admin</cas:user>
87E1 .|    |    |    |    |    
87E1 .|    |    |    |    |    
87E1 .|    |    |    |    |     </cas:authenticationSuccess>
87E1 .|    |    |    |    |    </cas:serviceResponse>
87E1 .|    |    |    |    |     [CurlRequest.php:82]
87E1 .|    |    |    |    <= true
87E1 .|    |    |    |    => CAS_Client::_readExtraAttributesCas20(DOMNodeList) [Client.php:2806]
87E1 .|    |    |    |    |    Testing for rubycas style attributes [Client.php:2916]
87E1 .|    |    |    |    <= ''
87E1 .|    |    |    |    Storing Proxy List [Client.php:2815]
87E1 .|    |    |    |    => CAS_ProxyChain_AllowedList::isProxyListAllowed(array ()) [Client.php:2818]
87E1 .|    |    |    |    |    No proxies were found in the response [AllowedList.php:81]
87E1 .|    |    |    |    <= true
87E1 .|    |    |    |    => CAS_Client::_renameSession('ST-211-v7zbnaeVfEyePADTWAg5-cas') [Client.php:2849]
87E1 .|    |    |    |    |    Session ID: ST-211-v7zbnaeVfEyePADTWAg5-cas [Client.php:3167]
87E1 .|    |    |    |    |    Restoring old session vars [Client.php:3170]
87E1 .|    |    |    |    <= ''
87E1 .|    |    |    <= true
87E1 .|    |    |    CAS 2.0 ticket `ST-211-v7zbnaeVfEyePADTWAg5-cas' was validated [Client.php:1231]
87E1 .|    |    |    => CAS_Client::_validatePGT('https://cas.example.com:8443/cas/serviceValidate?service=https%3A%2F%2Fclient.example.com%2Fproxy.php&ticket=ST-211-v7zbnaeVfEyePADTWAg5-cas&pgtUrl=https%3A%2F%2Fclient.example.com%2Fproxy.php', '<cas:serviceResponse xmlns:cas=\'http://www.yale.edu/tp/cas\'>    <cas:authenticationSuccess>     <cas:user>admin</cas:user>  </cas:authenticationSuccess></cas:serviceResponse>', DOMElement) [Client.php:1233]
87E1 .|    |    |    |    <proxyGrantingTicket> not found [Client.php:2242]
87E1 .|    |    |    |    => CAS_AuthenticationException::__construct(CAS_Client, 'Ticket validated but no PGT Iou transmitted', 'https://cas.example.com:8443/cas/serviceValidate?service=https%3A%2F%2Fclient.example.com%2Fproxy.php&ticket=ST-211-v7zbnaeVfEyePADTWAg5-cas&pgtUrl=https%3A%2F%2Fclient.example.com%2Fproxy.php', false, false, '<cas:serviceResponse xmlns:cas=\'http://www.yale.edu/tp/cas\'>  <cas:authenticationSuccess>     <cas:user>admin</cas:user>  </cas:authenticationSuccess></cas:serviceResponse>') [Client.php:2248]
87E1 .|    |    |    |    |    => CAS_Client::getURL() [AuthenticationException.php:76]
87E1 .|    |    |    |    |    <= 'https://client.example.com/proxy.php'
87E1 .|    |    |    |    |    CAS URL: https://cas.example.com:8443/cas/serviceValidate?service=https%3A%2F%2Fclient.example.com%2Fproxy.php&ticket=ST-211-v7zbnaeVfEyePADTWAg5-cas&pgtUrl=https%3A%2F%2Fclient.example.com%2Fproxy.php [AuthenticationException.php:79]
87E1 .|    |    |    |    |    Authentication failure: Ticket validated but no PGT Iou transmitted [AuthenticationException.php:80]
87E1 .|    |    |    |    |    Reason: no CAS error [AuthenticationException.php:93]
87E1 .|    |    |    |    |    CAS response: <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
87E1 .|    |    |    |    |     <cas:authenticationSuccess>
87E1 .|    |    |    |    |         <cas:user>admin</cas:user>
87E1 .|    |    |    |    |    
87E1 .|    |    |    |    |    
87E1 .|    |    |    |    |     </cas:authenticationSuccess>
87E1 .|    |    |    |    |    </cas:serviceResponse> [AuthenticationException.php:99]
87E1 .|    |    |    |    |    exit()
87E1 .|    |    |    |    |    -
87E1 .|    |    |    |    -
87E1 .|    |    |    -
87E1 .|    |    -
87E1 .|    -

@jfritschi
Copy link
Contributor

I think a wrong decision is taken in Client.php line 2743. A proxy() does not have to have an allow proxy chain to choose the proxyValidate Url. I think is should be something like (proxy || (service && begingProxiedAllowed)).

Will investigate further tomorrow unless someone else figures it out.

@jfritschi
Copy link
Contributor

Mmh somehow i can't reproduce your problem and my last post seems to be wrong.

I have commited a small patch to give us a bit more debug output in one of the functions that might be relevant. Please try the lastest version to get me a bit more info. In your debug.log im definately missing a callback from the server and that is very strange.

@jfritschi
Copy link
Contributor

After having another quick look at your logs:

In the server response (Response Body) you "should" also get a:
<cas:proxyGrantingTicket>PGTIOU-39-LrndNMap7ZxHOP3DHgRE-cas</cas:proxyGrantingTicket>

At the same time the callback should come back from the cas server to the proxy and deliver a matching pair of PGTIOU and PGT. Since both is not happening the question is really why this call is redirected according to your log. For this we definately need your code (send by mail if you want) or some info what you are using. In the current state i can't reproduce.
Please also have a look at the cas server log for errors.

@ravids
Copy link
Author

ravids commented Jan 13, 2012

I will post the phpCAS code usage we have. It is not much different to the example.

However, I think I did not get my point through. The callback which Joachim investigated works fine if we get to that step. CAS server performs two calls to the pgtUrl

  1. To validate the pgtUrl
    2.. If the validation in step 1 is successful, then only will CAS server issue the PGTIOU and the PGT. But the first call to validate the pgtUrl fails, because phpCAS redirects back to the CAS server.

In terms of CAS server, when I inspect the catalina.out the error is in validating the pgtUrl.

2012-01-13 09:07:23,314 ERROR [org.jasig.cas.web.ServiceValidateController] - <TicketException generating ticket for: [callbackUrl: https://client.example.com/proxy.php]> 

By adding the following few lines of code before we run the phpCAS example code, we managed to have the CAS server issue the PGTIOU and the PGT.

if((!isset($_GET["login"])) &&   (!isset($_GET["pgtIou"])))
{
    echo "done";
    return true;
}

Then through the browser we call https://client.example.com/proxy.php?login=true which results in the following apache log entry.

192.168.1.21 - - [13/Jan/2012:09:20:53 -0500] "GET /proxy.php?login=true HTTP/1.1" 302 491 "-" "Mozilla/5.0 (Windows NT 5.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1"

Then the browser is redirected the CAS server, we enter the user name and password. CAS server validates against the database, then tries to validate the pgtUrl

192.168.1.247 - - [13/Jan/2012:09:21:04 -0500] "GET /proxy.php HTTP/1.1" 200 4 "-" "Java/1.6.0_24"

Because of the if condition we added, we prevent phpCAS from executing, and simply return "done". If we do not have that switch then phpCAS would perform a redirect to CAS server, and CAS server decides that it could not validate the pgtUrl.

Now CAS server is happy that pgtUrl sent a 200 response, it generates the PGT and PGTIOU, and calls back the pgtUrl with those values.

192.168.1.247 - - [13/Jan/2012:09:21:04 -0500] "GET /proxy.php?pgtIou=PGTIOU-3-hXJCIjuXdWoQLJedhZEk-cas&pgtId=TGT-7-zPpWnvwB1L27LPtcxUFZc7FPxR1Y0EXEHYgYjHdCUQy2e9iFVA-cas HTTP/1.1" 200 371 "-" "Java/1.6.0_24"

And then CAS server redirects the browser back to the calling application with the service ticket

192.168.1.21 - - [13/Jan/2012:09:21:03 -0500] "GET /proxy.php?login=true&ticket=ST-5-7V1FVRefbK9acPj14NVG-cas HTTP/1.1" 302 - "https://cas.example.com:8443/cas/login?service=https%3A%2F%2Fclient.example.com%2Fproxy.php%3Flogin%3Dtrue" "Mozilla/5.0 (Windows NT 5.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1" 

What I am trying to say is that, it is the simple GET request to validate the pgtUrl that fails. Everything before and after works, if we get the validation step correct.

May be to clear my point I will ask a question.

What would phpCAS do if CAS server does a simple (without any PGT or PGTIOU) GET request to the pgtUrl?
CAS protocol (at least the CAS server I have) expects a 200 response, when it tries the validate the pgtUrl.

@ravids
Copy link
Author

ravids commented Jan 13, 2012

Following is the code that fails CAS server validation. Thus CAS server does not issue PGT or PGTIOU

<?php
// Example for a proxy with session usage
$path = "/home/example/phpCAS/source/CAS.php";
require_once($path);

// Uncomment to enable debugging
phpCAS::setDebug('log_proxy_ravi.log');

// Initialize phpCAS
phpCAS::proxy('2.0', 'cas.example.com', intval(8443), 'cas/');
$cas_server_ca_cert_path="/etc/httpd/conf.d/ssl.crt/STAR_example_com.crt";
phpCAS::setCasServerCACert($cas_server_ca_cert_path);

phpCAS::setPGTStorageFile(session_save_path());
// force CAS authentication
phpCAS::forceAuthentication();

// at this step, the user has been authenticated by the CAS server
// and the user's login name can be read with phpCAS::getUser().

// moreover, a PGT was retrieved from the CAS server that will
// permit to gain accesses to new services.
$serviceUrl='https://www.example.com/admin/web-service.php';
?>
<html>
<head>
<title>phpCAS proxied proxy example (with sessioning)</title>
<link rel="stylesheet" type='text/css' href='example.css'/>
</head>
<body>
<h1>phpCAS proxied proxy example (with sessioning)</h1>

<p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
<h2>Response from service <?php echo $serviceUrl; ?></h2>
<?php

  flush();
  // call a service and change the color depending on the result
  if ( phpCAS::serviceWeb($serviceUrl,$err_code,$output) ) {
    echo '<div class="success">';
  } else {
    echo '<div class="error">';
  }
  echo $output;
  echo '</div>';
?>
</body>
</html>

@ravids
Copy link
Author

ravids commented Jan 13, 2012

By simply adding

if((!isset($_GET["login"])) &&  (!isset($_GET["pgtIou"])))
{
    echo "done";
    return true;
}

as in the following example, CAS server validates the pgtUrl. Thus CAS serve issues the PGT and PGTIOU.
In this example we try to login at https://client.example.com/proxy.php?login=true

<?php
if((!isset($_GET["login"])) &&   (!isset($_GET["pgtIou"])))
{
    echo "done";
    return true;
}

// Example for a proxy with session usage
$path = "/home/example/phpCAS/source/CAS.php";
require_once($path);

// Uncomment to enable debugging
phpCAS::setDebug('log_proxy_ravi.log');

// Initialize phpCAS
phpCAS::proxy('2.0', 'cas.example.com', intval(8443), 'cas/');
$cas_server_ca_cert_path="/etc/httpd/conf.d/ssl.crt/STAR_example_com.crt";
phpCAS::setCasServerCACert($cas_server_ca_cert_path);

phpCAS::setPGTStorageFile(session_save_path());
// force CAS authentication
phpCAS::forceAuthentication();

// at this step, the user has been authenticated by the CAS server
// and the user's login name can be read with phpCAS::getUser().

// moreover, a PGT was retrieved from the CAS server that will
// permit to gain accesses to new services.
$serviceUrl='https://www.example.com/admin/web-service.php';
?>
<html>
<head>
<title>phpCAS proxied proxy example (with sessioning)</title>
<link rel="stylesheet" type='text/css' href='example.css'/>
</head>
<body>
<h1>phpCAS proxied proxy example (with sessioning)</h1>

<p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
<h2>Response from service <?php echo $serviceUrl; ?></h2>
<?php

  flush();
  // call a service and change the color depending on the result
  if ( phpCAS::serviceWeb($serviceUrl,$err_code,$output) ) {
    echo '<div class="success">';
  } else {
    echo '<div class="error">';
  }
  echo $output;
  echo '</div>';
?>
</body>
</html>

@jfritschi
Copy link
Contributor

Sorry but somehow you server behaviour is different than mine. My CAS server (jasig 3.4.11 i believe) does deliver a PGT even after a 302 "error" (see a log one of my tests). What version and server are you running? Somehow it also does not fit your described situation when hardcoding the callback url works. phpCAS will always deliver a 302 to any anonymous request.

127.0.0.1 - - [13/Jan/2012:17:01:02 +0100] "GET /phpcas/example_service_that_proxies.php HTTP/1.1" 302 4291 "-" "Java/1.6.0_18" 127.0.0.1 - - [13/Jan/2012:17:01:02 +0100] "GET /phpcas/example_service_that_proxies.php?pgtIou=PGTIOU-40-pb7iJIfQYzcHHB5GAhri-cas&pgtId=TGT-57-LQlm4ewfSuudcI4nj2DNLwGAxwNd2wCCgsPbkNDKbIgSGwN1mz-cas HTTP/1.1" 200 1113 "-" "Java/1.6.0_18"

The first call a is a pure dummy call to validate your proxy ssl cert against the trusted certstore on the cas server side. If it fails a valdiation (trust, dns or ip, validity) no PGT will be transmitted. Usually this is the problem when a PGT is not transmitted in the callback and no PGTIOU is added to the server answer.

The log excerpt from the cas server however suggest some other validation failure on the cas server side. No idea what it could be but a quick look at the cas server source indicates to me it could be something is not correct with your registered services? Is your service allowed for proxy? Is there maybe an error in the ant regexp? Are there any other messages in the cas server log around this entry?

Please also refrain from cutting your logs to bits and pieces. If we can't reproduce errors on our side the only way to figure stuff out is to see full logs/traces of the problems in question and not by you selectively sharing single lines of info you feel relevant and describing the situation. Especially proxy mode is very tricky business and not something where guessing on our part really helpfull.

Can you please show a full debug scenario of a single proxy test (apache access and error log, cas log, phpcas debug log). That might give us some more info to work with.

@ravids
Copy link
Author

ravids commented Jan 13, 2012

Thanks a lot for the detailed response. So there is a difference in how your CAS server behaves and mine. Mine does not like the 302, and yours works fine. I am now going to look at CAS server configuration again. Meanwhile I will post all the logs as you mentioned.

@ravids
Copy link
Author

ravids commented Jan 16, 2012

I apologize for the delay in posting the log files. First the phpCAS log

179E .START phpCAS-1.2.2+ ****************** [CAS.php:449]
179E .=> phpCAS::proxy('2.0', 'cas.example.com', 8443, 'cas/') [proxy.php:10]
179E .|    => CAS_Client::__construct('2.0', true, 'cas.example.com', 8443, 'cas/', true) [CAS.php:398]
179E .|    |    Starting a new session [Client.php:797]
179E .|    <= ''
179E .<= ''
179E .=> phpCAS::setCasServerCACert('/etc/httpd/conf.d/ssl.crt/STAR_example_com.crt') [proxy.php:12]
179E .<= ''
179E .=> phpCAS::setPGTStorageFile('/var/lib/php/session') [proxy.php:14]
179E .|    => CAS_PGTStorage_File::__construct(CAS_Client, '/var/lib/php/session') [Client.php:2219]
179E .|    |    => CAS_PGTStorage_AbstractStorage::__construct(CAS_Client) [File.php:119]
179E .|    |    <= ''
179E .|    <= ''
179E .<= ''
179E .=> phpCAS::forceAuthentication() [proxy.php:16]
179E .|    => CAS_Client::forceAuthentication() [CAS.php:1088]
179E .|    |    => CAS_Client::isAuthenticated() [Client.php:1088]
179E .|    |    |    => CAS_Client::_wasPreviouslyAuthenticated() [Client.php:1195]
179E .|    |    |    |    neither user not PGT found [Client.php:1361]
179E .|    |    |    <= false
179E .|    |    |    no ticket found [Client.php:1264]
179E .|    |    <= false
179E .|    |    => CAS_Client::redirectToCas(false) [Client.php:1097]
179E .|    |    |    => CAS_Client::getServerLoginURL(false, false) [Client.php:1402]
179E .|    |    |    |    => CAS_Client::getURL() [Client.php:326]
179E .|    |    |    |    |    Final URI: https://client.example.com/proxy.php [Client.php:3064]
179E .|    |    |    |    <= 'https://client.example.com/proxy.php'
179E .|    |    |    <= 'https://cas.example.com:8443/cas/login?service=https%3A%2F%2Fclient.example.com%2Fproxy.php'
179E .|    |    |    Redirect to : https://cas.example.com:8443/cas/login?service=https%3A%2F%2Fclient.example.com%2Fproxy.php [Client.php:1408]
179E .|    |    |    exit()
179E .|    |    |    -
179E .|    |    -
179E .|    -
36AE .START phpCAS-1.2.2+ ****************** [CAS.php:449]
36AE .=> phpCAS::proxy('2.0', 'cas.example.com', 8443, 'cas/') [proxy.php:10]
36AE .|    => CAS_Client::__construct('2.0', true, 'cas.example.com', 8443, 'cas/', true) [CAS.php:398]
36AE .|    |    Starting a new session [Client.php:797]
36AE .|    |    Ticket 'ST-31-36DU9hMoxL4yTCHUeVI3-cas' found [Client.php:875]
36AE .|    <= ''
36AE .<= ''
36AE .=> phpCAS::setCasServerCACert('/etc/httpd/conf.d/ssl.crt/STAR_example_com.crt') [proxy.php:12]
36AE .<= ''
36AE .=> phpCAS::setPGTStorageFile('/var/lib/php/session') [proxy.php:14]
36AE .|    => CAS_PGTStorage_File::__construct(CAS_Client, '/var/lib/php/session') [Client.php:2219]
36AE .|    |    => CAS_PGTStorage_AbstractStorage::__construct(CAS_Client) [File.php:119]
36AE .|    |    <= ''
36AE .|    <= ''
36AE .<= ''
36AE .=> phpCAS::forceAuthentication() [proxy.php:16]
36AE .|    => CAS_Client::forceAuthentication() [CAS.php:1088]
36AE .|    |    => CAS_Client::isAuthenticated() [Client.php:1088]
36AE .|    |    |    => CAS_Client::_wasPreviouslyAuthenticated() [Client.php:1195]
36AE .|    |    |    |    neither user not PGT found [Client.php:1361]
36AE .|    |    |    <= false
36AE .|    |    |    CAS 2.0 ticket `ST-31-36DU9hMoxL4yTCHUeVI3-cas' is present [Client.php:1229]
36AE .|    |    |    => CAS_Client::validateCAS20('', NULL, NULL) [Client.php:1230]
36AE .|    |    |    |     [Client.php:2740]
36AE .|    |    |    |    => CAS_Client::getServerServiceValidateURL() [Client.php:2746]
36AE .|    |    |    |    |    => CAS_Client::getURL() [Client.php:415]
36AE .|    |    |    |    |    |    Final URI: https://client.example.com/proxy.php [Client.php:3064]
36AE .|    |    |    |    |    <= 'https://client.example.com/proxy.php'
36AE .|    |    |    |    <= 'https://cas.example.com:8443/cas/serviceValidate?service=https%3A%2F%2Fclient.example.com%2Fproxy.php'
36AE .|    |    |    |    => CAS_Request_CurlRequest::sendRequest() [AbstractRequest.php:218]
36AE .|    |    |    |    |    CURL: Set CURLOPT_CAINFO [CurlRequest.php:123]
AA77 .START phpCAS-1.2.2+ ****************** [CAS.php:449]
AA77 .=> phpCAS::proxy('2.0', 'cas.example.com', 8443, 'cas/') [proxy.php:10]
AA77 .|    => CAS_Client::__construct('2.0', true, 'cas.example.com', 8443, 'cas/', true) [CAS.php:398]
AA77 .|    |    Starting a new session [Client.php:797]
AA77 .|    <= ''
AA77 .<= ''
AA77 .=> phpCAS::setCasServerCACert('/etc/httpd/conf.d/ssl.crt/STAR_example_com.crt') [proxy.php:12]
AA77 .<= ''
AA77 .=> phpCAS::setPGTStorageFile('/var/lib/php/session') [proxy.php:14]
AA77 .|    => CAS_PGTStorage_File::__construct(CAS_Client, '/var/lib/php/session') [Client.php:2219]
AA77 .|    |    => CAS_PGTStorage_AbstractStorage::__construct(CAS_Client) [File.php:119]
AA77 .|    |    <= ''
AA77 .|    <= ''
AA77 .<= ''
AA77 .=> phpCAS::forceAuthentication() [proxy.php:16]
AA77 .|    => CAS_Client::forceAuthentication() [CAS.php:1088]
AA77 .|    |    => CAS_Client::isAuthenticated() [Client.php:1088]
AA77 .|    |    |    => CAS_Client::_wasPreviouslyAuthenticated() [Client.php:1195]
AA77 .|    |    |    |    neither user not PGT found [Client.php:1361]
AA77 .|    |    |    <= false
AA77 .|    |    |    no ticket found [Client.php:1264]
AA77 .|    |    <= false
AA77 .|    |    => CAS_Client::redirectToCas(false) [Client.php:1097]
AA77 .|    |    |    => CAS_Client::getServerLoginURL(false, false) [Client.php:1402]
AA77 .|    |    |    |    => CAS_Client::getURL() [Client.php:326]
AA77 .|    |    |    |    |    Final URI: https://client.example.com/proxy.php [Client.php:3064]
AA77 .|    |    |    |    <= 'https://client.example.com/proxy.php'
AA77 .|    |    |    <= 'https://cas.example.com:8443/cas/login?service=https%3A%2F%2Fclient.example.com%2Fproxy.php'
AA77 .|    |    |    Redirect to : https://cas.example.com:8443/cas/login?service=https%3A%2F%2Fclient.example.com%2Fproxy.php [Client.php:1408]
AA77 .|    |    |    exit()
AA77 .|    |    |    -
AA77 .|    |    -
AA77 .|    -
36AE .|    |    |    |    |    Response Body: 
36AE .|    |    |    |    |    <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
36AE .|    |    |    |    |     <cas:authenticationSuccess>
36AE .|    |    |    |    |         <cas:user>admin</cas:user>
36AE .|    |    |    |    |    
36AE .|    |    |    |    |    
36AE .|    |    |    |    |     </cas:authenticationSuccess>
36AE .|    |    |    |    |    </cas:serviceResponse>
36AE .|    |    |    |    |     [CurlRequest.php:82]
36AE .|    |    |    |    <= true
36AE .|    |    |    |    => CAS_Client::_readExtraAttributesCas20(DOMNodeList) [Client.php:2806]
36AE .|    |    |    |    |    Testing for rubycas style attributes [Client.php:2916]
36AE .|    |    |    |    <= ''
36AE .|    |    |    |    Storing Proxy List [Client.php:2815]
36AE .|    |    |    |    => CAS_ProxyChain_AllowedList::isProxyListAllowed(array ()) [Client.php:2818]
36AE .|    |    |    |    |    No proxies were found in the response [AllowedList.php:81]
36AE .|    |    |    |    <= true
36AE .|    |    |    |    => CAS_Client::_renameSession('ST-31-36DU9hMoxL4yTCHUeVI3-cas') [Client.php:2849]
36AE .|    |    |    |    |    Session ID: ST-31-36DU9hMoxL4yTCHUeVI3-cas [Client.php:3167]
36AE .|    |    |    |    |    Restoring old session vars [Client.php:3170]
36AE .|    |    |    |    <= ''
36AE .|    |    |    <= true
36AE .|    |    |    CAS 2.0 ticket `ST-31-36DU9hMoxL4yTCHUeVI3-cas' was validated [Client.php:1231]
36AE .|    |    |    => CAS_Client::_validatePGT('https://cas.example.com:8443/cas/serviceValidate?service=https%3A%2F%2Fclient.example.com%2Fproxy.php&ticket=ST-31-36DU9hMoxL4yTCHUeVI3-cas&pgtUrl=https%3A%2F%2Fclient.example.com%2Fproxy.php', '<cas:serviceResponse xmlns:cas=\'http://www.yale.edu/tp/cas\'> <cas:authenticationSuccess>     <cas:user>admin</cas:user>  </cas:authenticationSuccess></cas:serviceResponse>', DOMElement) [Client.php:1233]
36AE .|    |    |    |    <proxyGrantingTicket> not found [Client.php:2242]
36AE .|    |    |    |    => CAS_AuthenticationException::__construct(CAS_Client, 'Ticket validated but no PGT Iou transmitted', 'https://cas.example.com:8443/cas/serviceValidate?service=https%3A%2F%2Fclient.example.com%2Fproxy.php&ticket=ST-31-36DU9hMoxL4yTCHUeVI3-cas&pgtUrl=https%3A%2F%2Fclient.example.com%2Fproxy.php', false, false, '<cas:serviceResponse xmlns:cas=\'http://www.yale.edu/tp/cas\'>   <cas:authenticationSuccess>     <cas:user>admin</cas:user>  </cas:authenticationSuccess></cas:serviceResponse>') [Client.php:2248]
36AE .|    |    |    |    |    => CAS_Client::getURL() [AuthenticationException.php:76]
36AE .|    |    |    |    |    <= 'https://client.example.com/proxy.php'
36AE .|    |    |    |    |    CAS URL: https://cas.example.com:8443/cas/serviceValidate?service=https%3A%2F%2Fclient.example.com%2Fproxy.php&ticket=ST-31-36DU9hMoxL4yTCHUeVI3-cas&pgtUrl=https%3A%2F%2Fclient.example.com%2Fproxy.php [AuthenticationException.php:79]
36AE .|    |    |    |    |    Authentication failure: Ticket validated but no PGT Iou transmitted [AuthenticationException.php:80]
36AE .|    |    |    |    |    Reason: no CAS error [AuthenticationException.php:93]
36AE .|    |    |    |    |    CAS response: <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
36AE .|    |    |    |    |     <cas:authenticationSuccess>
36AE .|    |    |    |    |         <cas:user>admin</cas:user>
36AE .|    |    |    |    |    
36AE .|    |    |    |    |    
36AE .|    |    |    |    |     </cas:authenticationSuccess>
36AE .|    |    |    |    |    </cas:serviceResponse> [AuthenticationException.php:99]
36AE .|    |    |    |    |    exit()
36AE .|    |    |    |    |    -
36AE .|    |    |    |    -
36AE .|    |    |    -
36AE .|    |    -
36AE .|    -

@ravids
Copy link
Author

ravids commented Jan 16, 2012

Next the apache access log & error log

Access Log

192.168.1.21 - - [16/Jan/2012:14:50:58 -0500] "GET /proxy.php HTTP/1.1" 302 476 "-" "Mozilla/5.0 (Windows NT 5.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1"
192.168.1.247 - - [16/Jan/2012:14:51:07 -0500] "GET /proxy.php HTTP/1.1" 302 476 "-" "Java/1.6.0_25"
192.168.1.21 - - [16/Jan/2012:14:51:07 -0500] "GET /proxy.php?ticket=ST-31-36DU9hMoxL4yTCHUeVI3-cas HTTP/1.1" 200 1240 "https://cas.example.com:8443/cas/login?service=https%3A%2F%2Fclient.example.com%2Fproxy.php" "Mozilla/5.0 (Windows NT 5.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1"

Error Log

[Mon Jan 16 14:51:07 2012] [error] [client 192.168.1.21] PHP Fatal error:  Uncaught exception 'CAS_AuthenticationException' in /home/example/phpCAS/source/CAS/Client.php:2244\nStack trace:\n#0 /home/example/phpCAS/source/CAS/Client.php(1233): CAS_Client->_validatePGT('https://cas.exa...', '<cas:serviceRes...', Object(DOMElement))\n#1 /home/example/phpCAS/source/CAS/Client.php(1088):
 CAS_Client->isAuthenticated()\n#2 /home/example/phpCAS/source/CAS.php(1088): CAS_Client->forceAuthentication()\n#3 /opt/www/html/proxy.php(16): phpCAS::forceAuthentication()\n#4 {main}\n  thrown in /home/example/phpCAS/source/CAS/Client.php on line 2244, referer: https://cas.example.com:8443/cas/login?service=https%3A%2F%2Fclient.example.com%2Fproxy.php 

@ravids
Copy link
Author

ravids commented Jan 16, 2012

I had to replace all certificate related info from catalina.out with the phrase "". Anything that could be considered sensitive was replaced. I believe that, it is the 302 redirect that causes the connection reset. I am also going to investigate why our CAS server hates 302 so much for the pgtURL validation.

2012-01-16 14:51:07,194 INFO [org.jasig.cas.authentication.AuthenticationManagerImpl] - <AuthenticationHandler: org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler successfully authenticated the user which provided the following credentials: [username: admin]>
2012-01-16 14:51:07,195 INFO [org.jasig.cas.CentralAuthenticationServiceImpl] - <Granted service ticket [ST-31-36DU9hMoxL4yTCHUeVI3-cas] for service [https://client.example.com/proxy.php] for user [admin]>
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
http-apr-8443-exec-8, setSoTimeout(5000) called
%% No cached client session
*** ClientHello, TLSv1
RandomCookie:  GMT: <removed> bytes = <removed>
Session ID:  {}
Cipher Suites: <removed>
Compression Methods:  { 0 }
***
http-apr-8443-exec-8, WRITE: TLSv1 Handshake, length = <removed>
http-apr-8443-exec-8, WRITE: SSLv2 client hello message, length = <removed>
http-apr-8443-exec-8, READ: TLSv1 Handshake, length = <removed>
*** ServerHello, TLSv1
RandomCookie:  GMT: <removed> bytes = <removed>
Session ID:  <removed>
Cipher Suite: <removed>
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
***
%% Created:  [Session-6, <removed>]
** <removed>
http-apr-8443-exec-8, READ: TLSv1 Handshake, length = <removed>
*** Certificate chain
chain [0] = [
[
<removed>
]
]


***
Found trusted certificate:
[
[
 <removed>
]
]


http-apr-8443-exec-8, READ: TLSv1 Handshake, length = 4
*** ServerHelloDone
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1
http-apr-8443-exec-8, WRITE: TLSv1 Handshake, length = 262

<removed>

http-apr-8443-exec-8, WRITE: TLSv1 Handshake, length = 32
http-apr-8443-exec-8, READ: TLSv1 Change Cipher Spec, length = 1
http-apr-8443-exec-8, READ: TLSv1 Handshake, length = 32
*** Finished
verify_data:  <removed>
***
%% Cached client session: [Session-6, <removed>]
http-apr-8443-exec-8, WRITE: TLSv1 Application Data, length = 231
http-apr-8443-exec-8, READ: TLSv1 Application Data, length = 560
http-apr-8443-exec-8, called close()
http-apr-8443-exec-8, called closeInternal(true)
http-apr-8443-exec-8, SEND TLSv1 ALERT:  warning, description = close_notify
http-apr-8443-exec-8, WRITE: TLSv1 Alert, length = 18
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
http-apr-8443-exec-8, setSoTimeout(5000) called
%% No cached client session
*** ClientHello, TLSv1
RandomCookie:  GMT: <removed> bytes = <removed>
Session ID:  {}
Cipher Suites: <removed>
Compression Methods:  { 0 }
***
http-apr-8443-exec-8, WRITE: TLSv1 Handshake, length = 75
http-apr-8443-exec-8, WRITE: SSLv2 client hello message, length = 101
http-apr-8443-exec-8, handling exception: java.net.SocketException: Connection reset
http-apr-8443-exec-8, SEND TLSv1 ALERT:  fatal, description = unexpected_message
http-apr-8443-exec-8, WRITE: TLSv1 Alert, length = 2
http-apr-8443-exec-8, Exception sending alert: java.net.SocketException: Broken pipe
http-apr-8443-exec-8, called closeSocket()
2012-01-16 14:51:07,409 ERROR [org.jasig.cas.util.HttpClient] - <java.net.SocketException: Connection reset>
java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:168)
    at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
    at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:798)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1149)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
    at sun.net.www.protocol.http.HttpURLConnection.followRedirect(HttpURLConnection.java:2124)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1367)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:379)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:318)
    at org.jasig.cas.util.HttpClient.isValidEndPoint(HttpClient.java:111)
    at org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler.authenticate(HttpBasedServiceCredentialsAuthenticationHandler.java:59)
    at org.jasig.cas.authentication.AuthenticationManagerImpl.authenticate(AuthenticationManagerImpl.java:88)
    at org.jasig.cas.CentralAuthenticationServiceImpl.delegateTicketGrantingTicket(CentralAuthenticationServiceImpl.java:262)
    at org.jasig.cas.web.ServiceValidateController.handleRequestInternal(ServiceValidateController.java:126)
    at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
    at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.jasig.cas.web.init.SafeDispatcherServlet.service(SafeDispatcherServlet.java:115)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.inspektr.common.web.ClientInfoThreadLocalFilter.doFilterInternal(ClientInfoThreadLocalFilter.java:48)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:928)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:539)
    at org.apache.tomcat.util.net.AprEndpoint$SocketWithOptionsProcessor.run(AprEndpoint.java:1773)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
2012-01-16 14:51:07,412 INFO [org.jasig.cas.authentication.AuthenticationManagerImpl] - <AuthenticationHandler: org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler failed to authenticate the user which provided the following credentials: [callbackUrl: https://client.example.com/proxy.php]>
2012-01-16 14:51:07,412 ERROR [org.jasig.cas.web.ServiceValidateController] - <TicketException generating ticket for: [callbackUrl: https://client.example.com/proxy.php]>
org.jasig.cas.ticket.TicketCreationException: error.authentication.credentials.bad
    at org.jasig.cas.CentralAuthenticationServiceImpl.delegateTicketGrantingTicket(CentralAuthenticationServiceImpl.java:291)
    at org.jasig.cas.web.ServiceValidateController.handleRequestInternal(ServiceValidateController.java:126)
    at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
    at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.jasig.cas.web.init.SafeDispatcherServlet.service(SafeDispatcherServlet.java:115)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.inspektr.common.web.ClientInfoThreadLocalFilter.doFilterInternal(ClientInfoThreadLocalFilter.java:48)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:928)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:539)
    at org.apache.tomcat.util.net.AprEndpoint$SocketWithOptionsProcessor.run(AprEndpoint.java:1773)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
Caused by: error.authentication.credentials.bad
    at org.jasig.cas.authentication.handler.BadCredentialsAuthenticationException.<clinit>(BadCredentialsAuthenticationException.java:25)
    at org.jasig.cas.authentication.AuthenticationManagerImpl.authenticate(AuthenticationManagerImpl.java:113)
    at org.jasig.cas.CentralAuthenticationServiceImpl.delegateTicketGrantingTicket(CentralAuthenticationServiceImpl.java:262)
    ... 30 more


@ravids
Copy link
Author

ravids commented Jan 16, 2012

I also forgot to reply to the following point by Joachim

Somehow it also does not fit your described situation when hardcoding the callback url works. phpCAS will always deliver a 302 to any anonymous request.

In this custom solution with the hard coded callback URL, I did not use phpCAS in the custom call back PHP script. I only used the pgt storage code from phpCAS.

@jfritschi
Copy link
Contributor

The phpCAS log is clean and works as expected. The cas server is simply not delivering the PGT/PGTiou in either the xml answer or in a callback. The apache access log does not register the callback from the cas server which can only mean the request does not even hit the apache server and must fail before (SSL layer, network, cas server etc.)
Especially from the tomcat log i would suspect that something in the SSL config is "wrong". The tomcat server is somehow cut off during ssl negotiation (which is before the webserver/php would kick in). Currently my best guess would be:

  • enable ssl debugging on client webserver
  • Try with another webserver
  • Try with the java option -Djavax.net.debug=ssl on the tomcat side to get more SSL info
  • Try with another tomcat version
  • Try a simple java ssl connection from the cas server to the client (portecle might be a choice, some short debug code or use "openssl s_client". This will allow you to verify that everything is working correctly on the ssl level
  • please verify all SSL parameters in the client certificate (expired?, dns name?, usage?) and also web server (TLS, SSLv etc.)
  • check networking issues (cas server behind loadbalancer?, firewall?)

Maybe this might give you some pointers but i strongly suspect there is something wrong in your environment. I hope this helps a bit...

@ravids
Copy link
Author

ravids commented Jan 17, 2012

Thanks again for your time and effort. I do have SSL debugging on for the tomcat server. There is no apache entry for the callback with PGT/PGTiou because, earlier the pgtUrl validation failed due to the 302 redirect.

Initially I also thought that the culprit is SSL and the environment. But with the slight modification to the phpCAS example code or with the hard coded pgtUrl to prevent the 302 redirect, everything works fine.

I will close this issue for now, and instead ask CAS server community why the CAS server hates the 302 response in my case.

I would like to thank the phpCAS community for being very supportive, and I hope to give back with our development efforts.

@ravids ravids closed this as completed Jan 17, 2012
@jfritschi
Copy link
Contributor

Yes, i think switching to the cas-user list might help. Maybe a greater audience is able to shed some light on the situation.

@gshekharjsr
Copy link

ravids I am also using the same code and not able to get the PGT after PGTiou is transmitted, I have made pgtCallback change in the code and in php logs I can see the PGTiou, but code doesn't works further. I am working on the example example_pgt_storage_db.php.

what further code changes you have done to make it work.

8685 .=> phpCAS::forceAuthentication() [example_pgt_storage_db.php:50]
8685 .| => CAS_Client::forceAuthentication() [CAS.php:1012]
8685 .| | => CAS_Client::isAuthenticated() [Client.php:1238]
8685 .| | | => CAS_Client::_wasPreviouslyAuthenticated() [Client.php:1349]
8685 .| | | | user = shekhar', PGT =PGTIOU-4-oeRAFdIx5DUTgS0l6lKr-cas01.example.org' [Client.php:1532]
8685 .| | | <= true
8685 .| | | user was already authenticated, no need to look for tickets [Client.php:1373]
8685 .| | <= true
8685 .| | no need to authenticate [Client.php:1240]
8685 .| <= true
8685 .<= ''
8685 .=> phpCAS::serviceWeb('https://localhost:8843/demo3/hello.html', NULL, NULL) [example_pgt_storage_db.php:72]
8685 .| => CAS_ProxiedService_Http_Abstract::send() [Client.php:2923]
8685 .| | => CAS_Client::retrievePT('https://localhost:8843/demo3/hello.html', NULL, NULL) [Client.php:2889]
8685 .| | | => CAS_Client::_readURL('https://localhost:8443/cas/proxy?targetService=https%3A%2F%2Flocalhost%3A8843%2Fdemo3%2Fhello.html&pgt=PGTIOU-4-oeRAFdIx5DUTgS0l6lKr-cas01.example.org', NULL, NULL, '') [Client.php:2619]
8685 .| | | | => CAS_Request_CurlRequest::sendRequest() [AbstractRequest.php:242]
8685 .| | | | | Response Body:
8685 .| | | | |
8685 .| | | | |
8685 .| | | | |
8685 .| | | | | <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
8685 .| | | | | <cas:proxyFailure code='INVALID_TICKET'>
8685 .| | | | | ticket 'PGTIOU-4-oeRAFdIx5DUTgS0l6lKr-cas01.example.org' not recognized
8685 .| | | | | /cas:proxyFailure
8685 .| | | | | /cas:serviceResponse
8685 .| | | | | [CurlRequest.php:84]
8685 .| | | | <= true
8685 .| | | <= true
8685 .| | <= false
8685 .| <= false

@vesskov
Copy link

vesskov commented Jan 13, 2015

I am new to CAS I fought the same error for hours - at the end it turned out that at some point I have commented
<bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"p:httpClient-ref="httpClient" />

in deployerConfigContext.xml.

After I have uncommented it, everything began working and PGT Iou is now transmitted to the configured URL.

@pampelix
Copy link

Has this already been resolved? I'm looking at the same issue.
In my opinion, the handling of this is just not thought through. The pgtUrl should have a parameter by default, which will make sure the call won't be redirected to CAS login page (like pgtId and pgtIou parameters). That way it would work out of the box, no matter whether the CAS application server does have access to CAS login page or not (which in my case it doesn't)

Is there a way to work around this without having to mess up the code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants