sso 0.1.0.beta2 → 0.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4c53a1e9c7573ea3d6e97727aa00e435c485b3d7
4
- data.tar.gz: ff596d704a4e53c462d45251d64108cb85918d0f
3
+ metadata.gz: 3427c7a74fc824e4a590aae4dedb206cd0c3f89c
4
+ data.tar.gz: 13355ce7e47c5088774fc5608b453dee91578136
5
5
  SHA512:
6
- metadata.gz: 4399983b1f108c80f30c497f5db66d406c95168271fcaa5c559e6b8b22f4ae99772b721db7b4e325694b896b29ef16e48a8cbc6a17e7df06d00df62ad5c87393
7
- data.tar.gz: 2895cdf553890ae507ca160e5f40afc6b5c098ac461a1cf458bd1e7d73befcd4232c476fa5570e2e9e369fdadcbc2fd8737a9cb64eb66f9af995e9a2727a8191
6
+ metadata.gz: 976e470dbb0a78ac0184a6a5d4381af04008cf158516d4b9106b08ad3eb2865257e6da196ba4affdd4e2318e50bb1f4aeed67e5b8fd6c47c4b2a8bfe1c96b5ff
7
+ data.tar.gz: c4cf08a461736d1df4ff3ff88a69fa6c424354cfe1739d6e561839b3f7f9798484cc75b86e20e48f0d7556441e4bb71757c033efd0deb0dbafcdb7868392fd18
@@ -1,4 +1,5 @@
1
1
  module SSO
2
+ # Helper to log results of benchmarks.
2
3
  module Benchmarking
3
4
  include ::SSO::Logging
4
5
 
@@ -1,6 +1,7 @@
1
1
  module SSO
2
2
  module Client
3
3
  module Authentications
4
+ # Logic to authenticate a Passport provided by an outsider app to an insider app.
4
5
  class Passport
5
6
  include ::SSO::Logging
6
7
  include ::SSO::Benchmarking
@@ -12,11 +13,11 @@ module SSO
12
13
  end
13
14
 
14
15
  def authenticate
15
- debug { "Performing authentication..." }
16
+ debug { 'Performing authentication...' }
16
17
  result = authenticate!
17
18
 
18
19
  if result.success?
19
- debug { "Authentication succeeded." }
20
+ debug { 'Authentication succeeded.' }
20
21
  return result
21
22
  end
22
23
 
@@ -65,7 +66,18 @@ module SSO
65
66
  end
66
67
 
67
68
  def verifier
68
- ::SSO::Client::PassportVerifier.new passport_id: passport_id, passport_state: 'refresh', passport_secret: chip_passport_secret, user_ip: ip, user_agent: agent, device_id: device_id
69
+ ::SSO::Client::PassportVerifier.new verifier_options
70
+ end
71
+
72
+ def verifier_options
73
+ {
74
+ passport_id: passport_id,
75
+ passport_state: 'refresh',
76
+ passport_secret: chip_passport_secret,
77
+ user_ip: ip,
78
+ user_agent: agent,
79
+ device_id: device_id,
80
+ }
69
81
  end
70
82
 
71
83
  def verification
@@ -78,7 +90,7 @@ module SSO
78
90
  end
79
91
 
80
92
  def signature_request
81
- debug { "Verifying signature of #{request.request_method.inspect} #{request.path.inspect} #{request.params.inspect}"}
93
+ debug { "Verifying signature of #{request.request_method.inspect} #{request.path.inspect} #{request.params.inspect}" }
82
94
  ::Signature::Request.new request.request_method, request.path, request.params
83
95
  end
84
96
 
@@ -93,7 +105,7 @@ module SSO
93
105
  end
94
106
 
95
107
  def chip_decryption
96
- debug { "Validating chip decryptability of raw chip #{chip.inspect}"}
108
+ debug { "Validating chip decryptability of raw chip #{chip.inspect}" }
97
109
  yield Operations.failure(:missing_chip, object: params) if chip.blank?
98
110
  yield Operations.failure(:missing_chip_key) unless chip_key
99
111
  yield Operations.failure(:missing_chip_iv) unless chip_iv
@@ -115,7 +127,7 @@ module SSO
115
127
  decipher.key = chip_key
116
128
  decipher.iv = chip_iv
117
129
  plaintext = decipher.update(chip_ciphertext) + decipher.final
118
- logger.debug { "Decryptied chip plaintext #{plaintext.inspect} using key #{chip_key.inspect} and iv #{chip_iv.inspect} and ciphertext #{chip_ciphertext.inspect}"}
130
+ logger.debug { "Decryptied chip plaintext #{plaintext.inspect} using key #{chip_key.inspect} and iv #{chip_iv.inspect} and ciphertext #{chip_ciphertext.inspect}" }
119
131
  plaintext
120
132
  end
121
133
  end
@@ -130,12 +142,12 @@ module SSO
130
142
 
131
143
  def chip_belongs_to_passport?
132
144
  unless passport_id
133
- debug { "Unknown passport_id" }
145
+ debug { 'Unknown passport_id' }
134
146
  return false
135
147
  end
136
148
 
137
149
  unless chip_passport_id
138
- debug { "Unknown passport_id" }
150
+ debug { 'Unknown passport_id' }
139
151
  return false
140
152
  end
141
153
 
@@ -180,15 +192,11 @@ module SSO
180
192
  params['passport_chip']
181
193
  end
182
194
 
183
- #def warden
184
- # request.env['warden']
185
- #end
186
-
187
195
  def chip_digest
188
196
  ::OpenSSL::Cipher::AES256.new :CBC
189
197
  end
190
198
 
191
- # TODO Use ActionDispatch remote IP or you might get the Load Balancer's IP instead :(
199
+ # TODO: Use ActionDispatch::Request#remote_ip
192
200
  def ip
193
201
  request.ip
194
202
  end
@@ -15,7 +15,7 @@ module SSO
15
15
  end
16
16
 
17
17
  def call
18
- get_response { |failure| return failure }
18
+ fetch_response { |failure| return failure }
19
19
  interpret_response
20
20
 
21
21
  rescue JSON::ParserError
@@ -25,7 +25,7 @@ module SSO
25
25
 
26
26
  private
27
27
 
28
- def get_response
28
+ def fetch_response
29
29
  yield Operations.failure(:server_unreachable, object: response) unless response.code == 200
30
30
  yield Operations.failure(:server_response_not_parseable, object: response) unless parsed_response
31
31
  yield Operations.failure(:server_response_missing_success_flag, object: response) unless response_has_success_flag?
data/lib/sso/server.rb CHANGED
@@ -10,7 +10,6 @@ require 'sso'
10
10
  require 'sso/server/errors'
11
11
  require 'sso/server/passport'
12
12
  require 'sso/server/passports'
13
- require 'sso/server/geolocations'
14
13
  require 'sso/server/engine'
15
14
 
16
15
  require 'sso/server/authentications/passport'
@@ -57,7 +57,10 @@ module SSO
57
57
  def environment
58
58
  @environment ||= default_environment
59
59
  end
60
- attr_writer :environment
60
+
61
+ def environment=(new_environment)
62
+ @environment = new_environment.to_s
63
+ end
61
64
 
62
65
  private
63
66
 
@@ -92,14 +95,13 @@ module SSO
92
95
  end
93
96
 
94
97
  def default_human_readable_location_for_ip
95
- proc do
98
+ proc do |ip|
96
99
  'Unknown'
97
100
  end
98
101
  end
99
102
 
100
103
  def default_session_backend
101
104
  fail('You need to configure session_backend, see SSO::Configuration for more info.') unless %w(developmen test).include?(environment)
102
- # Moneta.new :Memory
103
105
  end
104
106
 
105
107
  def default_passport_verification_timeout_ms
@@ -23,7 +23,7 @@ module SSO
23
23
  payload = { success: true, code: revocation.code }
24
24
  debug { "Revoked Passport with ID #{passport_id.inspect}" }
25
25
 
26
- return [200, { 'Content-Type' => 'application/json' }, [payload.to_json]]
26
+ [200, { 'Content-Type' => 'application/json' }, [payload.to_json]]
27
27
  end
28
28
 
29
29
  def json_code(code)
@@ -46,9 +46,9 @@ module SSO
46
46
  passport.create_chip!
47
47
 
48
48
  payload = { success: true, code: :here_is_your_passport, passport: passport.export }
49
- debug { "Created Passport #{passport.id}, sending it including user #{passport.user.inspect}}"}
49
+ debug { "Created Passport #{passport.id}, sending it including user #{passport.user.inspect}}" }
50
50
 
51
- return [200, { 'Content-Type' => 'application/json' }, [payload.to_json]]
51
+ [200, { 'Content-Type' => 'application/json' }, [payload.to_json]]
52
52
  end
53
53
 
54
54
  def json_code(code)
@@ -54,7 +54,7 @@ module SSO
54
54
  end
55
55
 
56
56
  def load_user!
57
- @user = SSO.config.find_user_for_passport.call passport: self.reload
57
+ @user = SSO.config.find_user_for_passport.call passport: reload
58
58
  end
59
59
 
60
60
  def create_chip!
@@ -113,7 +113,7 @@ module SSO
113
113
  end
114
114
 
115
115
  def update_location
116
- location_name = ::SSO::Server::Geolocations.human_readable_location_for_ip ip
116
+ location_name = ::SSO.config.human_readable_location_for_ip.call(ip)
117
117
  debug { "Updating geolocation for #{ip} which is #{location_name}" }
118
118
  self.location = location_name
119
119
  end
@@ -16,6 +16,7 @@ module SSO
16
16
  new(user: user, warden: warden, options: options).call
17
17
  rescue => exception
18
18
  ::SSO.config.exception_handler.call exception
19
+ nil
19
20
  end
20
21
  end
21
22
  end
@@ -30,6 +31,7 @@ module SSO
30
31
 
31
32
  error { 'Could not revoke the Passports.' } if revoking.failure?
32
33
  debug { 'Finished.' }
34
+ nil
33
35
  end
34
36
  end
35
37
  end
@@ -24,7 +24,6 @@
24
24
  end
25
25
  end
26
26
 
27
-
28
27
  # POI
29
28
  Warden::Manager.after_authentication(&::SSO::Server::Warden::Hooks::AfterAuthentication.to_proc)
30
29
  Warden::Manager.before_logout(&::SSO::Server::Warden::Hooks::BeforeLogout.to_proc)
@@ -29,6 +29,22 @@ RSpec.describe SSO::Client::Warden::Hooks::AfterFetch, type: :request, db: true
29
29
  allow(server_user).to receive(:tags).and_return %w(wears_glasses is_working_from_home never_gives_up)
30
30
  end
31
31
 
32
+ context 'invalid passport' do
33
+ let(:passport_secret) { SecureRandom.uuid }
34
+
35
+ it 'does not verify the passport' do
36
+ expect(client_passport).to_not be_verified
37
+ hook.call
38
+ expect(client_passport).to_not be_verified
39
+ end
40
+
41
+ it 'does not modify the passport' do
42
+ expect(client_passport).to_not be_modified
43
+ hook.call
44
+ expect(client_passport).to_not be_modified
45
+ end
46
+ end
47
+
32
48
  context 'user does not change' do
33
49
  it 'verifies the passport' do
34
50
  expect(client_passport).to_not be_verified
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SSO::Client::Warden::Strategies::Passport do
4
+
5
+ let(:env) { env_with_params }
6
+ let(:strategy) { described_class.new env }
7
+
8
+ describe '#valid?' do
9
+ context 'with :auth_version and :state' do
10
+ let(:env) { env_with_params '/', auth_version: '4.2', state: 'abc' }
11
+
12
+ it 'is true' do
13
+ expect(strategy).to be_valid
14
+ end
15
+ end
16
+
17
+ context 'blank :auth_version' do
18
+ let(:env) { env_with_params '/', auth_version: '', state: 'abc' }
19
+
20
+ it 'is false' do
21
+ expect(strategy).not_to be_valid
22
+ end
23
+ end
24
+
25
+ context 'blank :state' do
26
+ let(:env) { env_with_params '/', auth_version: '5.5', state: '' }
27
+
28
+ it 'is false' do
29
+ expect(strategy).not_to be_valid
30
+ end
31
+ end
32
+
33
+ context 'nil :auth_version' do
34
+ let(:env) { env_with_params '/', state: 'xzy' }
35
+
36
+ it 'is false' do
37
+ expect(strategy).not_to be_valid
38
+ end
39
+ end
40
+ end
41
+
42
+ describe '#authenticate!' do
43
+
44
+ context 'invalid passport' do
45
+ it 'is a custom response' do
46
+ expect(strategy.authenticate!).to eq :custom
47
+ end
48
+ end
49
+
50
+ it 'fails' do
51
+ expect(strategy).to receive(:custom!) do |rack_array|
52
+ expect(rack_array.size).to eq 3
53
+ expect(rack_array[0]).to eq 200
54
+ expect(rack_array[1]).to eq 'Content-Type' => 'application/json'
55
+ expect(rack_array[2]).to eq ['{"success":true,"code":"passport_verification_failed"}']
56
+ end
57
+ strategy.authenticate!
58
+ end
59
+
60
+ context 'valid passport' do
61
+ let(:operation) { Operations.success :some_code, object: :authentication_object }
62
+ let(:authentication) { double :authentication, authenticate: operation }
63
+
64
+ before do
65
+ allow(::SSO::Client::Authentications::Passport).to receive(:new).and_return authentication
66
+ allow(authentication).to receive(:success?).and_return true
67
+ end
68
+
69
+ it 'is a success response' do
70
+ expect(strategy.authenticate!).to eq :success
71
+ end
72
+
73
+ it 'succeeds' do
74
+ expect(strategy).to receive(:success!).with :authentication_object
75
+ strategy.authenticate!
76
+ end
77
+ end
78
+
79
+ end
80
+
81
+ end
@@ -0,0 +1,156 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SSO::Configuration do
4
+
5
+ let(:config) { described_class.new }
6
+
7
+ describe '#human_readable_location_for_ip' do
8
+ let(:lookup) { SSO.config.human_readable_location_for_ip }
9
+
10
+ context 'default' do
11
+ it 'is a proc' do
12
+ expect(lookup).to be_instance_of Proc
13
+ end
14
+
15
+ it 'is a String' do
16
+ expect(lookup.call('198.51.100.88')).to eq 'Unknown'
17
+ end
18
+ end
19
+
20
+ context 'customized' do
21
+ before do
22
+ SSO.config.human_readable_location_for_ip = proc { |ip| "Location of #{ip}" }
23
+ end
24
+
25
+ it 'is a custom String' do
26
+ expect(lookup.call('198.51.100.89')).to eq 'Location of 198.51.100.89'
27
+ end
28
+ end
29
+ end
30
+
31
+ describe '#environment' do
32
+ context 'with Rails' do
33
+ it 'is the Rails environment' do
34
+ expect(config.environment).to be ::Rails.env
35
+ end
36
+ end
37
+
38
+ context 'without Rails' do
39
+ before do
40
+ hide_const 'Rails'
41
+ stub_const 'ENV', 'RACK_ENV' => 'rackish'
42
+ end
43
+
44
+ it 'is the RACK_ENV' do
45
+ expect(config.environment).to eq 'rackish'
46
+ end
47
+
48
+ context 'without RACK_ENV' do
49
+ before do
50
+ stub_const 'ENV', {}
51
+ end
52
+
53
+ it 'is unknown' do
54
+ expect(config.environment).to eq 'unknown'
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ context 'test environment' do
61
+
62
+ describe '#logger' do
63
+ context 'with Rails' do
64
+ it 'is the Rails logger' do
65
+ expect(config.logger).to be ::Rails.logger
66
+ end
67
+
68
+ it 'is on the Rails logger level' do
69
+ expect(config.logger.level).to be ::Rails.logger.level
70
+ end
71
+ end
72
+
73
+ context 'without Rails' do
74
+ before do
75
+ hide_const 'Rails'
76
+ end
77
+
78
+ it 'is a Logger' do
79
+ expect(config.logger).to be_instance_of ::Logger
80
+ end
81
+
82
+ it 'is on UNKNOWN level' do
83
+ expect(config.logger.level).to eq ::Logger::UNKNOWN
84
+ end
85
+ end
86
+ end
87
+
88
+ end
89
+
90
+ context 'development environment' do
91
+ before do
92
+ config.environment = :development
93
+ end
94
+
95
+ describe '#logger' do
96
+ context 'with Rails' do
97
+ it 'is the Rails logger' do
98
+ expect(config.logger).to be ::Rails.logger
99
+ end
100
+
101
+ it 'is on the Rails logger level' do
102
+ expect(config.logger.level).to be ::Rails.logger.level
103
+ end
104
+ end
105
+
106
+ context 'without Rails' do
107
+ before do
108
+ hide_const 'Rails'
109
+ end
110
+
111
+ it 'is a Logger' do
112
+ expect(config.logger).to be_instance_of ::Logger
113
+ end
114
+
115
+ it 'is on DEBUG level' do
116
+ expect(config.logger.level).to eq ::Logger::DEBUG
117
+ end
118
+ end
119
+ end
120
+
121
+ end
122
+
123
+ context 'production environment' do
124
+ before do
125
+ config.environment = :production
126
+ end
127
+
128
+ describe '#logger' do
129
+ context 'with Rails' do
130
+ it 'is the Rails logger' do
131
+ expect(config.logger).to be ::Rails.logger
132
+ end
133
+
134
+ it 'is on the Rails logger level' do
135
+ expect(config.logger.level).to be ::Rails.logger.level
136
+ end
137
+ end
138
+
139
+ context 'without Rails' do
140
+ before do
141
+ hide_const 'Rails'
142
+ end
143
+
144
+ it 'is a Logger' do
145
+ expect(config.logger).to be_instance_of ::Logger
146
+ end
147
+
148
+ it 'is on WARN level' do
149
+ expect(config.logger.level).to eq ::Logger::WARN
150
+ end
151
+ end
152
+ end
153
+
154
+ end
155
+
156
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SSO::Server::Warden::Hooks::BeforeLogout do
4
+
5
+ let(:proc) { described_class.to_proc }
6
+ let(:calling) { proc.call(user, warden, options) }
7
+ let(:user) { double :user }
8
+ let(:request) { double :request, params: params.stringify_keys }
9
+ let(:params) { { passport_id: passport.id } }
10
+ let(:warden) { double :warden, request: request }
11
+ let(:options) { double :options }
12
+ let(:passport) { create :passport }
13
+
14
+ before do
15
+ Timecop.freeze
16
+ end
17
+
18
+ describe '.to_proc' do
19
+ it 'is a proc' do
20
+ expect(proc).to be_instance_of Proc
21
+ end
22
+ end
23
+
24
+ describe '#call' do
25
+ it 'accepts the three warden arguments and returns nothing' do
26
+ expect(calling).to be_nil
27
+ end
28
+
29
+ it 'revokes the passport' do
30
+ calling
31
+ passport.reload
32
+ expect(passport.revoked_at.to_i).to eq Time.now.to_i
33
+ expect(passport.revoke_reason).to eq 'logout'
34
+ end
35
+
36
+ it 'survives an exception' do
37
+ allow(described_class).to receive(:new).and_raise NoMethodError, 'I am a problem'
38
+ expect(::SSO.config.logger).to receive(:error)
39
+ expect(calling).to be_nil
40
+ end
41
+ end
42
+
43
+ end
data/spec/spec_helper.rb CHANGED
@@ -2,6 +2,7 @@ ENV['RACK_ENV'] = 'test'
2
2
 
3
3
  unless ENV['TRAVIS']
4
4
  require 'simplecov'
5
+ SimpleCov.add_filter '/spec/'
5
6
  SimpleCov.start
6
7
  end
7
8
 
@@ -4,6 +4,13 @@ module SSO
4
4
  module Test
5
5
  module Helpers
6
6
 
7
+ # Inspired by Warden::Spec::Helpers
8
+ def env_with_params(path = "/", params = {}, env = {})
9
+ method = params.delete(:method) || "GET"
10
+ env = { 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => "#{method}" }.merge(env)
11
+ Rack::MockRequest.env_for "#{path}?#{Rack::Utils.build_query(params)}", env
12
+ end
13
+
7
14
  def redirect_httparty_to_rails_stack
8
15
  redirect_httparty :get
9
16
  redirect_httparty :post
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sso
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.beta2
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - halo
@@ -276,7 +276,6 @@ files:
276
276
  - lib/sso/server/doorkeeper/resource_owner_authenticator.rb
277
277
  - lib/sso/server/engine.rb
278
278
  - lib/sso/server/errors.rb
279
- - lib/sso/server/geolocations.rb
280
279
  - lib/sso/server/middleware/passport_destruction.rb
281
280
  - lib/sso/server/middleware/passport_exchange.rb
282
281
  - lib/sso/server/middleware/passport_verification.rb
@@ -326,9 +325,12 @@ files:
326
325
  - spec/integration/oauth/password_spec.rb
327
326
  - spec/lib/sso/client/authentications/passport_spec.rb
328
327
  - spec/lib/sso/client/warden/hooks/after_fetch_spec.rb
328
+ - spec/lib/sso/client/warden/strategies/passport_spec.rb
329
329
  - spec/lib/sso/logging_spec.rb
330
+ - spec/lib/sso/server/configuration_spec.rb
330
331
  - spec/lib/sso/server/middleware/passport_destruction_spec.rb
331
332
  - spec/lib/sso/server/passports_spec.rb
333
+ - spec/lib/sso/server/warden/hooks/before_logout_spec.rb
332
334
  - spec/spec_helper.rb
333
335
  - spec/support/factories/doorkeeper/application.rb
334
336
  - spec/support/factories/server/passport.rb
@@ -351,9 +353,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
351
353
  version: 2.0.0
352
354
  required_rubygems_version: !ruby/object:Gem::Requirement
353
355
  requirements:
354
- - - ">"
356
+ - - ">="
355
357
  - !ruby/object:Gem::Version
356
- version: 1.3.1
358
+ version: '0'
357
359
  requirements: []
358
360
  rubyforge_project:
359
361
  rubygems_version: 2.4.5
@@ -402,9 +404,12 @@ test_files:
402
404
  - spec/integration/oauth/password_spec.rb
403
405
  - spec/lib/sso/client/authentications/passport_spec.rb
404
406
  - spec/lib/sso/client/warden/hooks/after_fetch_spec.rb
407
+ - spec/lib/sso/client/warden/strategies/passport_spec.rb
405
408
  - spec/lib/sso/logging_spec.rb
409
+ - spec/lib/sso/server/configuration_spec.rb
406
410
  - spec/lib/sso/server/middleware/passport_destruction_spec.rb
407
411
  - spec/lib/sso/server/passports_spec.rb
412
+ - spec/lib/sso/server/warden/hooks/before_logout_spec.rb
408
413
  - spec/spec_helper.rb
409
414
  - spec/support/factories/doorkeeper/application.rb
410
415
  - spec/support/factories/server/passport.rb
@@ -1,10 +0,0 @@
1
- module SSO
2
- module Server
3
- module Geolocations
4
- def self.human_readable_location_for_ip(_)
5
- # Implement your favorite GeoIP lookup here
6
- 'New York'
7
- end
8
- end
9
- end
10
- end