1
votes

Eyes are getting sore trying to hunt down the issue causing this. I'm narrowing it down but I'm tired of changing different parameters to get the signature to pass. I've been comparing my base string and Authorization headers with those output by the google-code-playground.

I've been referencing this article and think I am getting close:

PHP Oauth signature_invalid

My base string:

GET&https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthGetRequestToken&oauth_callback%3Dhttp%253A%252F%252Fgooglecodesamples.com%252Foauth_playground%252Findex.php%26oauth_consumer_key%3Danonymous%26oauth_nonce%3D1f8a27974826a0001f679186898bb79a%26oauth_signature_method%3DHMAC- SHA1%26oauth_timestamp%3D1313023952%26oauth_version%3D1.0%26scope%3Dhttps%253A%252F%252Fwww.google.com%252Fcalendar%252Ffeeds%252F

Authorization headers:

OAuth oauth_consumer_key="anonymous", oauth_nonce="1f8a27974826a0001f679186898bb79a", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1313023952", oauth_callback="http%3A%2F%2Fgooglecodesamples.com%2Foauth_playground%2Findex.php", oauth_version="1.0", oauth_signature="nHL5107wlVXrB5GJjyDClpc5pJs%3D"0signature_invalid

Main Function:

private function oAuthGetRequestToken()
{
    echo "<pre>";
    $secret = 'anonymous';
    $url = 'https://www.google.com/accounts/OAuthGetRequestToken';
    $scope = 'https://www.google.com/calendar/feeds/';

    $authParams = array(
                    'oauth_consumer_key' => 'anonymous',
                    'oauth_nonce' => self::generateNonce(),
                    'oauth_signature_method' => 'HMAC-SHA1',
                    'oauth_timestamp' => time(),
                    'oauth_callback' => 'http://googlecodesamples.com/oauth_playground/index.php',
                    'oauth_version' => '1.0');

    $unsignedBaseString = self::getBaseString('GET', $url, $authParams, $scope);            

    $unsignedKey = array($authParams['oauth_consumer_key'], $secret);
    $unsignedKeyParts = array_map('urlencode', $unsignedKey);
    $key = implode('&', $unsignedKeyParts);

    $oauth_signature = self::hmacsha1($key, $unsignedBaseString);
    $authParams['oauth_signature'] = $oauth_signature;

    $rest = new Rest();
    $oAuthGetRequestTokenResponse = $rest->OAuthHttpGetRequest($url, $authParams, $scope);
    print_r($oAuthGetRequestTokenResponse);
}

Helper functions:

    protected function generateNonce()
{
    $nonce = hash('md5', self::makeRandomString());
    return $nonce;
}

protected function makeRandomString($bits = 256)
{
    $bytes = ceil($bits / 8);
    $return = '';
    for ($i = 0; $i < $bytes; $i++) {
        $return .= chr(mt_rand(0, 255));
    }
    return $return;
}

protected function hmacsha1($key, $data) 
{
    return base64_encode(hash_hmac('sha1', $data, $key, true));
}

protected function getBaseString($method, $url, $authParams, $scope)
{
    $authString = '';       
    foreach($authParams as $key => $value)
        $authString .= $key . "=" . urlencode($value) . "&";

    $authString = rtrim($authString, '&');

    $baseString = $method . '&' . urlencode($scope) . '&' . $authString;
    return $baseString;
}

Rest/Request function:

public function OAuthHttpGetRequest($url, $authParams, $scope)
{
    $oAuthHeaders = '';
    $oAuthHttpGetResponse;
    foreach($authParams as $key=>$value)
    {
        $oAuthHeaders .= $key . '="' . urlencode($value) . '", ';
    }

    $oAuthHeaders = rtrim($oAuthHeaders, ', ');
    $authString = "OAuth " . $oAuthHeaders;
    echo "<br/>" . $authString;
    $urlWithScope = $url . '?scope=' . urlencode($scope);

    if($curlHandle = curl_init())
    {
        curl_setopt($curlHandle, CURLOPT_URL, $urlWithScope);

        curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curlHandle, CURLOPT_HTTPHEADER, array("Authorization: " . $authString));
        //curl_setopt($curlHandle, CURLOPT_POST, TRUE);
        //curl_setopt($curlHandle, CURLOPT_POSTFIELDS, );
        curl_setopt($curlHandle, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($curlHandle, CURLOPT_SSL_VERIFYHOST, 0);

        $oAuthHttpGetResponse = curl_exec($curlHandle);
        echo curl_errno($curlHandle);
        echo curl_error($curlHandle);

        curl_close($curlHandle);
    }
    else
        die("Could not instance cURL, is the module enabled?");

    return $oAuthHttpGetResponse;
}
1

1 Answers

0
votes

on first read I think your problem is in the getBaseString function:

$baseString = $method . '&' . urlencode($scope) . '&' . $authString;

I think that you should use the REQUEST TOKEN ENDPOINT here instead of the scope...

Scopes are requested with additional parameter, because generally the OAuth protocol does not specify the existence of scopes - they are extension needed to better tune API access, but they are not mandatory for the protocol to work.

And when creating the base signature string, the URL that is included after the $method, is always the URL which is going to receive the request...

In your case I think it should be:

$baseString = $method . '&' . urlencode($url) . '&' . $authString;

--- ADDON ---

To be more clear: when first requesting REQUEST token, the base string should contain the URL of the REQUET TOKEN endpoing...

When later requesting ACCESS token, the base string should contain the URL of the ACCESS TOKEN endpoint

When finally, after getting ACCESS token you are accessing a resource (scope) then the base string should contain the URL of the resource (aka scope in your example)...