sso 0.1.0.beta2 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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