sso 0.1.0.alpha5 → 0.1.0.alpha6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sso/client/README.md +17 -2
  3. data/lib/sso/client/authentications/passport.rb +176 -0
  4. data/lib/sso/client/passport.rb +7 -3
  5. data/lib/sso/client/passport_verifier.rb +130 -0
  6. data/lib/sso/client/warden/hooks/after_fetch.rb +32 -81
  7. data/lib/sso/client/warden/strategies/passport.rb +43 -0
  8. data/lib/sso/client.rb +3 -0
  9. data/lib/sso/server/authentications/passport.rb +16 -49
  10. data/lib/sso/server/configuration.rb +36 -6
  11. data/lib/sso/server/doorkeeper/access_token_marker.rb +7 -7
  12. data/lib/sso/server/middleware/passport_destruction.rb +40 -0
  13. data/lib/sso/server/middleware/{passport_creation.rb → passport_exchange.rb} +15 -11
  14. data/lib/sso/server/middleware/passport_verification.rb +2 -2
  15. data/lib/sso/server/passport.rb +43 -15
  16. data/lib/sso/server/passports.rb +59 -31
  17. data/lib/sso/server/warden/hooks/after_authentication.rb +1 -1
  18. data/lib/sso/server/warden/hooks/before_logout.rb +1 -1
  19. data/lib/sso/server/warden/strategies/passport.rb +8 -6
  20. data/lib/sso/server.rb +2 -3
  21. data/spec/dummy/app/controllers/sessions_controller.rb +1 -1
  22. data/spec/dummy/config/application.rb +6 -0
  23. data/spec/dummy/config/initializers/sso.rb +10 -6
  24. data/spec/dummy/config/initializers/warden.rb +3 -11
  25. data/spec/dummy/db/migrate/20150303132931_create_passports_table.rb +29 -15
  26. data/spec/dummy/db/schema.rb +10 -5
  27. data/spec/integration/oauth/authorization_code_spec.rb +80 -10
  28. data/spec/integration/oauth/{password_verification_spec.rb → password_spec.rb} +39 -3
  29. data/spec/lib/sso/client/authentications/passport_spec.rb +92 -0
  30. data/spec/{integration/oauth → lib/sso/client/warden/hooks}/after_fetch_spec.rb +4 -3
  31. data/spec/lib/sso/server/middleware/passport_destruction_spec.rb +33 -0
  32. data/spec/lib/sso/server/passports_spec.rb +104 -0
  33. data/spec/spec_helper.rb +2 -0
  34. data/spec/support/factories/doorkeeper/application.rb +0 -3
  35. data/spec/support/factories/server/passport.rb +5 -1
  36. data/spec/support/factories/server/user.rb +1 -1
  37. metadata +31 -21
@@ -32,8 +32,10 @@ module SSO
32
32
  return Operations.failure :invalid_signature, object: failure_rack_array
33
33
  end
34
34
 
35
- debug { 'The request was properly signed, I found the corresponding passport.' }
35
+ debug { 'The request was properly signed, I found the corresponding passport. Updating activity...' }
36
36
  update_passport
37
+ debug { 'Attaching user to passport' }
38
+ passport.load_user!
37
39
 
38
40
  if passport.state == state
39
41
  Operations.success :signature_approved_no_changes, object: success_same_state_rack_array
@@ -44,12 +46,14 @@ module SSO
44
46
  end
45
47
 
46
48
  def check_arguments
49
+ debug { 'Checking arguments...' }
47
50
  yield Operations.failure :missing_verb if verb.blank?
48
51
  yield Operations.failure :missing_passport_id if passport_id.blank?
49
52
  yield Operations.failure :missing_state if state.blank?
50
53
  yield Operations.failure :passport_not_found if passport.blank?
51
54
  yield Operations.failure :passport_revoked if passport.invalid?
52
- # yield Operations.failure :user_not_encapsulated if passport.user.blank?
55
+ debug { 'Arguments are fine.' }
56
+ #yield Operations.failure :user_not_encapsulated if passport.user.blank?
53
57
  Operations.success :arguments_are_valid
54
58
  end
55
59
 
@@ -74,16 +78,24 @@ module SSO
74
78
  end
75
79
 
76
80
  def passport
77
- @passport ||= backend.find_by_id passport_id
81
+ @passport ||= passport!
82
+ end
83
+
84
+ def passport!
85
+ return unless record = backend.find_by_id(passport_id)
86
+ debug { "Successfully loaded Passport #{passport_id} from database." }
87
+ record
78
88
  end
79
89
 
80
90
  def passport_id
81
91
  signature_request.authenticate { |passport_id| return passport_id }
92
+
82
93
  rescue Signature::AuthenticationError
83
94
  nil
84
95
  end
85
96
 
86
97
  def valid_signature?
98
+ debug { 'Checking request signature...' }
87
99
  signature_request.authenticate { Signature::Token.new passport_id, passport.secret }
88
100
  true
89
101
  rescue Signature::AuthenticationError
@@ -96,52 +108,7 @@ module SSO
96
108
  end
97
109
 
98
110
  def update_passport
99
- debug { "Will update activity of Passport #{passport.id} if neccesary..." }
100
- if passport.ip.to_s == ip.to_s && passport.agent.to_s == user_agent.to_s
101
- debug { "No changes in IP or User Agent so I won't perform an update now..." }
102
- Operations.success :already_up_to_date
103
- else
104
- debug { "Yes, it is necessary, updating activity of Passport #{passport.id}" }
105
- passport.update_attributes ip: ip.to_s, agent: user_agent, activity_at: Time.now
106
- Operations.success :passport_metadata_updated
107
- end
108
- end
109
-
110
- def application
111
- passport.application
112
- end
113
-
114
- def app_scopes
115
- application.scopes
116
- end
117
-
118
- def insider?
119
- if app_scopes.empty?
120
- warn { "Doorkeeper::Application #{application.name} with ID #{application.id} has no scope restrictions. Assuming 'outsider' for now." }
121
- return false
122
- end
123
-
124
- app_scopes.has_scopes? [:insider]
125
- end
126
-
127
- def ip
128
- if insider?
129
- params['ip']
130
- else
131
- request_ip
132
- end
133
- end
134
-
135
- def user_agent
136
- if insider?
137
- params['user_agent']
138
- else
139
- request.user_agent
140
- end
141
- end
142
-
143
- def request_ip
144
- request.env['action_dispatch.remote_ip'] || fail('Whoops, I thought you were using Rails, but action_dispatch.remote_ip is empty!')
111
+ ::SSO::Server::Passports.update_activity passport_id: passport.id, request: request
145
112
  end
146
113
 
147
114
  def verb
@@ -3,16 +3,13 @@ require 'logger'
3
3
  module SSO
4
4
  class Configuration
5
5
 
6
+ # Server
7
+
6
8
  def human_readable_location_for_ip
7
9
  @human_readable_location_for_ip || default_human_readable_location_for_ip
8
10
  end
9
11
  attr_writer :human_readable_location_for_ip
10
12
 
11
- def exception_handler
12
- @exception_handler || default_exception_handler
13
- end
14
- attr_writer :exception_handler
15
-
16
13
  def user_state_base
17
14
  @user_state_base || fail('You need to configure user_state_base, see SSO::Configuration for more info.')
18
15
  end
@@ -28,6 +25,30 @@ module SSO
28
25
  end
29
26
  attr_writer :user_state_key
30
27
 
28
+ # Client
29
+
30
+ def session_backend
31
+ @session_backend || default_session_backend
32
+ end
33
+ attr_writer :session_backend
34
+
35
+ def passport_verification_timeout_ms
36
+ @passport_verification_timeout_ms || default_passport_verification_timeout_ms
37
+ end
38
+ attr_writer :passport_verification_timeout_ms
39
+
40
+ # Both
41
+
42
+ def exception_handler
43
+ @exception_handler || default_exception_handler
44
+ end
45
+ attr_writer :exception_handler
46
+
47
+ def passport_chip_key
48
+ @passport_chip_key || fail('You need to configure a secret passport_chip_key, see SSO::Configuration for more info.')
49
+ end
50
+ attr_writer :passport_chip_key
51
+
31
52
  def logger
32
53
  @logger ||= default_logger
33
54
  end
@@ -62,7 +83,7 @@ module SSO
62
83
  end
63
84
 
64
85
  def default_exception_handler
65
- proc do
86
+ proc do |exception|
66
87
  return unless ::SSO.config.logger
67
88
  ::SSO.config.logger.error(self.class) do
68
89
  "An internal error occured #{exception.class.name} #{exception.message} #{exception.backtrace[0..5].join(' ') if exception.backtrace}"
@@ -76,5 +97,14 @@ module SSO
76
97
  end
77
98
  end
78
99
 
100
+ def default_session_backend
101
+ fail('You need to configure session_backend, see SSO::Configuration for more info.') unless %w(developmen test).include?(environment)
102
+ # Moneta.new :Memory
103
+ end
104
+
105
+ def default_passport_verification_timeout_ms
106
+ 100
107
+ end
108
+
79
109
  end
80
110
  end
@@ -38,25 +38,25 @@ module SSO
38
38
  end
39
39
 
40
40
  def handle_authorization_grant_flow
41
- # We cannot rely on session[:passport_id] here because the end-user might have cookies disabled.
42
- # The only thing we can rely on to identify the user/Passport is the incoming grant token.
41
+ # We cannot rely on looking up session[:passport_id] here because the end-user might have cookies disabled.
42
+ # The only thing we can really rely on to identify the Passport is the incoming grant token.
43
43
  debug { %(Detected outgoing "Access Token" #{outgoing_access_token.inspect} of the "Authorization Code Grant" flow) }
44
44
  debug { %(This Access Token belongs to "Authorization Grant Token" #{grant_token.inspect}. Augmenting related Passport with it...) }
45
45
  registration = ::SSO::Server::Passports.register_access_token_from_grant grant_token: grant_token, access_token: outgoing_access_token
46
46
 
47
47
  return if registration.success?
48
- warn { 'The passport could not be augmented. Destroying warden session.' }
48
+ warn { 'The passport could not be augmented via the authorizaton grant. Destroying warden session.' }
49
49
  warden.logout
50
50
  end
51
51
 
52
52
  def handle_password_flow
53
- local_passport_id = session[:passport_id] # <- We know this is always set because it was set in this very response
53
+ local_passport_id = session[:passport_id] # <- We know this always exists because it was set in this very response
54
54
  debug { %(Detected outgoing "Access Token" #{outgoing_access_token.inspect} of the "Resource Owner Password Credentials Grant" flow.) }
55
55
  debug { %(Augmenting local Passport #{local_passport_id.inspect} with this outgoing Access Token...) }
56
- generation = ::SSO::Server::Passports.register_access_token passport_id: local_passport_id, access_token: outgoing_access_token
56
+ registration = ::SSO::Server::Passports.register_access_token_from_id passport_id: local_passport_id, access_token: outgoing_access_token
57
57
 
58
- return if generation.success?
59
- warn { 'The passport could not be generated. Destroying warden session.' }
58
+ return if registration.success?
59
+ warn { 'The passport could not be augmented via the access token. Destroying warden session.' }
60
60
  warden.logout
61
61
  end
62
62
 
@@ -0,0 +1,40 @@
1
+ module SSO
2
+ module Server
3
+ module Middleware
4
+ class PassportDestruction
5
+ include ::SSO::Logging
6
+
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ request = Rack::Request.new(env)
13
+
14
+ if !(request.delete? && request.path.start_with?(passports_path))
15
+ debug { "I'm not interested in this #{request.request_method.inspect} request to #{request.path.inspect} I only care for DELETE #{passports_path.inspect}" }
16
+ return @app.call(env)
17
+ end
18
+
19
+ passport_id = request.path.to_s.split('/').last
20
+ revocation = ::SSO::Server::Passports.logout passport_id: passport_id
21
+ env['warden'].logout
22
+
23
+ payload = { success: true, code: revocation.code }
24
+ debug { "Revoked Passport with ID #{passport_id.inspect}" }
25
+
26
+ return [200, { 'Content-Type' => 'application/json' }, [payload.to_json]]
27
+ end
28
+
29
+ def json_code(code)
30
+ [200, { 'Content-Type' => 'application/json' }, [{ success: true, code: code }.to_json]]
31
+ end
32
+
33
+ def passports_path
34
+ OmniAuth::Strategies::SSO.passports_path
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,7 +1,9 @@
1
1
  module SSO
2
2
  module Server
3
3
  module Middleware
4
- class PassportCreation
4
+ # Hands out the Passport when presented with the corresponding Access Token.
5
+ #
6
+ class PassportExchange
5
7
  include ::SSO::Logging
6
8
 
7
9
  def initialize(app)
@@ -11,9 +13,10 @@ module SSO
11
13
  def call(env)
12
14
  request = Rack::Request.new(env)
13
15
  remote_ip = request.env['action_dispatch.remote_ip'].to_s
16
+ device_id = request.params['device_id']
14
17
 
15
18
  if !(request.post? && request.path == passports_path)
16
- debug { "I'm not interested in this request to #{request.path}" }
19
+ debug { "I'm not interested in this #{request.request_method.inspect} request to #{request.path.inspect} I only care for POST #{passports_path.inspect}" }
17
20
  return @app.call(env)
18
21
  end
19
22
 
@@ -29,18 +32,19 @@ module SSO
29
32
  return json_code :access_token_invalid
30
33
  end
31
34
 
32
- creation = ::SSO::Server::Passports.generate owner_id: access_token.resource_owner_id, ip: remote_ip, agent: request.user_agent
33
- passport_id = creation.object
34
- finding = ::SSO::Server::Passports.find(passport_id)
35
-
35
+ finding = ::SSO::Server::Passports.find_by_access_token_id(access_token.id)
36
36
  if finding.failure?
37
- error { "Could not find newly generated Passport #{finding.code.inspect} - #{finding.object.inspect}"}
38
- return json_code :access_token_not_attached_to_valid_passport
37
+ # This should never happen. Every Access Token should be connected to a Passport.
38
+ return json_code :passport_not_found
39
39
  end
40
-
41
40
  passport = finding.object
42
- debug { "Attaching user to passport #{passport.inspect}" }
43
- passport.user = SSO.config.find_user_for_passport.call(passport: passport, ip: remote_ip)
41
+
42
+ ::SSO::Server::Passports.update_activity passport_id: passport.id, request: request
43
+
44
+ debug { "Attaching user and chip to passport #{passport.inspect}" }
45
+ passport.load_user!
46
+ passport.create_chip!
47
+
44
48
  payload = { success: true, code: :here_is_your_passport, passport: passport.export }
45
49
  debug { "Created Passport #{passport.id}, sending it including user #{passport.user.inspect}}"}
46
50
 
@@ -15,13 +15,13 @@ module SSO
15
15
  debug { 'Detected incoming Passport verification request.' }
16
16
  env['warden'].authenticate! :passport
17
17
  else
18
- debug { "I'm not interested in this request to #{request.path}" }
18
+ debug { "I'm not interested in this #{request.request_method.inspect} request to #{request.path.inspect} I only care for GET #{passports_path.inspect}" }
19
19
  @app.call(env)
20
20
  end
21
21
  end
22
22
 
23
23
  def passports_path
24
- OmniAuth::Strategies::SSO.passports_path
24
+ ::OmniAuth::Strategies::SSO.passports_path
25
25
  end
26
26
 
27
27
  end
@@ -5,23 +5,21 @@ module SSO
5
5
  # This could be MongoDB or whatever
6
6
  class Passport < ActiveRecord::Base
7
7
  include ::SSO::Logging
8
+ include ::SSO::Benchmarking
8
9
 
9
10
  self.table_name = 'passports'
10
11
 
11
12
  before_validation :ensure_secret
12
- before_validation :ensure_group_id
13
13
  before_validation :ensure_activity_at
14
14
 
15
15
  before_save :update_location
16
16
 
17
- belongs_to :application, class_name: 'Doorkeeper::Application'
18
-
19
- validates :secret, :group_id, presence: true
17
+ validates :secret, presence: true
20
18
  validates :oauth_access_token_id, uniqueness: { scope: [:owner_id, :revoked_at], allow_blank: true }
21
19
  validates :revoke_reason, allow_blank: true, format: { with: /\A[a-z_]+\z/ }
22
- validates :application_id, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
23
20
 
24
21
  attr_accessor :user
22
+ attr_reader :chip
25
23
 
26
24
  def export
27
25
  debug { "Exporting Passport #{id} including the encapsulated user." }
@@ -29,6 +27,7 @@ module SSO
29
27
  id: id,
30
28
  secret: secret,
31
29
  state: state,
30
+ chip: chip,
32
31
  user: user,
33
32
  }
34
33
  end
@@ -47,19 +46,52 @@ module SSO
47
46
  end
48
47
 
49
48
  def state!
50
- result = nil
51
- time = Benchmark.realtime do
52
- result = OpenSSL::HMAC.hexdigest user_state_digest, user_state_key, user_state_base
49
+ benchmark 'Passport user state calculation' do
50
+ OpenSSL::HMAC.hexdigest user_state_digest, user_state_key, user_state_base
51
+ end
52
+ end
53
+
54
+ def load_user!
55
+ @user = SSO.config.find_user_for_passport.call passport: self.reload
56
+ end
57
+
58
+ def create_chip!
59
+ @chip = chip!
60
+ end
61
+
62
+ def chip!
63
+ benchmark 'Passport chip encryption' do
64
+ ensure_secret
65
+ cipher = chip_digest
66
+ cipher.encrypt
67
+ cipher.key = chip_key
68
+ chip_iv = cipher.random_iv
69
+ ciphertext = cipher.update chip_plaintext
70
+ ciphertext << cipher.final
71
+ debug { "The Passport chip plaintext #{chip_plaintext.inspect} was encrypted using key #{chip_key.inspect} and IV #{chip_iv.inspect} and resultet in ciphertext #{ciphertext.inspect}" }
72
+ chip = [Base64.encode64(ciphertext).strip(), Base64.encode64(chip_iv).strip()].join('|')
73
+ logger.debug { "Augmented passport #{id.inspect} with chip #{chip.inspect}" }
74
+ chip
53
75
  end
54
- debug { "The user state digest is #{result.inspect}" }
55
- debug { "Calculating the user state took #{(time * 1000).round(2)}ms" }
56
- result
57
76
  end
58
77
 
59
78
  def user_state_digest
60
79
  OpenSSL::Digest.new 'sha1'
61
80
  end
62
81
 
82
+ def chip_digest
83
+ OpenSSL::Cipher::AES256.new :CBC
84
+ end
85
+
86
+ def chip_key
87
+ SSO.config.passport_chip_key
88
+ end
89
+
90
+ # Don't get confused, the chip plaintext is the passport secret
91
+ def chip_plaintext
92
+ secret
93
+ end
94
+
63
95
  def user_state_key
64
96
  ::SSO.config.user_state_key
65
97
  end
@@ -74,10 +106,6 @@ module SSO
74
106
  self.secret ||= SecureRandom.uuid
75
107
  end
76
108
 
77
- def ensure_group_id
78
- self.group_id ||= SecureRandom.uuid
79
- end
80
-
81
109
  def ensure_activity_at
82
110
  self.activity_at ||= Time.now
83
111
  end
@@ -17,10 +17,20 @@ module SSO
17
17
  Operations.failure :backend_error, object: exception
18
18
  end
19
19
 
20
- def self.generate(owner_id:, ip:, agent:)
21
- debug { "Generating Passport for user ID #{owner_id.inspect} and IP #{ip.inspect} and Agent #{agent.inspect}" }
20
+ def self.find_by_access_token_id(id)
21
+ record = backend.where(revoked_at: nil).find_by_oauth_access_token_id(id)
22
22
 
23
- record = backend.create owner_id: owner_id, ip: ip, agent: agent, application_id: 0
23
+ if record
24
+ Operations.success(:record_found, object: record)
25
+ else
26
+ Operations.failure :record_not_found
27
+ end
28
+ end
29
+
30
+ def self.generate(owner_id:, ip:, agent:, device: nil)
31
+ debug { "Generating Passport for user ID #{owner_id.inspect} and IP #{ip.inspect} and Agent #{agent.inspect} and Device #{device.inspect}" }
32
+
33
+ record = backend.create owner_id: owner_id, ip: ip, agent: agent, device: device
24
34
 
25
35
  if record.persisted?
26
36
  debug { "Successfully generated passport with ID #{record.id}" }
@@ -30,6 +40,33 @@ module SSO
30
40
  end
31
41
  end
32
42
 
43
+ def self.update_activity(passport_id:, request:)
44
+ record = find_valid_passport(passport_id) { |failure| return failure }
45
+
46
+ immediate_ip = request.respond_to?(:remote_ip) ? request.remote_ip : request.ip
47
+ if record.insider?
48
+ proxied_ip = request['ip']
49
+ unless proxied_ip
50
+ warn { "There should have been a proxied IP param, but there was none. I will use the immediare IP #{immediate_ip} now." }
51
+ proxied_ip = immediate_ip
52
+ end
53
+ attributes = { ip: proxied_ip, agent: request['agent'], device: request['device_id'] }
54
+ else
55
+ attributes = { ip: immediate_ip, agent: request.user_agent, device: request.params['device_id'] }
56
+ end
57
+ attributes.merge! activity_at: Time.now
58
+
59
+ record.stamps ||= {} # <- Not thread-safe, this may potentially delete all existing stamps, I guess
60
+ record.stamps[attributes[:ip]] = Time.now.to_i
61
+
62
+ debug { "Updating activity of #{record.insider? ? :insider : :outsider} Passport #{passport_id.inspect} using IP #{attributes[:ip]} agent #{attributes[:agent]} and device #{attributes[:device]}" }
63
+ if record.update_attributes(attributes)
64
+ Operations.success :passport_metadata_updated
65
+ else
66
+ Operations.failure :could_not_update_passport_activity, object: record.errors.to_hash
67
+ end
68
+ end
69
+
33
70
  def self.register_authorization_grant(passport_id:, token:)
34
71
  record = find_valid_passport(passport_id) { |failure| return failure }
35
72
  access_grant = find_valid_access_grant(token) { |failure| return failure }
@@ -47,7 +84,9 @@ module SSO
47
84
  access_token = find_valid_access_token(access_token) { |failure| return failure }
48
85
  record = find_valid_passport_by_grant_id(access_grant.id) { |failure| return failure }
49
86
 
50
- if record.update_attribute :oauth_access_token_id, access_token.id
87
+ is_insider = access_token.scopes.include? 'insider'
88
+
89
+ if record.update_attributes oauth_access_token_id: access_token.id, insider: is_insider
51
90
  debug { "Successfully augmented Passport #{record.id} with Access Token ID #{access_token.id} which is #{access_token.token}" }
52
91
  Operations.success :passport_known_by_grant_augmented_with_access_token
53
92
  else
@@ -55,31 +94,33 @@ module SSO
55
94
  end
56
95
  end
57
96
 
58
- def self.register_access_token(passport_id:, access_token:)
97
+ def self.register_access_token_from_id(passport_id:, access_token:)
59
98
  access_token = find_valid_access_token(access_token) { |failure| return failure }
60
99
  record = find_valid_passport(passport_id) { |failure| return failure }
61
100
 
62
- if record.update_attribute :oauth_access_token_id, access_token.id
63
- debug { "Successfully augmented Passport #{record.id} with Access Token ID #{access_token.id} which is #{access_token.token}" }
101
+ is_insider = access_token.scopes.include? 'insider'
102
+
103
+ if record.update_attributes oauth_access_token_id: access_token.id, insider: is_insider
104
+ debug { "Successfully augmented #{is_insider ? :insider : :outsider} Passport #{record.id} with Access Token ID #{access_token.id} which is #{access_token.token}" }
64
105
  Operations.success :passport_augmented_with_access_token
65
106
  else
66
107
  Operations.failure :could_not_augment_passport_with_access_token
67
108
  end
68
109
  end
69
110
 
70
- def self.logout(passport_id:, provider_passport_id:)
71
- if passport_id.present? || provider_passport_id.present?
72
- debug { "Attemting to logout Passport groups of Passport IDs #{passport_id.inspect} and #{provider_passport_id.inspect}..." }
73
- else
74
- debug { "Should logout Passport groups now, but don't know which ones. Moving on..." }
75
- return Operations.success :nothing_to_revoke_from
76
- end
111
+ def self.logout(passport_id:)
112
+ return Operations.failure(:missing_passport_id) if passport_id.blank?
77
113
 
78
- count = 0
79
- count += logout_cluster(passport_id) if passport_id.present?
80
- count += logout_cluster(provider_passport_id) if provider_passport_id.present?
114
+ debug { "Logging out Passport with ID #{passport_id.inspect}" }
115
+ record = backend.find_by_id passport_id
116
+ return Operations.success(:passport_does_not_exist) unless record
117
+ return Operations.success(:passport_already_revoked) if record.revoked_at
81
118
 
82
- Operations.success :passports_revoked, object: count
119
+ if record.update_attributes revoked_at: Time.now, revoke_reason: :logout
120
+ Operations.success :passport_revoked
121
+ else
122
+ Operations.failure :backend_could_not_revoke_passport
123
+ end
83
124
  end
84
125
 
85
126
  private
@@ -89,7 +130,6 @@ module SSO
89
130
  return record if record
90
131
 
91
132
  debug { "Could not find valid passport with ID #{id.inspect}" }
92
- debug { "All I have is #{backend.all.inspect}" }
93
133
  yield Operations.failure :passport_not_found if block_given?
94
134
  nil
95
135
  end
@@ -127,18 +167,6 @@ module SSO
127
167
  end
128
168
  end
129
169
 
130
- def self.logout_cluster(passport_id)
131
- unless passport_id.present? && record = backend.find_by_id(passport_id)
132
- debug { "Cannot revoke Passport group of Passport ID #{passport_id.inspect} because it does not exist." }
133
- return 0
134
- end
135
-
136
- debug { "Revoking Passport group #{record.group_id.inspect} of Passport ID #{passport_id.inspect}" }
137
- affected_row_count = backend.where(group_id: record.group_id).update_all revoked_at: Time.now, revoke_reason: :logout
138
- debug { "Successfully revoked #{affected_row_count.inspect} Passports." }
139
- affected_row_count
140
- end
141
-
142
170
  def self.backend
143
171
  ::SSO::Server::Passport
144
172
  end
@@ -27,7 +27,7 @@ module SSO
27
27
  request = warden.request
28
28
  session = warden.env['rack.session']
29
29
 
30
- debug { "Generating a passport for user #{user.id.inspect} for the session cookie at the SSO server..." }
30
+ debug { "Generating a passport for user #{user.id.inspect} for the session with the SSO server..." }
31
31
  attributes = { owner_id: user.id, ip: request.ip, agent: request.user_agent }
32
32
 
33
33
  generation = SSO::Server::Passports.generate attributes
@@ -26,7 +26,7 @@ module SSO
26
26
 
27
27
  def call
28
28
  debug { 'Before warden destroys the passport in the cookie, it will revoke all connected Passports as well.' }
29
- revoking = Passports.logout passport_id: params['passport_id'], provider_passport_id: session['passport_id']
29
+ revoking = Passports.logout passport_id: params['passport_id']
30
30
 
31
31
  error { 'Could not revoke the Passports.' } if revoking.failure?
32
32
  debug { 'Finished.' }
@@ -4,6 +4,7 @@ module SSO
4
4
  module Strategies
5
5
  class Passport < ::Warden::Strategies::Base
6
6
  include ::SSO::Logging
7
+ include ::SSO::Benchmarking
7
8
 
8
9
  def valid?
9
10
  params['auth_version'].to_s != '' && params['state'] != ''
@@ -12,12 +13,7 @@ module SSO
12
13
  def authenticate!
13
14
  debug { 'Authenticating from Passport...' }
14
15
 
15
- authentication = nil
16
- time = Benchmark.realtime do
17
- authentication = ::SSO::Server::Authentications::Passport.new(request).authenticate
18
- end
19
-
20
- info { "The Passport verification took #{(time * 1000).round}ms" }
16
+ authentication = passport_authentication
21
17
 
22
18
  if authentication.success?
23
19
  debug { 'Authentication from Passport successful.' }
@@ -32,6 +28,12 @@ module SSO
32
28
  ::SSO.config.exception_handler.call exception
33
29
  end
34
30
 
31
+ def passport_authentication
32
+ benchmark 'Passport verification' do
33
+ ::SSO::Server::Authentications::Passport.new(request).authenticate
34
+ end
35
+ end
36
+
35
37
  end
36
38
  end
37
39
  end
data/lib/sso/server.rb CHANGED
@@ -11,13 +11,12 @@ require 'sso/server/errors'
11
11
  require 'sso/server/passport'
12
12
  require 'sso/server/passports'
13
13
  require 'sso/server/geolocations'
14
- require 'sso/server/configuration'
15
- require 'sso/server/configure'
16
14
  require 'sso/server/engine'
17
15
 
18
16
  require 'sso/server/authentications/passport'
19
17
  require 'sso/server/middleware/passport_verification'
20
- require 'sso/server/middleware/passport_creation'
18
+ require 'sso/server/middleware/passport_destruction'
19
+ require 'sso/server/middleware/passport_exchange'
21
20
 
22
21
  require 'sso/server/warden/hooks/after_authentication'
23
22
  require 'sso/server/warden/hooks/before_logout'
@@ -16,7 +16,7 @@ class SessionsController < ApplicationController
16
16
  warden.authenticate! :password
17
17
 
18
18
  if session[:return_path]
19
- debug { "Sending tou back to #{session[:return_path]}" }
19
+ debug { "Sending you back to #{session[:return_path]}" }
20
20
  redirect_to session[:return_path]
21
21
  session[:return_path] = nil
22
22
  else
@@ -32,5 +32,11 @@ module Dummy
32
32
  manager.serialize_from_session { |id| User.find_by_id(id) }
33
33
  end
34
34
 
35
+ config.middleware.insert_after ::Warden::Manager, ::SSO::Server::Middleware::PassportVerification
36
+ config.middleware.insert_after ::Warden::Manager, ::SSO::Server::Middleware::PassportDestruction
37
+ config.middleware.insert_after ::Warden::Manager, ::SSO::Server::Middleware::PassportExchange
38
+ config.middleware.insert_after ::Warden::Manager, ::SSO::Server::Doorkeeper::GrantMarker
39
+ config.middleware.insert_after ::Warden::Manager, ::SSO::Server::Doorkeeper::AccessTokenMarker
40
+
35
41
  end
36
42
  end