Question

I'm currently trying to get PHP to login and authenticate with a CAS single sign on server which is proving difficult.

The official site has some basic source code here which is supposed to handle the authentication and log in a user. As far as I can see and in my testing it completes steps 1 and 2 in the process (see this diagram for the basic process). Once I've logged into the test server I can complete step 3 and retrieve the service ticket from the URL that sent me back to my page. There doesn't seem to be any examples anywhere to complete steps 4 and 5 of the process. Is it correct that I need to write my own code to do that?

I have attempted to get the ticket back and then send it off to the validation service using some of my own code with cURL or fsockopen with no luck.

if (isset($_GET['ticket']))
{
    $currentProtocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') ? 'https://' : 'http://';
    $requestUri = explode('?', $_SERVER['REQUEST_URI']);
    $requestUri = $requestUri[0];
    $ticket = $_GET['ticket'];
    $port = ($_SERVER['SERVER_PORT'] != 80) ? ':8080' : '';
    $currentUrl = urlencode($currentProtocol . $_SERVER['SERVER_NAME'] . $port . $requestUri);
    $validateUrl = 'ssl://server.com/cas/serviceValidate?service=' . $currentUrl . '&ticket=' . $ticket;

    $errno = 0;
    $errstr = '';   
    $fp = fsockopen($validateUrl, 443, $errno, $errstr, 30);

    if (!$fp) {
        echo "$errstr ($errno)<br />\n";
    }
    else {
        var_dump($fp);

        $out = "GET / HTTP/1.1\r\n";
        $out .= "Host: www.example.com\r\n";
        $out .= "Connection: Close\r\n\r\n";
        fwrite($fp, $out);
        while (!feof($fp)) {
            echo fgets($fp, 128);
        }
        fclose($fp);
    }
}

I can get a legitimate response from the service if I access it through the browser directly e.g:

https://server.com/cas/serviceValidate?service=http%3A%2F%2Flocalhost%3A8080%2Ftestcas%2Fcas-client.php&ticket=ST-35717-XLiWQ2ucCCuks2wsVNMJ-cas

Which returns an XML response containing the Active Directory User ID:

<cas:serviceResponse xmlns:cas='http://www.server.com/cas'>
    <cas:authenticationSuccess>
        <cas:user>c314317</cas:user>
    </cas:authenticationSuccess>
</cas:serviceResponse>

But I really think I need to be able to access that URL directly from the server side with PHP, then once I have the user ID I can link that back with our systems and log them into the site.

My problem is there doesn't seem to be any code to handle the ticket and validation side of things. Can anyone point me in the right direction?

Thanks very much.

Was it helpful?

Solution

OK I think I solved the problem with cURL. I didn't have the CURLOPT_SSL_VERIFYPEER set to false and that's why it was failing. I can now get the XML response with PHP, process the XML response and retrieve the user ID. Here's the code:

// Get the current server address we are executing the PHP from
$currentProtocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') ? 'https://' : 'http://';
$requestUri = explode('?', $_SERVER['REQUEST_URI']);
$requestUri = $requestUri[0];
$ticket = $_GET['ticket'];
$port = ($_SERVER['SERVER_PORT'] != 80) ? ':' . $_SERVER['SERVER_PORT'] : '';   # Don't need the port if it's 80, but needed if for example test server is running port 8080 
$currentUrl = $currentProtocol . $_SERVER['SERVER_NAME'] . $port . $requestUri;

// Setup the validation URL
$validateUrl = 'https://sso.server.com/cas/serviceValidate?service=' . strtolower(urlencode($currentUrl)) . '&ticket=' . $ticket;

// Send request to validate the URL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $validateUrl);        # The URL to get the data from
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);     # Return the value of curl_exec() instead of outputting it out directly.
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 120);      # The number of seconds to wait while trying to connect
curl_setopt($ch, CURLOPT_TIMEOUT, 120);             # The maximum number of seconds to allow cURL functions to execute
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);        # Check the existence of a common name and also verify that it matches the hostname provided
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);    # Stop cURL from verifying the peer's certificate
curl_setopt($ch, CURLOPT_HEADER, false);            # Don't include the header in the output

// Execute the request and close the handle
$xml = curl_exec($ch);
curl_close($ch);

// Get the user ID from the XML using XPath
$xml = new SimpleXMLElement($xml);
$result = $xml->xpath('cas:authenticationSuccess/cas:user');
$userId = null;

while(list( , $node) = each($result))
{
    $userId = (string) $node;
}

echo 'user: ' . $userId . "<br>";
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top