open_auth2 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,95 @@
1
+ module OpenAuth2
2
+
3
+ # Holds the info required to make a valid request to an OAuth server.
4
+ class Config
5
+ attr_accessor *Provider::Base::Keys
6
+ attr_reader :provider, :provider_const, :provider_string
7
+
8
+ # Use to set config info.
9
+ #
10
+ # Examples:
11
+ # OpenAuth2::Config.new do |c|
12
+ # c.provider = :default
13
+ # end
14
+ #
15
+ def initialize
16
+ set_default_as_provider
17
+ yield self if block_given?
18
+ end
19
+
20
+ # Use to set config info.
21
+ #
22
+ # Examples:
23
+ # config = OpenAuth2::Config.new
24
+ #
25
+ # config.configure do |c|
26
+ # c.provider = :google
27
+ # end
28
+ #
29
+ # Returns: self.
30
+ #
31
+ def configure
32
+ yield self if block_given?
33
+ end
34
+
35
+ # Finds provider's module & copies its Options key/value pairs.
36
+ #
37
+ # Accepts:
38
+ # name - String/Symbol/Constant.
39
+ #
40
+ def provider=(name)
41
+ set_provider_vars(name)
42
+ copy_provider_keys
43
+ end
44
+
45
+ # Removes all overwritten config & reset to default.
46
+ def reset_provider
47
+ remove_instance_vars
48
+ set_default_as_provider
49
+ end
50
+
51
+ def parse(response_body)
52
+ @provider_const.new.parse(self, response_body)
53
+ end
54
+
55
+ private
56
+
57
+ def set_default_as_provider
58
+ self.provider = :default
59
+ end
60
+
61
+ def set_provider_vars(name)
62
+ @provider = name
63
+ @provider_string = name.to_s
64
+ @provider_const = constantize_provider_string
65
+ end
66
+
67
+ def constantize_provider_string
68
+ provider_string = @provider_string.camelize
69
+ full_string = "OpenAuth2::Provider::#{provider_string}"
70
+
71
+ @provider_const = full_string.constantize
72
+ rescue NameError
73
+ raise UnknownProvider, "Known Providers: #{known_providers}"
74
+ end
75
+
76
+ def known_providers
77
+ known_providers = OpenAuth2::Provider.constants
78
+ known_providers.delete(:Base)
79
+
80
+ known_providers
81
+ end
82
+
83
+ def copy_provider_keys
84
+ @provider_const::new.options.each do |key,value|
85
+ instance_variable_set("@#{key}", value)
86
+ end
87
+ end
88
+
89
+ def remove_instance_vars
90
+ instance_variables.each do |var|
91
+ remove_instance_variable var
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,37 @@
1
+ module OpenAuth2
2
+
3
+ # Client/Token use this to make the actual requests to OAuth server.
4
+ # Since some OAuth servers have seperate endpoints for authorization
5
+ # & api requests, we use @faraday_url to store that info.
6
+ #
7
+ module Connection
8
+ def self.included(base)
9
+ base.class_eval do
10
+ attr_accessor :faraday_url
11
+ end
12
+ end
13
+
14
+ # Yields: Faraday object, so user can choose choose their own
15
+ # middleware.
16
+ #
17
+ # Examples:
18
+ # config = OpenAuth2::Config.new
19
+ # client = OpenAuth2::Client.new(config)
20
+ #
21
+ # client.connection do
22
+ # response :logger
23
+ # end
24
+ #
25
+ # Returns: Faraday object.
26
+ #
27
+ def connection(&blk)
28
+ @connection ||= Faraday.new(:url => @faraday_url) do |builder|
29
+ builder.request :url_encoded
30
+ builder.adapter :net_http
31
+ builder.instance_eval(&blk) if block_given?
32
+ end
33
+
34
+ @connection
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ module OpenAuth2
2
+
3
+ # Helper module that Client/Token extend so they can have access to
4
+ # Options methods. We delegate those methods to @config, which should
5
+ # contain Config object.
6
+ #
7
+ module DelegateToConfig
8
+ def self.extended(base)
9
+ base.send(:attr_accessor, :config)
10
+ base.delegate_to_config
11
+ end
12
+
13
+ def delegate_to_config
14
+ OpenAuth2::Provider::Base::Keys.each do |key|
15
+ define_method(key) do
16
+ @config.send(key)
17
+ end
18
+
19
+ define_method("#{key}=") do |value|
20
+ @config.send("#{key}=", value)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ module OpenAuth2
2
+ module Provider
3
+
4
+ # Contains all possible Options keys. Config uses this to define
5
+ # methods.
6
+ #
7
+ module Base
8
+ Keys = [
9
+ :client_id,
10
+ :client_secret,
11
+ :code,
12
+ :authorize_url,
13
+ :redirect_uri,
14
+ :code_url,
15
+ :authorize_path,
16
+ :token_path,
17
+ :access_token,
18
+ :refresh_token,
19
+ :response_type,
20
+ :access_token_grant_name,
21
+ :refresh_token_grant_name,
22
+ :refresh_token_name,
23
+ :scope,
24
+ :endpoint,
25
+ :path_prefix,
26
+ :token_expires_at,
27
+ :token_arrived_at,
28
+ ]
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,24 @@
1
+ module OpenAuth2
2
+ module Provider
3
+
4
+ # Contains the default Options, which is copied to Config on
5
+ # #initialize. We can then choose another provider or overwrite
6
+ # them individually.
7
+ #
8
+ class Default
9
+ def options
10
+ {
11
+ :response_type => 'code',
12
+ :access_token_grant_name => 'authorization_code',
13
+ :refresh_token_grant_name => 'refresh_token',
14
+ :refresh_token_name => :refresh_token,
15
+ :scope => [],
16
+ }
17
+ end
18
+
19
+ def parse(config, response_body)
20
+ response_body
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ module OpenAuth2
2
+ module Provider
3
+ class Facebook
4
+ def options
5
+ {
6
+ :authorize_url => 'https://graph.facebook.com',
7
+ :code_url => 'https://www.facebook.com',
8
+ :refresh_token_grant_name => 'fb_exchange_token',
9
+ :refresh_token_name => 'fb_exchange_token',
10
+ :authorize_path => '/dialog/oauth',
11
+ :token_path => 'oauth/access_token',
12
+ :endpoint => 'https://graph.facebook.com'
13
+ }
14
+ end
15
+
16
+ def parse(config, response_body)
17
+ access_token = response_body.gsub('access_token=', '')
18
+ config.access_token = access_token
19
+ config.refresh_token = access_token
20
+ config.token_arrived_at = Time.now
21
+ config.token_expires_at = "60 days?"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+ module OpenAuth2
2
+ module Provider
3
+ class Google
4
+ def options
5
+ {
6
+ :authorize_url => 'https://accounts.google.com',
7
+ :code_url => 'https://accounts.google.com',
8
+ :authorize_path => '/o/oauth2/auth',
9
+ :redirect_uri => 'http://localhost:9393/google/callback',
10
+ :token_path => '/o/oauth2/token',
11
+ :endpoint => 'https://www.googleapis.com'
12
+ }
13
+ end
14
+
15
+ def parse(config, body)
16
+ json = JSON.parse(body)
17
+
18
+ config.access_token = json['access_token']
19
+ config.token_arrived_at = Time.now
20
+ config.token_expires_at = Time.now+3600
21
+
22
+ # google sends refresh_token when getting access_token, but not
23
+ # when refreshing
24
+ unless config.refresh_token
25
+ config.refresh_token = json['refresh_token']
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ # Contains various providers & their config info stored in Options hash.
2
+ # When user sets a provider, we copy over its Options to Config.
3
+ #
4
+ # The reason for this setup is b/c various OAuth servers accept &
5
+ # return different options & values. This way users can contribute
6
+ # their own providers, i.e. a very simple plugin system.
7
+ #
8
+ # Acceptable providers are modules defined under OpenAuth2::Provider,
9
+ # have Options hash.
10
+ #
11
+ # Examples:
12
+ # module OpenAuth2::Providers::YourProviderName
13
+ # Options = {
14
+ # :authorize_url => 'https://your_provider_name.com'
15
+ # }
16
+ # end
17
+ #
18
+ module OpenAuth2
19
+ module Provider
20
+ end
21
+ end
@@ -0,0 +1,126 @@
1
+ require_relative 'client'
2
+
3
+ module OpenAuth2
4
+
5
+ # Gets Access/Refresh tokens from OAuth server.
6
+ class Token < Client
7
+ def initialize(config)
8
+ @config = config
9
+ @faraday_url = authorize_url
10
+ end
11
+
12
+ # Packages info from config & passed in arguments into an url that
13
+ # user can to visit to authorize this app.
14
+ #
15
+ # Examples:
16
+ # token.build_code_url
17
+ # #=> 'http://...'
18
+ #
19
+ # # or
20
+ # token.build_code_url(:scope => 'publish_stream')
21
+ #
22
+ # Accepts:
23
+ # params - (optional) Hash of additional config.
24
+ #
25
+ # Returns: String (url).
26
+ #
27
+ def build_code_url(params={})
28
+ url = URI::HTTPS.build(:host => host,
29
+ :path => authorize_path,
30
+ :query => encoded_body(params))
31
+ url.to_s
32
+ end
33
+
34
+ # Makes request to OAuth server for access token & parses it by
35
+ # delegating to the appropriate provider.
36
+ #
37
+ # Accepts:
38
+ # params - (optional) Hash of additional config to be sent with
39
+ # request.
40
+ #
41
+ def get(params={})
42
+ body = get_body_hash(params)
43
+ raw_request = post(body)
44
+
45
+ parse(raw_request)
46
+ end
47
+
48
+ # Makes request to OAuth server to refresh the access token.
49
+ #
50
+ # Accepts:
51
+ # params - (optional) Hash of additional config to be sent with
52
+ # request.
53
+ #
54
+ def refresh(params={})
55
+ body = refresh_body_hash(params)
56
+ raw_request = post(body)
57
+
58
+ parse(raw_request)
59
+ end
60
+
61
+ def token_expired?
62
+ token_expires_at > Time.now
63
+ rescue
64
+ nil
65
+ end
66
+
67
+ private
68
+
69
+ # We use URI#parse to get rid of those pesky extra /.
70
+ def host
71
+ URI.parse(code_url).host
72
+ end
73
+
74
+ def encoded_body(params)
75
+ URI.encode_www_form(url_body_hash(params))
76
+ end
77
+
78
+ # Combine default options & user arguments.
79
+ def url_body_hash(params)
80
+
81
+ # user can define scope as String or Array
82
+ joined_scope = scope.join(',') if scope.respond_to?(:join)
83
+
84
+ {
85
+ :response_type => response_type,
86
+ :client_id => client_id,
87
+ :redirect_uri => redirect_uri,
88
+ :scope => joined_scope
89
+ }.merge(params)
90
+ end
91
+
92
+ def get_body_hash(params)
93
+ {
94
+ :client_id => client_id,
95
+ :client_secret => client_secret,
96
+ :code => code,
97
+ :grant_type => access_token_grant_name,
98
+ :redirect_uri => redirect_uri
99
+ }.merge(params)
100
+ end
101
+
102
+ def refresh_body_hash(params)
103
+ {
104
+ :client_id => client_id,
105
+ :client_secret => client_secret,
106
+ :grant_type => refresh_token_grant_name,
107
+ refresh_token_name => refresh_token
108
+ }.merge(params)
109
+ end
110
+
111
+ # Makes the actual request. `connection` is a Faraday object.
112
+ def post(body)
113
+ connection.post do |conn|
114
+ conn.headers["Content-Type"] = "application/x-www-form-urlencoded"
115
+ conn.headers["Accept"] = "application/json"
116
+ conn.url(token_path)
117
+ conn.body = body
118
+ end
119
+ end
120
+
121
+ def parse(response)
122
+ @config.parse(response.body)
123
+ response
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,3 @@
1
+ module OpenAuth2
2
+ VERSION = '0.0.8'
3
+ end
data/lib/open_auth2.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'active_support/inflector'
2
+ require 'faraday'
3
+ require 'uri'
4
+ require 'json'
5
+
6
+ require_relative 'open_auth2/provider'
7
+ require_relative 'open_auth2/provider/base'
8
+ require_relative 'open_auth2/provider/default'
9
+ require_relative 'open_auth2/provider/facebook'
10
+ require_relative 'open_auth2/provider/google'
11
+
12
+ require_relative 'open_auth2/delegate_to_config'
13
+ require_relative 'open_auth2/config'
14
+ #require_relative 'open_auth2/config'
15
+ require_relative 'open_auth2/connection'
16
+ require_relative 'open_auth2/token'
17
+ require_relative 'open_auth2/client'
18
+
19
+ require_relative 'open_auth2/version'
20
+
21
+ module OpenAuth2
22
+ class UnknownProvider < StandardError; end
23
+ end
@@ -0,0 +1,80 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require './lib/open_auth2/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "open_auth2"
6
+ s.version = OpenAuth2::VERSION
7
+ s.authors = ["sent-hil"]
8
+ s.email = ["me@sent-hil.com"]
9
+ s.homepage = "https://github.com/sent-hil/OpenAuth2"
10
+ s.description = %q{OpenAuth2 is a simple OAuth2 client.}
11
+ s.summary = %q{OpenAuth2 is a simple OAuth2 client written on top of Faraday in Ruby. The goal is a simple, well documented, easy to use interface for all your OAuth2 needs.}
12
+
13
+ s.rubyforge_project = "OpenAuth2"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- spec/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map do |f|
18
+ File.basename(f)
19
+ end
20
+
21
+ s.require_paths = ["lib"]
22
+
23
+ s.add_dependency 'faraday', '~> 0.7'
24
+ s.add_dependency 'activesupport', '~> 3.1'
25
+ s.add_dependency 'json'
26
+
27
+ if RUBY_PLATFORM == 'java'
28
+ s.add_dependency 'json'
29
+ s.add_dependency 'jruby-openssl'
30
+ end
31
+
32
+ s.add_development_dependency 'rake', '~> 0.9'
33
+ s.add_development_dependency 'rspec', '~> 2.8'
34
+ s.add_development_dependency 'vcr', '1.11.3'
35
+ s.add_development_dependency 'fakeweb', '~> 1.3'
36
+ s.add_development_dependency 'timecop', '~> 0.3'
37
+
38
+ # = MANIFEST =
39
+ s.files = %w[
40
+ Gemfile
41
+ License
42
+ Rakefile
43
+ Readme.markdown
44
+ Spec.markdown
45
+ examples/fb.rb
46
+ examples/google.rb
47
+ lib/open_auth2.rb
48
+ lib/open_auth2/client.rb
49
+ lib/open_auth2/config.rb
50
+ lib/open_auth2/connection.rb
51
+ lib/open_auth2/delegate_to_config.rb
52
+ lib/open_auth2/provider.rb
53
+ lib/open_auth2/provider/base.rb
54
+ lib/open_auth2/provider/default.rb
55
+ lib/open_auth2/provider/facebook.rb
56
+ lib/open_auth2/provider/google.rb
57
+ lib/open_auth2/token.rb
58
+ lib/open_auth2/version.rb
59
+ open_auth2.gemspec
60
+ spec/client_spec.rb
61
+ spec/config_spec.rb
62
+ spec/facebook/client_spec.rb
63
+ spec/facebook/token_spec.rb
64
+ spec/fixtures/creds.rb
65
+ spec/fixtures/vcr/fb/access_token.yml
66
+ spec/fixtures/vcr/fb/cocacola.yml
67
+ spec/fixtures/vcr/fb/me.yml
68
+ spec/fixtures/vcr/fb/post.yml
69
+ spec/fixtures/vcr/fb/refresh_token.yml
70
+ spec/fixtures/vcr/goog/access_token.yml
71
+ spec/fixtures/vcr/goog/list.yml
72
+ spec/fixtures/vcr/goog/post.yml
73
+ spec/fixtures/vcr/goog/refresh_token.yml
74
+ spec/google/client_spec.rb
75
+ spec/google/token_spec.rb
76
+ spec/spec_helper.rb
77
+ spec/token_spec.rb
78
+ ]
79
+ # = MANIFEST =
80
+ end
@@ -0,0 +1,92 @@
1
+ require 'open_auth2'
2
+ require 'spec_helper'
3
+
4
+ describe OpenAuth2::Client do
5
+ let(:config) do
6
+ OpenAuth2::Config.new do |c|
7
+ c.provider = :facebook
8
+ c.access_token = :access_token
9
+ end
10
+ end
11
+
12
+ subject do
13
+ described_class.new(config)
14
+ end
15
+
16
+ context '#initialize' do
17
+ it 'accepts config as an argument' do
18
+ subject.config.should == config
19
+ end
20
+
21
+ it 'accepts config via block' do
22
+ subject = described_class.new do |c|
23
+ c.config = config
24
+ end
25
+
26
+ subject.config.should == config
27
+ end
28
+
29
+ it 'sets endpoint to make requests' do
30
+ subject.faraday_url.should == 'https://graph.facebook.com'
31
+ end
32
+ end
33
+
34
+ context '#configure' do
35
+ it 'accepts a block to set/overwrite config' do
36
+ subject.configure do |c|
37
+ c.access_token = :access_token
38
+ c.refresh_token = :refresh_token
39
+ end
40
+
41
+ subject.access_token.should == :access_token
42
+ subject.refresh_token.should == :refresh_token
43
+ end
44
+ end
45
+
46
+ context '#token' do
47
+ it 'returns OpenAuth2::Token object' do
48
+ subject.token.should be_an(OpenAuth2::Token)
49
+ end
50
+ end
51
+
52
+ context '#build_code_url' do
53
+ it 'delegates to OpenAuth2::Token' do
54
+ OpenAuth2::Token.any_instance.should_receive(:build_code_url)
55
+ subject.build_code_url
56
+ end
57
+ end
58
+
59
+ subject { described_class.new(config) }
60
+
61
+ context OpenAuth2::DelegateToConfig do
62
+ it 'delegates Options getter methods' do
63
+ subject.authorize_url.should == 'https://graph.facebook.com'
64
+ end
65
+
66
+ it 'delegates Options setter methods' do
67
+ url = 'http://facebook.com'
68
+ subject.authorize_url = url
69
+
70
+ subject.authorize_url.should == url
71
+ end
72
+
73
+ it 'overwritten Options stays that way' do
74
+ config.access_token.should == :access_token
75
+ end
76
+ end
77
+
78
+ context OpenAuth2::Connection do
79
+ it 'returns Faraday object' do
80
+ subject.connection.should be_a(Faraday::Connection)
81
+ end
82
+
83
+ it 'allows adding custom middleware to Faraday' do
84
+ subject.connection do
85
+ response :logger
86
+ end
87
+
88
+ subject.connection.builder.handlers.should
89
+ include(Faraday::Response::Logger)
90
+ end
91
+ end
92
+ end