Simulating SSO login via php curl

(Michael Katrantzis) #1

I’m in the process of integrating Discourse into our platform (using an iframe) and I am trying to understand what I am doing wrong and can’t get SSO to authenticate my users.

I am working on symfony 1.4 and I have an action that accommodates both the logic of displaying the page (that contains the iframe) and that of logging the users in.

public function executeViewDiscussionForum(sfWebRequest $request){

$requestIsInternal  = $request->getParameter('isInternal');
    //====Discourse will redirect here again with the payload parameters
    $response = DiscourseAuthDriver::makeCurlRequest('http://****.****.com:8080');
$url = parse_url($response['Location']);
$cookie = $response['Set-Cookie'];
parse_str($url['query'], $params);
$sso = $params['sso'];
$signature = $params['sig'];
// load the payload passed in by Discourse
$payload = $sso;
$ssoHelper = new SSOHelper();
// this should be the same in your code and in your Discourse settings:
$secret = '****';
$ssoHelper->setSecret( $secret );
// validate the payload
if (!($ssoHelper->validatePayload($payload,$signature))) {
    // invaild, deny
$nonce = $ssoHelper->getNonce($payload);
// Insert your user authentication code here ...
// Required and must be unique to your application
$userId = $this->currentUser->id;
// Required and must be consistent with your application
$userEmail = $this->currentUser->getEmailAddress();
// Optional - if you don't set these, Discourse will generate suggestions
// based on the email address
$extraParameters = array(
    'username' => $this->currentUser->getUsername(),
    'name'     => $this->currentUser->getFullname()
// build query string and redirect back to the Discourse site
$query = $ssoHelper->getSignInString($nonce, $userId, $userEmail, $extraParameters);
DiscourseAuthDriver::makeCurlRequest('http://*****.***.com:8080/session/sso_login?' . $query, $cookie); 


The SSOHelper class that im using is the one found here:

GitHub - cviebrock/discourse-php: A PHP class for helping with Discourse's SSO login

And the DiscourseAuthDriver::makeCurlRequest is as below:

public static function makeCurlRequest($url, $cookie=null){
        $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_HTTPHEADER, array("Set-Cookie: ".$cookie));
            curl_setopt($ch, CURLOPT_NOBODY, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; Linux x86_64; rv:21.0) Gecko/20100101 Firefox/21.0"); // Necessary. The server checks for a valid User-Agent.        
        $response = curl_exec($ch);
        $header = $response;
        $header = self::get_headers_from_curl_response($header);

        return $header[1];

If I dont have SSO enabled I can see the main discourse page loading just fine in my iframe.

The logic behind the above was that by using curl I can essentially simulate the sign in process and then serve the logged in page in the iframe but that doesnt seem to cut it as even if I manually navigate to the sign in url with the hashed parameters and everything I get the following error:

“Account login timed out, please try logging in again”

I have checked other possible answers as well as my settings and I dont have the approval option set so I thought it might be due to session information not being passed in upon requesting the login but even after adding that it doesnt seem to work.

Can anyone see what is wrong with this or identify any flaws in the logic?

(Jeff Atwood) #2

Any ideas here @sam? Ways we can improve the howto?

(Sam Saffron) #3

Oh my, there is tons of code here very hard for me to debug through all of it. But that error means that our nonce expired (you have 10 minutes where the nonce is good, it has one use), which could mean a few things.

  1. You have not load the nonce correctly
  2. You have not added the nonce correctly
  3. You have other issues generating the payload

(Kane York) #4

It looks to me like the PHP code is trying to perform the SSO login, instead of the browser? Which would be extremely wrong, and would take up the one use of the nonce…

(Michael Katrantzis) #5

Thank you all for your replies!

@riking That is indeed the case and to be honest I am not even sure if I will be able to make the iframe work considering that it ll need to carry session info but the whole point of this attempt was to see if I can use curl to simulate the browsers requests and log in the user. Could you maybe explain what you mean by “would take up the one use of the nonce”

@sam I will check the logic again but the library was used by other people in other threads I read and seemed to work.

I may have missed that but I think the API is not currently supporting the login function. It would be great if you could do that via the API as it would improve the UX massively in cases like mine where full integration is needed.

(Michael Katrantzis) #6

@sam @riking For some reason the request url works fine today and it does authenticate my users. I honestly dont understand why that is as I havent changed anything since yesterday.

In any case this seems to work now and to avoid having to mess with headers and have issues with iframe etc, I made it so that it only uses curl to retrieve the initial url that contains the payload data.

Once I grab these I process and construct the new request and then pass em to a hidden frame that is making the login request (i.e. from the browser as @riking suggested) javascript is then taking over to remove this hidden frame and load a new one that is loading the main discourse page with the user already logged in.

Thanks for the help guys!

(Kane York) #7

You should be doing this:

  • implement the SSO protocol as normal
  • after a user signs in on your site, take them to an interstitial with <embed src="" onload="window.location = '/login_finish.php'">

Is there a way to include a redirect after an SSO login?