signet-rails 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -28,6 +28,30 @@ $ gem install signet-rails
28
28
 
29
29
  TODO: Write usage instructions here
30
30
 
31
+ ## TODO
32
+
33
+ A list of items still todo or work in progress
34
+
35
+ 0. Give an example usage
36
+ * Example of setting default options
37
+ * Example of setting per provider options
38
+ * Clearly document default `extract\_from\_env`
39
+ * Clearly document default `extract\_by\_oauth\_id`
40
+ 1. Is there a better (Rails) way to creating per-request instances of signet OAuth clients?
41
+ 2. Currently use the env variable to store the handlers and references to the instances... is this thread safe (probably) and the best way (probably not)?
42
+ 3. Better way of sourcing the Google default authorization_uri and token_credential_uri? From signet directly?
43
+ 4. Clear definition of the Signet options and the `signet-rails` options
44
+ 5. More Rails-esque way of getting the `rack.session` in `extract\_from\_env`?
45
+ 6. Better way of loading persistance wrappers in builder?
46
+ 7. Check to see whether we have all required signet options at the end of Builder.provder?
47
+ 8. Sort out `approval\_prompt` vs 'prompt'
48
+ 9. Better `auth\_options` split at the end of Builder.provider?
49
+ 10. Avoid having to dup options the whole time: fix signet?
50
+ 11. Refactor Handler.handle code... messy
51
+ 12. Document handling of callback in Rails
52
+ 13. Error handling...
53
+ 14. Document the various `env` values that can/will be set and when (e.g. `signet.XXX.persistance\_obj` on `auth\_callback`)
54
+
31
55
  ## Contributing
32
56
 
33
57
  1. Fork it
@@ -1,5 +1,5 @@
1
1
  require 'signet/rails'
2
- require 'signet/rails/wrappers/active_record'
2
+ require 'active_support/core_ext/string'
3
3
 
4
4
  module Signet
5
5
  module Rails
@@ -7,7 +7,7 @@ module Signet
7
7
  @@default_options = {}
8
8
 
9
9
  def self.set_default_options opts = {}
10
- # normalize to symbol version
10
+ # normalize to symbol hash
11
11
  n_opts = opts.inject({}) { |memo,(k,v)| memo[k.to_sym] = v; memo }
12
12
  @@default_options = n_opts
13
13
  end
@@ -17,17 +17,31 @@ module Signet
17
17
  end
18
18
 
19
19
  def provider(opts = {}, &block)
20
- # normalize to symbol version
20
+ # normalize to symbol hash
21
21
  n_opts = opts.inject({}) { |memo,(k,v)| memo[k.to_sym] = v; memo }
22
+
23
+ # use the default_options as a base... then merge these changes on top
22
24
  combined_options = @@default_options.merge(n_opts)
23
25
 
24
26
  # now set some defaults if they aren't already set
25
- combined_options[:persist] ||= [:refresh_token, :access_token, :expires_in, :issued_at]
27
+
28
+ combined_options[:persist_attrs] ||= [:refresh_token, :access_token, :expires_in, :issued_at]
26
29
  combined_options[:name] ||= :google
30
+
31
+ # TODO: see https://developers.google.com/accounts/docs/OAuth2Login#authenticationuriparameters
27
32
  combined_options[:approval_prompt] ||= 'auto'
28
- combined_options[:redirect_uri] = "http://localhost:3000/signet/#{combined_options[:name]}/callback"
29
- combined_options[:authorization_uri] = 'https://accounts.google.com/o/oauth2/auth'
30
- combined_options[:token_credential_uri] = 'https://accounts.google.com/o/oauth2/token'
33
+
34
+ # unless specified, we need to set this at request-time because we need the env to get server etc
35
+ # combined_options[:redirect_uri] = ??? need env
36
+
37
+ # TODO: better way of sourcing these defaults... from signet?
38
+ combined_options[:authorization_uri] ||= 'https://accounts.google.com/o/oauth2/auth'
39
+ combined_options[:token_credential_uri] ||= 'https://accounts.google.com/o/oauth2/token'
40
+
41
+ # whether we handle the persistance of the auth callback or simply pass-through
42
+ combined_options[:handle_auth_callback] ||= true
43
+
44
+ # method to get the persistance object when creating a client via the factory
31
45
  combined_options[:extract_from_env] ||= lambda do |env, client|
32
46
  u = nil
33
47
  session = env['rack.session']
@@ -39,7 +53,8 @@ module Signet
39
53
  end
40
54
  u
41
55
  end
42
- combined_options[:handle_callback] ||= true
56
+
57
+ # when on an auth_callback, how do we get the persistance object from the id?
43
58
  combined_options[:extract_by_oauth_id] ||= lambda do |id, client|
44
59
  u = nil
45
60
  begin
@@ -51,19 +66,27 @@ module Signet
51
66
  u
52
67
  end
53
68
 
54
- def active_record_wrapper meth
69
+ combined_options[:persistance_wrapper] ||= :active_record
70
+ persistance_wrapper = lambda do |meth|
55
71
  lambda do |context, client|
56
72
  y = meth.call context, client
57
- w = Signet::Rails::Wrappers::ActiveRecord.new y, client
73
+ klass_str = combined_options[:persistance_wrapper].to_s
74
+ require "signet/rails/wrappers/#{klass_str}"
75
+ w = "Signet::Rails::Wrappers::#{klass_str.camelize}".constantize.new y, client
58
76
  end
59
77
  end
60
78
 
61
- combined_options[:extract_by_oauth_id] = active_record_wrapper combined_options[:extract_by_oauth_id]
62
- combined_options[:extract_from_env] = active_record_wrapper combined_options[:extract_from_env]
79
+ combined_options[:extract_by_oauth_id] = persistance_wrapper.call combined_options[:extract_by_oauth_id]
80
+ combined_options[:extract_from_env] = persistance_wrapper.call combined_options[:extract_from_env]
63
81
 
64
82
  # TODO: check here we have the basics?
83
+
84
+ # TODO: better auth_options split?
85
+ auth_option_keys = [:prompt, :redirect_uri, :access_type, :approval_prompt, :client_id]
86
+ base_options = combined_options
87
+ auth_options = base_options.select { |k,v| auth_option_keys.include? k }
65
88
 
66
- use Signet::Rails::Handler, combined_options, &block
89
+ use Signet::Rails::Handler, base_options, auth_options, &block
67
90
  end
68
91
 
69
92
  def call(env)
@@ -5,19 +5,25 @@ module Signet
5
5
 
6
6
  class Factory
7
7
  def self.create_from_env name, env, opt_hsh = {load_token: true}
8
- # rework this to use singleton?
9
- handler = env["signet.#{name.to_s}"]
10
8
 
11
- client = Signet::OAuth2::Client.new handler.options
9
+ # TODO: thread safe? best approach? Other uses below
10
+ client = env["signet.#{name.to_s}.instance"]
12
11
 
13
- if opt_hsh[:load_token]
14
- obj = handler.options[:extract_from_env].call env, client
15
- handler.load_token_state obj, client
12
+ return client if !!client
13
+
14
+ # TODO: again, not pretty...
15
+ handler = env["signet.#{name.to_s}"]
16
16
 
17
- env["signet.#{name.to_s}.instance"] = obj
18
- end
17
+ client = Signet::OAuth2::Client.new handler.options
19
18
 
20
- client
19
+ if opt_hsh[:load_token]
20
+ obj = handler.options[:extract_from_env].call env, client
21
+ handler.load_token_state obj, client
22
+
23
+ env["signet.#{name.to_s}.instance"] = obj
24
+ end
25
+
26
+ client
21
27
  end
22
28
  end
23
29
  end
@@ -5,52 +5,69 @@ require 'rack/utils'
5
5
  module Signet
6
6
  module Rails
7
7
  class Handler
8
- def initialize(app, opts = {}, &block)
8
+ def initialize(app, opts = {}, auth_opts = {}, &block)
9
9
  @app = app
10
10
  @options = opts
11
+ @auth_options = auth_opts
11
12
  end
12
13
 
13
14
  def options
14
- @options
15
+ # TODO: this is because signet doesn't dup what we pass in....
16
+ @options.dup
17
+ end
18
+
19
+ def auth_options env
20
+ # TODO: this is because signet doesn't dup what we pass in....
21
+ ret = @auth_options.dup
22
+ unless ret.include? :redirect_uri
23
+ req = Rack::Request.new env
24
+ scheme = req.ssl? ? 'https' : 'http'
25
+ ret[:redirect_uri] = "#{scheme}://#{req.host_with_port}/signet/#{options[:name]}/auth_callback"
26
+ end
27
+ ret
15
28
  end
16
29
 
17
30
  def handle(env)
18
31
 
19
- if "/signet/#{@options[:name]}/login" == env['PATH_INFO'] && 'GET' == env['REQUEST_METHOD']
20
- client = Factory.create_from_env @options[:name], env
21
- r = Rack::Response.new
32
+ # set these to 'handle' the request
33
+ status = headers = body = nil
22
34
 
23
- # TODO: a better way of filtering down to the auth options
24
- auth_options_whitelist = [:approval_prompt]
25
- auth_options = @options.select { |k,_| auth_options_whitelist.include?(k) }
26
- redirect_uri = client.authorization_uri(auth_options).to_s
35
+ # TODO: better way than a gross if elsif block?
36
+ if "/signet/#{options[:name]}/auth" == env['PATH_INFO'] && 'GET' == env['REQUEST_METHOD']
37
+
38
+ # we are looking to auth... so nothing to load
39
+ client = Factory.create_from_env options[:name], env, load_token: false
40
+
41
+ r = Rack::Response.new
42
+ redirect_uri = client.authorization_uri(auth_options(env)).to_s
27
43
  r.redirect(redirect_uri)
28
- r.finish
29
- elsif "/signet/#{@options[:name]}/callback" == env['PATH_INFO']
30
- client = Factory.create_from_env @options[:name], env, load_token: false
44
+ status, headers, body = r.finish
45
+ elsif "/signet/#{options[:name]}/auth_callback" == env['PATH_INFO'] && 'GET' == env['REQUEST_METHOD']
46
+ client = Factory.create_from_env options[:name], env, load_token: false
31
47
  query_string_params = Rack::Utils.parse_query(env['QUERY_STRING'])
32
48
  client.code = query_string_params['code']
33
- fat = client.fetch_access_token!
49
+ client.redirect_uri = auth_options(env)[:redirect_uri]
50
+ client.fetch_access_token!
34
51
 
35
- if @options[:handle_callback]
36
- # try to get the token store
37
- obj = @options[:extract_by_oauth_id].call client.decoded_id_token['id'], client
52
+ if options[:handle_auth_callback]
53
+ # TODO: remove
54
+ puts '******************************************'
55
+ puts client.decoded_id_token.inspect
56
+
57
+ obj = options[:extract_by_oauth_id].call client.decoded_id_token['id'], client
38
58
  persist_token_state obj, client
39
59
  obj.persist
40
- env["signet.#{options[:name]}.obj"] = obj.obj
41
-
60
+ env["signet.#{options[:name]}.persistance_obj"] = obj.obj
42
61
  else
43
- # pass this on for handling by the rails app
44
- env["signet.#{options[:name]}.client"] = client
45
-
62
+ env["signet.#{options[:name]}.auth_client"] = client
46
63
  end
47
-
48
- [nil,nil,nil]
49
64
  end
65
+
66
+ [status, headers, body]
50
67
  end
51
68
 
52
69
  def persist_token_state wrapper, client
53
- for i in @options[:persist]
70
+ for i in options[:persist_attrs]
54
71
  if client.respond_to?(i) && wrapper.obj.respond_to?(i.to_s+'=')
55
72
  wrapper.obj.method(i.to_s+'=').call(client.method(i).call)
56
73
  end
@@ -58,7 +75,7 @@ module Signet
58
75
  end
59
76
 
60
77
  def load_token_state wrapper, client
61
- for i in @options[:persist]
78
+ for i in options[:persist_attrs]
62
79
  if wrapper.obj.respond_to?(i) && client.respond_to?(i.to_s+'=')
63
80
  client.method(i.to_s+'=').call(wrapper.obj.method(i).call)
64
81
  end
@@ -67,15 +84,15 @@ module Signet
67
84
 
68
85
  def call(env)
69
86
  # rework this to use singleton?
70
- env["signet.#{@options[:name]}"] = self
87
+ env["signet.#{options[:name]}"] = self
71
88
 
72
89
  status, headers, body = handle(env)
73
-
90
+
74
91
  unless status
75
92
 
76
93
  status, headers, body = @app.call(env)
77
94
 
78
- obj = env["signet.#{@options[:name]}.instance"]
95
+ obj = env["signet.#{options[:name]}.instance"]
79
96
  if !!obj
80
97
  obj.persist
81
98
  end
@@ -84,7 +101,6 @@ module Signet
84
101
 
85
102
  [status, headers, body]
86
103
  end
87
-
88
104
  end
89
105
  end
90
106
  end
@@ -1,5 +1,5 @@
1
1
  module Signet
2
2
  module Rails
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  end
@@ -2,20 +2,20 @@ module Signet
2
2
  module Rails
3
3
  module Wrappers
4
4
  class ActiveRecord
5
- def initialize obj, client
6
- @obj = obj
7
- @client = client
8
- end
5
+ def initialize obj, client
6
+ @obj = obj
7
+ @client = client
8
+ end
9
9
 
10
- def obj
11
- @obj
12
- end
10
+ def obj
11
+ @obj
12
+ end
13
13
 
14
- def persist
15
- if @obj.changed?
16
- @obj.save
17
- end
18
- end
14
+ def persist
15
+ if @obj.changed?
16
+ @obj.save
17
+ end
18
+ end
19
19
  end
20
20
  end
21
21
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: signet-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: