I'm connecting to Drupal 7 through services and OAuth. All is working fine and I'm able to connect except in one situation:

When a client has a timestamp 10 minutes later (the server is working with punctual UTC+1).
The client tries to fetch token and the server refuses it with message "Unauthorized: Expired timestamp, yours 1341148133, ours 1341147701"

In OAuth.php: timestamp_threshold = 300 (5 minutes).
In function check_timestamp(), line 676 it takes time() (so it will get it in server timezone).

Any solution?
Also what will happens when client and server are in a different timezone?

For the moment the only solution is to avoid check_timestamp($timestamp) at line 648 in check_signature():

  /**
   * all-in-one function to check the signature on a request
   * should guess the signature method appropriately
   */
  private function check_signature($request, $consumer, $token) {
    // this should probably be in a different method
    $timestamp = $request instanceof OAuthRequest
        ? $request->get_parameter('oauth_timestamp')
        : NULL;
    $nonce = $request instanceof OAuthRequest
        ? $request->get_parameter('oauth_nonce')
        : NULL;
    //$this->check_timestamp($timestamp); // <-- TIMEZONE Errors!
    $this->check_nonce($consumer, $token, $nonce, $timestamp);

    $signature_method = $this->get_signature_method($request);

    $signature = $request->get_parameter('oauth_signature');
    $valid_sig = $signature_method->check_signature(
      $request,
      $consumer,
      $token,
      $signature
    );

    if (!$valid_sig) {
      throw new OAuthException("Invalid signature");
    }
  }

Which are the risks?

Thanks,
Miguel

Comments

miqmago’s picture

Issue summary: View changes

Adding code

g10’s picture

This also fixes the issue when using 2-legged auth in an app and the client device (desktop, mobile…) its clock is not correctly set.

IMHO, the implementation is not correct, according to the oAuth specs ( http://oauth.net/core/1.0/#nonce )

The timestamp value MUST be a positive integer and MUST be equal or greater than the timestamp used in previous requests.

So the only requirement is that the timestamp should be newer then the last timestamp used, not that it should be in a given range of the server time.

miqmago’s picture

Category: support » bug

Then I change it to bug.
If I knew where the last timestamp is stored (if it is, if it is not then I will create see how to create a db entry with last timestamp used field) I will try to repair it. I will take a look but don't know when...

g10’s picture

Timestamps are not being stored, cfr. check_timestamp() method.

Although stated in the oAuth specs as such, it still would cause problems for 2-legged.
Can you tell the difference between client A and B if they both use the same key/secret with 2-legged auth?
As I have implement it (could be faulty), is making one user with a consumer, then using that one key/secret for all the client apps,
as a result it is not possible to differentiate which client is making the call. (As said, I might have done it wrong)

With 3-legged there are distinct consumers, I guess storing the last timestamp for each consumer should work.

miqmago’s picture

Sorry about my ignorance... I don't know if I'm using 2 or 3 legged. I think it is 3 legged, because I create a consumer for each user.

As far as I understand from what you say, maybe would work for 2-legged to store the sid, or better the access token with last timestamp. Then you could differenciate each request.
I don't know if with 2-legged there is a different access token for each device.

miqmago’s picture

Issue summary: View changes

Clarifying description