signet-rails 0.0.8 → 0.0.9

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.
@@ -1,5 +1,5 @@
1
1
  module Signet
2
2
  module Rails
3
- VERSION = "0.0.8"
3
+ VERSION = "0.0.9"
4
4
  end
5
5
  end
@@ -2,18 +2,16 @@ module Signet
2
2
  module Rails
3
3
  module Wrappers
4
4
  class ActiveRecord
5
- def initialize obj, client
6
- @obj = obj
5
+ def initialize(credentials, client)
6
+ @credentials = credentials
7
7
  @client = client
8
8
  end
9
9
 
10
- attr_reader :obj
11
- attr_reader :client
10
+ attr_reader :credentials
11
+ attr_reader :client
12
12
 
13
13
  def persist
14
- if @obj.changed?
15
- @obj.save
16
- end
14
+ @credentials.save if @credentials.changed?
17
15
  end
18
16
  end
19
17
  end
@@ -4,22 +4,29 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'signet/rails/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "signet-rails"
7
+ spec.name = 'signet-rails'
8
8
  spec.version = Signet::Rails::VERSION
9
- spec.authors = ["Paul Jolly"]
10
- spec.email = ["paul@myitcv.org.uk"]
9
+ spec.authors = ['Paul Jolly']
10
+ spec.email = ['paul@myitcv.org.uk']
11
11
  spec.description = %q{A wrapper around the Google Signet OAuth Library}
12
12
  spec.summary = %q{Incorporate Signet goodness into Rails}
13
- spec.homepage = "https://github.com/myitcv/signet-rails"
14
- spec.license = "MIT"
13
+ spec.homepage = 'https://github.com/myitcv/signet-rails'
14
+ spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rake"
23
- spec.add_dependency "signet"
24
- spec.add_dependency "rack"
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'rake'
23
+ spec.add_development_dependency 'rspec', '~> 2.14.1'
24
+ spec.add_development_dependency 'sinatra'
25
+ spec.add_development_dependency 'factory_girl', '~> 4.2.0'
26
+ spec.add_development_dependency 'faraday', '~> 0.8.1'
27
+ spec.add_development_dependency 'activerecord'
28
+ spec.add_development_dependency 'sqlite3'
29
+ spec.add_development_dependency 'jwt'
30
+ spec.add_dependency 'signet', '~> 0.4.5'
31
+ spec.add_dependency 'rack', '>= 1.4.5'
25
32
  end
@@ -0,0 +1,11 @@
1
+ class FakeApp < Sinatra::Base
2
+ attr_accessor :callback
3
+ get '/' do
4
+ @callback.call env if @callback
5
+ 'Root'
6
+ end
7
+ get '/signet/google/auth_callback' do
8
+ @callback.call env if @callback
9
+ 'Auth Callback'
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ class User < ActiveRecord::Base
2
+ validates_uniqueness_of :uid
3
+ has_many :o_auth2_credentials, dependent: :destroy
4
+ end
5
+
6
+ class OAuth2Credential < ActiveRecord::Base
7
+ belongs_to :user
8
+ serialize :signet, Hash
9
+ validates_uniqueness_of :name, scope: :id
10
+ end
@@ -0,0 +1,181 @@
1
+ require 'spec_helper'
2
+ require 'securerandom'
3
+ require 'jwt'
4
+ require 'uri'
5
+ require 'faraday'
6
+ require 'sinatra/base'
7
+ require 'faraday/adapter/test'
8
+ require 'signet/rails'
9
+
10
+
11
+ describe Signet::Rails::Handler do
12
+
13
+ # creates a basic Rack stack with an instance of a Signet::Rails::Handler in place
14
+ #
15
+ # Top lightweight sinatra app for testing
16
+ # Rack::Lint
17
+ # Signet::Rails::Handler
18
+ # Rack:Lint
19
+ # Rack::Session::Cookie
20
+ # Bot Rack::Lint
21
+ #
22
+ def create_base_app opts = {}
23
+ app_1 = FakeApp.new
24
+ app_2 = Rack::Lint.new app_1
25
+ app_3 = Signet::Rails::Builder.new app_2 do
26
+ provider opts
27
+ end
28
+ app_4 = Rack::Lint.new app_3
29
+ app_5 = Rack::Session::Cookie.new app_4, secret: SecureRandom.hex(64)
30
+ app_6 = Rack::Lint.new app_5
31
+
32
+ # Sinatra wraps our top app... let's get it back out again
33
+ # for @top. See
34
+ # https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1448-L1456
35
+ @top = app_1.instance_variable_get :@instance
36
+
37
+ @base = app_6
38
+ @app_env = nil
39
+ @top.callback = lambda do |env|
40
+ @app_env = env
41
+ end
42
+ @req = request @base
43
+
44
+ @base
45
+ end
46
+
47
+ def req_get uri, env_opts = {}
48
+ @req.get uri, env(env_opts)
49
+ end
50
+
51
+ def create_login_app opts = {}
52
+ create_base_app opts.merge({type: :login})
53
+ end
54
+
55
+ DEFAULT_ENV = {
56
+ "SERVER_NAME" => "myitcv.org.uk",
57
+ "SERVER_PORT" => "4321"
58
+ }.freeze
59
+
60
+ def request app
61
+ req = Rack::MockRequest.new app
62
+ end
63
+
64
+ def env opts = {}
65
+ # a slight abuse of options that are passed to Rack::MockRequest.env_for
66
+ # we overload opts to also allow the setting of :cookie
67
+ # This option is stripped out if set and translated into an HTTP_COOKIE
68
+ # option
69
+ opts = opts.dup
70
+ if opts.include? :cookie
71
+ cookie = if options[:cookie].is_a?(Rack::Response)
72
+ options[:cookie]["Set-Cookie"]
73
+ else
74
+ options[:cookie]
75
+ end
76
+ opts.delete :cookie
77
+ opts["HTTP_COOKIE"] = cookie || ""
78
+ end
79
+ e = DEFAULT_ENV.dup.merge opts
80
+ end
81
+
82
+ before do
83
+ @faraday = Faraday.new do |builder|
84
+ builder.adapter :test do |stub|
85
+ stub.post('/o/oauth2/token') {
86
+ id_token = {"iss"=>"accounts.google.com", "aud"=>"id", "token_hash"=>"my_token_hash", "at_hash"=>"M0rVHD8aKqJRMwlpkWuvrw", "cid"=>"id", "azp"=>"id", "id"=>"myitcv", "sub"=>"105997489348527668257", "iat"=>12, "exp"=>42}
87
+ resp_body = { "access_token" => "my_access_token", "token_type" => "Bearer", "expires_in" => 1234, "id_token" => JWT.encode(id_token, 'secret'), "refresh_token" => "my_refresh_token" }
88
+ [ 200, {}, JSON.dump(resp_body) ]
89
+ }
90
+ end
91
+ end
92
+ end
93
+
94
+ # **********************************************
95
+
96
+ context 'that is login based' do
97
+
98
+ it 'should require a string client id' do
99
+ expect { create_login_app }.
100
+ to raise_error(ArgumentError, 'Client id is required for a type: :login provider')
101
+ end
102
+
103
+ it 'should require a scope to be defined' do
104
+ expect {create_login_app client_id: 'id'}.
105
+ to raise_error(ArgumentError, 'Scope is required')
106
+ end
107
+
108
+ it 'should require scope to be a(n array of) string(s)'
109
+ it 'should handle scope strings that contain commas'
110
+
111
+ it 'should handle untrimmed scope strings' do
112
+ create_login_app client_id: 'id', scope: ' test '
113
+ resp = req_get '/signet/google/auth'
114
+ redirect = URI 'https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=auto&client_id=id&redirect_uri=http://myitcv.org.uk:4321/signet/google/auth_callback&response_type=code&scope=test'
115
+ query_params = URI.decode_www_form redirect.query
116
+ scope_params = query_params.select { |p| p[0] == 'scope' }
117
+ expect(scope_params.length).to eq(1)
118
+ expect(scope_params[0][1]).to eq('test')
119
+ end
120
+
121
+ context 'with default arguments' do
122
+
123
+ it 'should redirect to google' do
124
+ create_login_app client_id: 'id', scope: 'test'
125
+ resp = req_get '/signet/google/auth'
126
+ expect(resp.body).to be_empty
127
+ expect(resp.original_headers['Location']).to eq('https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=auto&client_id=id&redirect_uri=http://myitcv.org.uk:4321/signet/google/auth_callback&response_type=code&scope=test')
128
+ end
129
+
130
+ it 'should redirect for an auth request'
131
+
132
+ it 'errors if rack.session is not available'
133
+
134
+ it 'should handle multiple scopes' do
135
+ create_login_app client_id: 'id', scope: ['test','trial']
136
+ resp = req_get '/signet/google/auth'
137
+ expect(resp.body).to be_empty
138
+ expect(resp.original_headers['Location']).to eq('https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=auto&client_id=id&redirect_uri=http://myitcv.org.uk:4321/signet/google/auth_callback&response_type=code&scope=test%20trial')
139
+ end
140
+
141
+ it 'should handle url scopes' do
142
+ create_login_app client_id: 'id', scope: ['https://www.googleapis.com/auth/userinfo.email']
143
+ resp = req_get '/signet/google/auth'
144
+ expect(resp.body).to be_empty
145
+ expect(resp.original_headers['Location']).to eq('https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=auto&client_id=id&redirect_uri=http://myitcv.org.uk:4321/signet/google/auth_callback&response_type=code&scope=https://www.googleapis.com/auth/userinfo.email')
146
+ end
147
+
148
+ it 'should require an auth_code on auth callback' do
149
+ create_login_app client_id: 'id', scope: 'scope'
150
+ expect { resp = req_get '/signet/google/auth_callback' }.
151
+ to raise_error(ArgumentError, 'Missing authorization code in auth_callback')
152
+ end
153
+
154
+ it 'should attempt to get an access_token on auth_callback' do
155
+ create_login_app client_id: 'id', scope: 'scope', connection: @faraday
156
+
157
+ # TODO this could be made stronger
158
+ @faraday.app.should_receive(:call).with(1).and_call_original
159
+ resp = req_get '/signet/google/auth_callback', params: {code: '123'}
160
+ credentials = @app_env['signet.google.persistence_obj']
161
+ expect(resp.body).to eq('Auth Callback')
162
+ expect(@app_env['signet.google']).to be_a(Signet::Rails::Handler)
163
+ expect(credentials).not_to be_nil
164
+ expect(credentials.signet).not_to be_nil
165
+ expect(credentials.signet['refresh_token']).to eq('my_refresh_token')
166
+ end
167
+ end
168
+ end
169
+ context 'that is google-based' do
170
+ it 'should redirect based on provider name' do
171
+ base, top = create_base_app name: :google, type: :login, client_id: 'id', client_secret: 456, scope: 'myscope'
172
+ req = request base
173
+ resp = req.get '/signet/google/auth'
174
+ end
175
+ end
176
+ it 'should be google-based'
177
+ it 'should test default options'
178
+ it 'should handle option :handle_auth_callback false'
179
+ it 'should handle multiple users'
180
+ end
181
+
@@ -0,0 +1,20 @@
1
+ require 'signet/rails'
2
+ require 'sinatra/base'
3
+ require 'factory_girl'
4
+ require 'faraday'
5
+ require 'faraday/adapter/test'
6
+ require 'securerandom'
7
+ require 'jwt'
8
+ require 'uri'
9
+
10
+ Dir[File.dirname(__FILE__)+"/support/*.rb"].each {|file| require file }
11
+ Dir[File.dirname(__FILE__)+"/*factory.rb"].each {|file| require file }
12
+ Dir[File.dirname(__FILE__)+"/factories/*.rb"].each {|file| require file }
13
+
14
+ RSpec.configure do |config|
15
+ config.treat_symbols_as_metadata_keys_with_true_values = true
16
+ config.run_all_when_everything_filtered = true
17
+ config.filter_run :focus
18
+ config.order = 'random'
19
+ end
20
+
@@ -0,0 +1,45 @@
1
+ require 'active_record'
2
+
3
+ ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
4
+
5
+ ActiveRecord::Migration.create_table :users do |t|
6
+ t.string :uid
7
+ t.timestamps
8
+ end
9
+
10
+ ActiveRecord::Migration.create_table :o_auth2_credentials do |t|
11
+ t.string :name
12
+ t.references :user, index: true
13
+ t.string :signet
14
+ t.timestamps
15
+ end
16
+
17
+ # http://iain.nl/testing-activerecord-in-isolation
18
+ module ActiveModel::Validations
19
+ # Extension to enhance `should have` on AR Model instances. Calls
20
+ # model.valid? in order to prepare the object's errors object.
21
+ #
22
+ # You can also use this to specify the content of the error messages.
23
+ #
24
+ # @example
25
+ #
26
+ # model.should have(:no).errors_on(:attribute)
27
+ # model.should have(1).error_on(:attribute)
28
+ # model.should have(n).errors_on(:attribute)
29
+ #
30
+ # model.errors_on(:attribute).should include("can't be blank")
31
+ def errors_on(attribute)
32
+ self.valid?
33
+ [self.errors[attribute]].flatten.compact
34
+ end
35
+ alias :error_on :errors_on
36
+ end
37
+
38
+ RSpec.configure do |config|
39
+ config.around do |example|
40
+ ActiveRecord::Base.transaction do
41
+ example.run
42
+ raise ActiveRecord::Rollback
43
+ end
44
+ end
45
+ end
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: signet-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
5
- prerelease:
4
+ version: 0.0.9
6
5
  platform: ruby
7
6
  authors:
8
7
  - Paul Jolly
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-08-27 00:00:00.000000000 Z
11
+ date: 2013-11-10 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
@@ -30,51 +27,143 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
- name: signet
42
+ name: rspec
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 2.14.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 2.14.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: sinatra
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
52
60
  - !ruby/object:Gem::Version
53
61
  version: '0'
54
- type: :runtime
62
+ type: :development
55
63
  prerelease: false
56
64
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
65
  requirements:
59
- - - ! '>='
66
+ - - '>='
60
67
  - !ruby/object:Gem::Version
61
68
  version: '0'
62
69
  - !ruby/object:Gem::Dependency
63
- name: rack
70
+ name: factory_girl
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 4.2.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 4.2.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: faraday
64
85
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
86
  requirements:
67
- - - ! '>='
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 0.8.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: 0.8.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: activerecord
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
68
102
  - !ruby/object:Gem::Version
69
103
  version: '0'
70
- type: :runtime
104
+ type: :development
71
105
  prerelease: false
72
106
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
107
  requirements:
75
- - - ! '>='
108
+ - - '>='
76
109
  - !ruby/object:Gem::Version
77
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: sqlite3
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: jwt
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: signet
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ~>
144
+ - !ruby/object:Gem::Version
145
+ version: 0.4.5
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ~>
151
+ - !ruby/object:Gem::Version
152
+ version: 0.4.5
153
+ - !ruby/object:Gem::Dependency
154
+ name: rack
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: 1.4.5
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: 1.4.5
78
167
  description: A wrapper around the Google Signet OAuth Library
79
168
  email:
80
169
  - paul@myitcv.org.uk
@@ -83,6 +172,8 @@ extensions: []
83
172
  extra_rdoc_files: []
84
173
  files:
85
174
  - .gitignore
175
+ - .rspec
176
+ - .rubocop.yml
86
177
  - Gemfile
87
178
  - LICENSE.txt
88
179
  - README.md
@@ -94,30 +185,39 @@ files:
94
185
  - lib/signet/rails/version.rb
95
186
  - lib/signet/rails/wrappers/active_record.rb
96
187
  - signet-rails.gemspec
97
- - tags
188
+ - spec/factories/fakeapp_factory.rb
189
+ - spec/factories/user_factory.rb
190
+ - spec/handler_spec.rb
191
+ - spec/spec_helper.rb
192
+ - spec/support/active_record.rb
98
193
  homepage: https://github.com/myitcv/signet-rails
99
194
  licenses:
100
195
  - MIT
196
+ metadata: {}
101
197
  post_install_message:
102
198
  rdoc_options: []
103
199
  require_paths:
104
200
  - lib
105
201
  required_ruby_version: !ruby/object:Gem::Requirement
106
- none: false
107
202
  requirements:
108
- - - ! '>='
203
+ - - '>='
109
204
  - !ruby/object:Gem::Version
110
205
  version: '0'
111
206
  required_rubygems_version: !ruby/object:Gem::Requirement
112
- none: false
113
207
  requirements:
114
- - - ! '>='
208
+ - - '>='
115
209
  - !ruby/object:Gem::Version
116
210
  version: '0'
117
211
  requirements: []
118
212
  rubyforge_project:
119
- rubygems_version: 1.8.23
213
+ rubygems_version: 2.0.3
120
214
  signing_key:
121
- specification_version: 3
215
+ specification_version: 4
122
216
  summary: Incorporate Signet goodness into Rails
123
- test_files: []
217
+ test_files:
218
+ - spec/factories/fakeapp_factory.rb
219
+ - spec/factories/user_factory.rb
220
+ - spec/handler_spec.rb
221
+ - spec/spec_helper.rb
222
+ - spec/support/active_record.rb
223
+ has_rdoc: