Hi, i have installed Services and oAuth module, but i can't authenticate to my REST server.
The error i get when i try to call service ( http://drupalsite/endpoint/node/1?oauth_consumer_key=eAQjV6.... ) with my access_token and other details is "NetworkError: 401 Unauthorized:The consumer is not authorized to access this service".
I have created oAuth context. REST server is using oAuth auth and with my created context.
Also i have created Consumer which has the same context.

Maybe i have missed some configuration? or is this bug?
Thanks.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

kylebrowning’s picture

Project: Services » OAuth 1.0

This is an oAuth bug.

edb’s picture

Could you share the code you have used to get up to this point? There is zero documentation around for this stuff and it would be useful for others to take a look.

borys’s picture

You can follow this instructions to get all needed keys and authorize your application:
http://groups.drupal.org/node/131039#comment-426184

Then i have used "example/index.php" file from this library (http://oauth.googlecode.com/svn/code/php/), filled all keys, that should look something like this:

$test_consumer = new OAuthConsumer("eAQjV6K3ob99sdfSebb3LFpERHDMSyrd4B", "mcUBpM6L6p9wGeKRdfC5uVVB5rZGAaNik", NULL);
$req_token = new OAuthConsumer("gJERkazjpoZDKKtAAusdfbi3TW3X5k8yVX", "FYpXjbts2Sng2J3mjQSsQc9zwSWQA3SL", 1);
$acc_token = new OAuthConsumer("ivqoTo2NauiM9oM5Zo7pukj6sdfnx4WsVz", "QULixTA6rQBoiEd7x8dfKWwyN8JmG5nDi", 1);
//....
$req_req = OAuthRequest::from_consumer_and_token($test_consumer, NULL, "GET", "http://drupalsite/oauth/request_token");
$req_req->sign_request($sig_method, $test_consumer, NULL);

$acc_req = OAuthRequest::from_consumer_and_token($test_consumer, $req_token, "GET", "http://drupalsite/oauth/access_token");
$acc_req->sign_request($sig_method, $test_consumer, $req_token);

$echo_req = OAuthRequest::from_consumer_and_token($test_consumer, $acc_token, "GET", 'http://drupalsite/endpoint/node/1', array());
$echo_req->sign_request($sig_method, $test_consumer, $acc_token);

Then you can go to this page and the last link should look something like this:
Example
http://drupalsite/endpoint/node/1?oauth_consumer_key=eAQjV6K3ob99TSebb3d...

This link should call API, but i get 'The consumer is not authorized to access this service' error.

If you will get this working with Services 3.x and Drupal 7, please share the information.

solange_k’s picture

I have the same problem, using OAuth Authentication 7.x-3.1, Services 7.x-3.1 + REST Server 7.x-3.1, I've configured everything correctly as far as I can tell, ie, created context, consumer, and set to use "Enable the oauth provider" etc , I'm using http://code.google.com/p/oauth/ to test (having downloaded svn on localhost) with all the required parameters (key + secret) and invariably the server response is "401 Unauthorized: Invalid signature".

I've tried everything.... anyone have any clues? ?

Thanks

jobeirne’s picture

Which version of the OAuth module is everyone using? I highly recommend working off of a dev branch, and then pegging to a specific commit when you find a version that works for you.

After having installed OAuth/Services/REST Server, creating a context, and creating a consumer, I've followed the instructions here (under 'Obtaining an Access Token Pair'). I then use Groovy's HTTPBuilder to communicate with the Drupal endpoint, also detailed in the link above.

The above works fine for me. I wonder if there's a misunderstanding in your use of (or a bug in) the PHP library you're using to make requests.

James

Alan Evans’s picture

Just a suggestion here - I'm opening a separate issue about updating the OAuth.php lib from google in oauth.module, but in my case this was the solution to my authentication woes on services. Problems arise if you have API client code using the latest google OAuth.php to sign a request, but oauth.module uses an older version which has some issues.

You can try downloading the latest from google ( http://oauth.googlecode.com/svn/code/php/ ) , and replacing the bundled file under oauth/lib/ with the new one and see if that helps. There aren't many changes, but the $_SERVER['SERVER_NAME'] change is massively significant if you use a non-standard port.

Alan Evans’s picture

See also #1337718: OAuthRequest->http_url defaults to having the port twice! - this is one possible cause of auth failures (client code signs with a different url as the server verifying). Note that the main issue that is addressed here only applies if you're using a non-standard port.

TriangleTodd’s picture

I don't know that a lot of people here write or know perl, but it's what I use for OAuth testing. Hope it helps.

Note: I have yet to get OAuth working and I am receiving the error in this bug report. If I'm doing something wrong in the script below please let me know. If there is a patch you can point me to for this particular issue that would also be appreciated.

#!/usr/bin/perl
# TEdwards - 04/02/12 - Testing Drupal OAuth 6.x-3.0-beta4
use strict;
use warnings;

use Data::Dumper;
use LWP::UserAgent;
use HTTP::Request::Common;
use Net::OAuth;
$Net::OAuth::PROTOCOL_VERSION = Net::OAuth::PROTOCOL_VERSION_1_0;

# The base uri to your drupal installation and your user key and secret pair.
my $site = "http://www-dev.CENSORED.com";
my $user_key = "M9y4VkrpN3gwT3353B9fPaf5obBUVeWC";
my $user_secret = "FRbj9GJWEkK2Frf7jCbTgrDP789HaVvf";

################################################################################
#
# Since we already know our user key and secret the &request subroutine can be
# used to generate our request token and secret. Returns them as a hash. 
# eg.:
   my %request = &request;
   print "POST => ",          $request{url},        "\n";
   print "Request Token: ",   $request{token},      "\n";
   print "Request Secret: ",  $request{secret},     "\n\n";
# 
# We can now generate an access token and secret by calling the &access 
# subroutine and passing it the request token and secret.
# eg.
   my %access = &access(
     'token' => $request{token}, 
     'secret' => $request{secret} 
   );
   print "POST => ",          $access{url},         "\n";
   print "Access Token: ",    $access{token},       "\n";
   print "Access Secret: ",   $access{secret},      "\n\n";
#
# 
# Now that we have an access token and secret we can start making api calls with
# the &get subroutine below. The &get subroutine expects for you to pass it a 
# hash including the access token, access token secret, api endpoint, any 
# parameters you want to send to the API, and a boolean named json. If json is
# null or false the Content API will return XML unless otherwise configured.
# eg.
   my %apires   = &get(
     token      => 'sbppwHHpCoxiKFDkibac9ZzwNTaiXFKo',
     secret     => 'Evsd5SCAxEdTBWctt6EFBL7ZnKwiWTTu',
     endpoint   => '/api/content',
     parameters => [ 
       'limit=5',
       'type=article',
       'page=2',
     ],
     json       => 1,
   );
   print "GET => ",           $apires{url},         "\n";
   print "Data Returned: ",   $apires{data},        "\n";
#
################################################################################


sub get {
  my %args = @_;

  my %response;  

  my $json = $args{json} ? '.json' : '';
  my $parameters = join('&',@{$args{parameters}});
  my $url = $site.$args{endpoint}.$json.'?'.$parameters;

  my $request =
    Net::OAuth->request('protected resource')->new(
      consumer_key => $user_key,
      consumer_secret => $user_secret,
      token => $args{token},
      token_secret => $args{secret},
      request_url => $url,
      request_method => 'GET',
      signature_method => 'HMAC-SHA1',
      timestamp => time,
      nonce => _nonce(),
    );  

  $request->sign;
  $response{url} = $request->to_url;

  my $ua = LWP::UserAgent->new;
  my $res = $ua->request(GET $response{url});
  if ($res->is_success) {
    $response{data} = $res->as_string;
  } else {
    die "\nError getting protected resource: ".$res->status_line."\n\n";
  }
  
}

sub request {
  my %request;

  # the default request token uri
  my $url = $site."/oauth/request_token";
  my $request =
    Net::OAuth->request('consumer')->new(
      consumer_key => $user_key,
      consumer_secret => $user_secret,
      request_url => $url,
      request_method => 'POST',
      signature_method => 'HMAC-SHA1',
      timestamp => time,
      nonce => _nonce(),
    );
 
  $request->sign;
  $request{url} = $request->to_url;
  
  my $ua = LWP::UserAgent->new;
  my $res = $ua->request(POST $request{url});

  if ($res->is_success) {
    my $response  = Net::OAuth->response('request token')->from_post_body($res->content);
    $request{token}  = $response->token;
    $request{secret} = $response->token_secret;
  } else {
    die "\nError getting request token: ".$res->status_line."\n\n";
  }

  return %request;
}

sub access {
  my %args = @_;

  my %access;
  
  # the default access token and authorization uri's 
  my $access_url    = $site."/oauth/access_token";
  my $authorize_url = $site."/oauth/authorize?oauth_token=".$args{token};
  
  print "\nGo to the following URL and login:\n     $authorize_url\n\n";
  &_pause;

  my $request =
    Net::OAuth->request('access token')->new(
      consumer_key => $user_key,
      consumer_secret => $user_secret,
      token => $args{token},
      token_secret => $args{secret},
      request_url => $access_url,
      request_method => 'POST',
      signature_method => 'HMAC-SHA1',
      timestamp => time,
      nonce => _nonce(),
  );
  $request->sign;
  $access{url} = $request->to_url;

  my $ua = LWP::UserAgent->new;
  my $res = $ua->request(POST $access{url});
  
  if ($res->is_success) {
    my $response = Net::OAuth->response('access token')->from_post_body($res->content);
    $access{token} = $response->token;
    $access{secret} = $response->token_secret;
  } else {
    die "\nError getting access token: ".$res->status_line."\n\n";
  }
  return %access;
}

sub _nonce {
  my @a = ('A'..'Z', 'a'..'z', 0..9);
  my $nonce = '';
  for(0..31) {
    $nonce .= $a[rand(scalar(@a))];
  }

  $nonce;
}

sub _pause {
  local( $| ) = ( 1 );
  print "Press <Enter> or <Return> to continue... \n\n";
  my $resp = <STDIN>;
} 
christianchristensen’s picture

Status: Active » Needs review
FileSize
691 bytes

(Note: this patch is against 6.x-3.x, but I think this might need some thought...)
I noticed I was getting an Invalid signature against OAuth as a server regardless of what client I was trying. Upon debugging it turned out the bit trying to parse the query string and avoid collision with "q" was being triggered, even though the client wasn't aware of a "q" parameter. I suspect this b/c I am using nginx+php-fpm with rewrite rules, which seems like it could be a more broad problem. My solution here was to do one last ditch detection looking for "oauth/" in the "q" query string.

christianchristensen’s picture

Updating this patch with consideration for port information as well - these seem like additional options relevant to a representative drupal installations.

christianchristensen’s picture

Cleaner version of #10

glennpratt’s picture

Status: Needs review » Needs work
+++ b/includes/DrupalOAuthRequest.incundefined
@@ -44,6 +50,9 @@ class DrupalOAuthRequest extends OAuthRequest {
+    if (variable_get('oauth_common_from_request_build_http_url', FALSE)) {
+      $http_url = $base_url . $_SERVER['REQUEST_URI'];

I wouldn't even hide this behind a variable. Drupal carefully built $base_url for you and provides options to override it.

As far as I can tell, the code in the OAuth library is wrong, it will break on a reverse proxy or if your servers hostname isn't set to the public hostname. See:

http://code.google.com/p/oauth/source/browse/code/php/OAuth.php#258

glennpratt’s picture

Status: Needs work » Needs review

Dreditor changed status on me.

christianchristensen’s picture

@glennpratt Fair point!

christianchristensen’s picture

I have been working through this a bit more and based on my earlier patch, matching on "oauth/" in the path, this does not account for the variety of ways other URL strings could be called (i.e. services_oauth). I am offering up a compromise here to ignore all "q=" query path options (default drupal case) until a more reasonable comparison to pull out "q=" passed vs. "q=" from drupal cases.

devkinetic’s picture

christianchristensen, your patch in #15 has resolved my separate issue #1536852: WSOD on oauth/request_token

miqmago’s picture

After appliyng #15 I get "401 Unauthorized: Invalid signature" when requesting a token with valid consumer and valid consumer secret. When reverting the patch this error disappears.

GET /public_html/oauth/request_token?oauth_consumer_key=yrh...&oauth_nonce=ea0...&oauth_signature=C5B...&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1336214121&oauth_version=1.0 HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20100101 Firefox/12.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ca,es-es;q=0.8,es;q=0.6,en-us;q=0.4,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://localhost/android_tests/oauth_test/example/client.php
Cookie: has_js=1

oauth_consumer_key yrh...
oauth_nonce ea0...
oauth_signature C5B...
oauth_signature_method HMAC-SHA1
oauth_timestamp 1336214121
oauth_version 1.0

miqmago’s picture

I haven't seen this was a D6 patch. Anyway, is this appliyng to D7?

miqmago’s picture

After scratching and scratching my head, I see this is a documentation & design problem.

Please, see this StackOverflow question

kylebrowning’s picture

to be clear you should probably be using Services 7.x-3.x-dev it has updates to the services oauth module that may fix your issues.

I have successfully created an endpoint, and made successful 2 legged AND 2 legged oath calls.

I really think he oath module is in bad bad shape and I cant really decide if I should start a new branch and do it correctly. or fix the latest dev :/

The usability behind it is terrible and Im going to start cleaning it up pretty soon.

Syntapse’s picture

That's great news. i put oauth testing aside since my first post, but i'll get back on to testing once there's a cleaner build to test... An set of accompanying videos or recipes would be great. I'm happy to contribute once I get some use cases going...

eojthebrave’s picture

Just wanted to chime in and say that I am also making successful 2-legged calls with the latest dev release of services (7.x-3.x), and that it does not work with the 7.x-3.1 release.

muschpusch’s picture

Could please someone share how he achieved this? Should it still work on current dev?

alandarev’s picture

I am newbie in OAuth + Services, but wanted to try 'industrial standards' while writing my internal infrastructure.
What can go wrong? Just install few stable modules, configure then and done! Sadly NO...

Ok, sorry for abstract. Have been having same issue with 7.x-3.1 stable Services and 7.x-3.0 OAuth.
After reading this article, decided to try 7.x-3.x dev of Services, and it seems to be working now (in 3 legged OAuth + REST )

So I advice you trying dev branch of Services.

muschpusch’s picture

I failed even with services in dev. Moved back to session authentification. Did you apply any patches?

alandarev’s picture

Status: Needs review » Closed (fixed)

The described issue seems to be fixed in 7.x-3.x-dev as pointed out in comments #20, #22, #24