Hello,
This implements a basic OAuth client. It's fairly useless by itself, and the intention is that it will be extended by other classes -- e.g., you'd implement a FactoryClient that includes this code.
By default, it will check config/settings.yml for a key under oauth: with the name of the host. I included a commented-out example. If this is not to your liking, you're free to implement your own consumer_credentials_for_resource, and to customize default_headers. (For example, in Katello, you might want default_headers to return {'katello-user' => 'admin'}.)
As an open question: Where should this code live? I've placed it in Conductor, but I'm wondering if it might actually belong in aeolus-image, which is likely going to be the primary consumer of OAuth providers.
None of the providers we wish to consume using OAuth -- iwhd, Factory, or Config Server -- have OAuth support just yet. However, it should be trivial to implement new clients once they're ready.
I don't have tests ready yet, but wanted to get this on the list for review sooner rather than later.
Sample usage:
require 'oauth_client' o = OAuthClient.new('http://www.example.com/') o.authenticated_get('/api/providers') puts o.body
Best, Matt
--- aeolus-conductor.spec.in | 1 + src/Gemfile | 1 + src/Gemfile.lock | 2 + src/config/settings.yml | 4 +++ src/lib/oauth_client.rb | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 70 insertions(+), 0 deletions(-) create mode 100644 src/lib/oauth_client.rb
diff --git a/aeolus-conductor.spec.in b/aeolus-conductor.spec.in index 9f5b6c2..b974a1d 100644 --- a/aeolus-conductor.spec.in +++ b/aeolus-conductor.spec.in @@ -36,6 +36,7 @@ Requires: rubygem(rails_warden) Requires: rubygem(aeolus-image) Requires: rubygem(pg) Requires: rubygem(ruby-net-ldap) +Requires: rubygem(oauth) Requires: postgresql Requires: postgresql-server
diff --git a/src/Gemfile b/src/Gemfile index db6f949..2d8e8df 100644 --- a/src/Gemfile +++ b/src/Gemfile @@ -21,6 +21,7 @@ gem 'fastercsv' gem 'rails_warden' gem 'ruby-net-ldap' gem 'aeolus-image' +gem 'oauth' group :development, :test do gem 'rspec-rails' gem 'rspec-core' diff --git a/src/Gemfile.lock b/src/Gemfile.lock index 122990b..c708203 100644 --- a/src/Gemfile.lock +++ b/src/Gemfile.lock @@ -84,6 +84,7 @@ GEM treetop (~> 1.4.8) mime-types (1.16) nokogiri (1.5.0.beta.4) + oauth (0.4.4) pg (0.11.0) polyglot (0.3.1) rack (1.3.0) @@ -174,6 +175,7 @@ DEPENDENCIES json launchy nokogiri + oauth pg rack-restful_submit rails (>= 3.0.7) diff --git a/src/config/settings.yml b/src/config/settings.yml index 0a629f1..8ffa414 100644 --- a/src/config/settings.yml +++ b/src/config/settings.yml @@ -12,3 +12,7 @@ # :port: 389 :iwhd: :url: http://localhost:9090 +# :oauth: +# example.com: +# :consumer_key: consumer_key_here +# :consumer_secret: consumer_secret_here diff --git a/src/lib/oauth_client.rb b/src/lib/oauth_client.rb new file mode 100644 index 0000000..8cc86ed --- /dev/null +++ b/src/lib/oauth_client.rb @@ -0,0 +1,62 @@ +class OAuthClient + require 'oauth' + + def initialize(resource) + @consumer = OAuth::Consumer.new( + consumer_key_for_resource(resource), + consumer_secret_for_resource(resource), + :site => resource + ) + @access_token = OAuth::AccessToken.new(@consumer) + end + + def authenticated_delete(uri, headers=nil) + headers ||= default_headers + @access_token.delete(uri, headers) + end + + def authenticated_get(uri, headers=nil) + headers ||= default_headers + @access_token.get(uri, headers) + end + + def authenticated_head(uri, headers=nil) + headers ||= default_headers + @access_token.head(uri, headers) + end + + def authenticated_post(uri, body='', headers=nil) + headers ||= default_headers + @access_token.post(uri, body, headers) + end + + def authenticated_put(uri, body='', headers=nil) + headers ||= default_headers + @access_token.put(uri, body, headers) + end + + private + + # Default headers - override in specific clients + def default_headers + nil + end + + def consumer_key_for_resource(resource) + @consumer_key ||= consumer_credentials_for_resource(resource)[:consumer_key] + end + + def consumer_secret_for_resource(resource) + @consumer_secret ||= consumer_credentials_for_resource(resource)[:consumer_secret] + end + + def consumer_credentials_for_resource(resource) + site_name = URI.parse(resource).host || resource + begin + SETTINGS_CONFIG[:oauth][site_name].reject{|k,v| ![:consumer_key, :consumer_secret].include?(k) } + rescue + raise "No credentials found in settings.yml for provider #{site_name}" + end + end + +end
aeolus-devel@lists.fedorahosted.org