Awesome. Typhoeus uses curb, right? This OAuth lib is quite tightly
tied to Net::HTTP, though I wish that weren't the case. However,
while building out the CLI (lib/oauth/cli.rb, which is in need of some
refactoring), I ended up making / finding ways to generate signatures,
etc. without using Net::HTTP, so you may be able to re-use some of
that.
As a result, you're probably best of using MockRequest (which was
created for the CLI / testing), as it proxies a Hash.
> One thing that's impeding my understanding is this: The signature for
> the OAuth::RequestProxy.proxy method is "proxy(request, options = {})"
> but everywhere it's called - including in documentation examples - it
> is simply passed a hash. No request, and no nil to take its place.
>
> I don't understand how that works. What am I missing here?
Wow, that is confusing. Since it's being passed a Hash, that's being
used as the stand-in for the "request" object and it's (probably)
instantiating a MockRequest RequestProxy. I'm not sure where / how
the options are actually used; it may be specific for individual
request proxies (e.g. Net::HTTP).
seth
The OAuth::Consumer class is tightly bound, but the RequestProxy stuff
isn't, so if you're just trying to use the OAuth library to generate
signatures, then you'll want to write a new RequestProxy. I'd
recommend looking at the client/net_http.rb class, and at the various
RequestProxies.
>> One thing that's impeding my understanding is this: The signature for
>> the OAuth::RequestProxy.proxy method is "proxy(request, options = {})"
>> but everywhere it's called - including in documentation examples - it
>> is simply passed a hash. No request, and no nil to take its place.
>>
>> I don't understand how that works. What am I missing here?
I can't speak to the examples (links?) but OAuth::RequestProxy should
definitely take a "request" object; what is a request object is
defined as new subclasses of OAuth::RequestProxy::Base are defined, as
in:
module OAuth::RequestProxy::Net
module HTTP
class HTTPRequest < OAuth::RequestProxy::Base
proxies ::Net::HTTPRequest
from oauth/request_proxy/net_http.rb
So what you'll want to do is write an OAuth::RequestProxy::EasyProxy
(I think that's right, based on a quick glance at Typhoeus) that
normalizes the various parameters from the request into the
formats/escaping expected by OAuth::Signature::* (basically you need
method, uri, and parameters [expected by OAuth] for an outgoing
Request object).
Once you have that, you can look at writing an OAuth::Client that
wraps all the OAuth parameters, signing, and request modification into
a neat package. Once that's done, at least the OAuth::Consumer.sign!
method should work, and the OAuth::Consumer.create_http method can
changed to allow different HTTP classes; SSL and the get_*_token
methods will take a bit more refactoring, though, depending on how the
Typhoeus request class expects SSL and/or parameters.
Hope that helps!
b.
Actually when creating it Paul wrote his own C bindings, but it does
use libcurl like curb.
> The OAuth::Consumer class is tightly bound, but the RequestProxy stuff
> isn't, so if you're just trying to use the OAuth library to generate
> signatures, then you'll want to write a new RequestProxy. I'd
> recommend looking at the client/net_http.rb class, and at the various
> RequestProxies.
That is mainly what I'm trying to do. I want to use Typhoeus to make
my OAuth-authenticated HTTP requests (I'm okay with using OAuth and
Net::HTTP to perform initial authentication), so I'm looking to come
up with a way to use OAuth to sign Typhoeus requests.
> I can't speak to the examples (links?) >
The example is in the OAuth::RequestProxy::MockRequest doc, found
here: http://oauth.rubyforge.org/rdoc/classes/OAuth/RequestProxy/MockRequest.html
request = OAuth::RequestProxy.proxy
"method" => "iq",
"uri" => [from, to] * "&",
"parameters" => {
"oauth_consumer_key" => oauth_consumer_key,
"oauth_token" => oauth_token,
"oauth_signature_method" => "HMAC-SHA1"
}
The generated RDoc is actually a little bit malformatted; I've cleaned
it up above. But, on further inspection, I see that most calls in the
OAuth code base do call it with some object in the first slot. It's
only MockRequest that shows using a hash - which is exactly the point
of MockRequest, and I don't know what had me so confused about that.
I also see now the magic in MockRequest: "proxies Hash". That coupled
with how RequestProxy.proxy looks at the class of the passed request
object to decide which of the proxies to use is making things clear to
me now (I think the problem is just that this code is much smarter
than I am). :)
> So what you'll want to do is write an OAuth::RequestProxy::EasyProxy
[snip]
> Hope that helps!
It definitely does. I think for my purposes all I really need to do is
figure out how to use MockRequest to sign requests for Typhoeus.
Because Typhoeus supports get/put/post/delete taking a URI and hash of
parameters, I should be able to wrap those up in methods that use
MockRequest to generate and apply the signature.
Thanks very much for the road map, gentlemen. I have a much better
understanding of how this all works now - and it's really quite
clever, I must say.
--
Bill Kocik
GitHub is down, otherwise I'd attach what's below.
The short of it is that you need to use `"GET"` as your method instead
of `:get` (the MockRequestProxy isn't smart enough to do the
conversion, which I'd argue is fine--explicit is good). You're also
repeating OAuth params that are already in the `Authorization` header
(don't bother merging your params with those from the proxy if you're
planning on using header auth).
I changed variable (in both senses) strings so that I could compare it
to the command-line output. The signature base string is almost
always the place to look for problems.
seth
$ oauth --consumer-key key --consumer-secret consumer_secret --token
token --secret token_secret --nonce
csWqt5OX63Ggsm0HINfSZNn07WzVFi14LnQM1dUSs --timestamp 1253126550
--method GET --uri http://example.com/foo --parameters "bar:baz" debug
require 'oauth'
def get(*args)
uri = args[0]
params = args[1] || {}
req = OAuth::RequestProxy.proxy(
'method' => "GET",
'uri' => uri,
'parameters' => prepare_parameters(params)
)
req.sign!(:consumer_secret => "consumer_secret", :token_secret =>
"token_secret")
#raise req.oauth_header
puts "URI: #{uri}"
puts "Parameters: #{req.parameters.merge(params).inspect}"
puts "SBS: #{req.signature_base_string}"
puts "Authorization header: #{req.oauth_header}"
# res = Typhoon.get(uri, :params => req.parameters.merge(params),
:headers => {"Authorization" => req.oauth_header})
# raise res.inspect
end
def prepare_parameters(params)
extra_params = {}
params.each do |k,v|
k = k.is_a?(Symbol) ? k.to_s : k
extra_params[k] = v
end
{
"oauth_consumer_key" => "key",
"oauth_nonce" => "csWqt5OX63Ggsm0HINfSZNn07WzVFi14LnQM1dUSs",
"oauth_timestamp" => 1253126550,
"oauth_token" => "token",
"oauth_signature_method" => 'HMAC-SHA1',
"oauth_version" => '1.0'
}.reject { |k,v| v.nil? || v == "" }.merge(extra_params)
end
get("http://example.com/foo", {:bar => "baz"})
On Wed, Sep 16, 2009 at 2:56 PM, Seth Fitzsimmons <se...@mojodna.net> wrote:
> The short of it is that you need to use `"GET"` as your method instead
> of `:get` (the MockRequestProxy isn't smart enough to do the
> conversion, which I'd argue is fine--explicit is good). You're also
> repeating OAuth params that are already in the `Authorization` header
> (don't bother merging your params with those from the proxy if you're
> planning on using header auth).