single-sign-onsymfony-1.4discourse

Simulating Discourse SSO login via php curl


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');

    if($requestIsInternal==='1'){
        //====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
        $this->redirect404();
    }

    $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

And the DiscourseAuthDriver::makeCurlRequest is as below:

public static function makeCurlRequest($url, $cookie=null){
        $ch = curl_init($url);
        if($cookie){
            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);

        curl_close($ch);
        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?


Solution

  • I dont know how but for some reason the request url works fine today and it does authenticate my users.

    In order to avoid having to mess with headers and have issues with the 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 based on the given payload and then pass em to a hidden frame that is making the login request (i.e. from the browser) 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.

    Hope it helps someone in the future.