doorkeeper_sso_client 0.4.6 → 0.4.7
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 +4 -4
- data/lib/doorkeeper_sso_client.rb +0 -2
- data/lib/doorkeeper_sso_client/mixins/devise/controller_helpers.rb +4 -0
- data/lib/doorkeeper_sso_client/version.rb +1 -1
- data/spec/lib/doorkeeper_sso_client/mixins/devise/controller_helper_spec.rb +4 -0
- data/spec/models/passport_spec.rb +17 -1
- metadata +2 -4
- data/lib/doorkeeper_sso_client/passport_verifier.rb +0 -146
- data/lib/doorkeeper_sso_client/warden/hooks/after_fetch.rb +0 -134
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e39b15ab6dd20ae730f58de5e82d046a49eadb72
|
4
|
+
data.tar.gz: b5a888aeca2850a2f10f65a248d620ae887bef95
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83316a1e64626bad774180b1b8ad8dbe824b50448fde2c2f37b87e073a14c4f172a01d04414b868018905070947d46c506c70dcaeafd4b1dc36a67dcd27f9b57
|
7
|
+
data.tar.gz: 97937dfdb0942e6e278e91557e5029471952ab96f5378e345df7775023411a9d2da86671f40719b62ab31f018ba45c12af81d3d9696de3d23c34592a08b1f97d
|
@@ -3,9 +3,7 @@ require 'doorkeeper_sso_client/mixins'
|
|
3
3
|
require "doorkeeper_sso_client/engine"
|
4
4
|
require 'doorkeeper_sso_client/config'
|
5
5
|
require 'doorkeeper_sso_client/logging'
|
6
|
-
require 'doorkeeper_sso_client/passport_verifier'
|
7
6
|
require 'doorkeeper_sso_client/warden/support'
|
8
|
-
require 'doorkeeper_sso_client/warden/hooks/after_fetch'
|
9
7
|
require 'doorkeeper_sso_client/version'
|
10
8
|
require 'omniauth/strategies/doorkeeper_sso'
|
11
9
|
|
@@ -27,6 +27,10 @@ module DoorkeeperSsoClient
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
def after_omniauth_failure_path_for(scope)
|
31
|
+
return File.join( DoorkeeperSsoClient::Config.base_uri, "logout?app_id=" + DoorkeeperSsoClient::Config.oauth_client_id.to_s )
|
32
|
+
end
|
33
|
+
|
30
34
|
def sign_out(resource_or_scope=nil)
|
31
35
|
return sign_out_all_scopes unless resource_or_scope
|
32
36
|
if scope_match? resource_or_scope, :#{scope}
|
@@ -53,6 +53,10 @@ RSpec.describe "DoorkeeperSsoClient::Mixins::Devise::ControllerHelpers DeviseHoo
|
|
53
53
|
it { expect(controller.after_sign_out_path_for(:user)).to eq "http://sso_server.com/logout?app_id=123" }
|
54
54
|
end
|
55
55
|
|
56
|
+
describe "#after_omniauth_failure_path_for" do
|
57
|
+
# Will redirect to sso server to completely logout user
|
58
|
+
it { expect(controller.after_omniauth_failure_path_for(:ANYSCOPE)).to eq "http://sso_server.com/logout?app_id=123" }
|
59
|
+
end
|
56
60
|
|
57
61
|
describe "#after_sign_in_path_for" do
|
58
62
|
# Will redirect to request.env['omniauth.origin']
|
@@ -52,7 +52,23 @@ RSpec.describe DoorkeeperSsoClient::Passport, :type => :model do
|
|
52
52
|
it { expect(fetched_passport.uid).to eq passport_uid }
|
53
53
|
it { expect(fetched_passport.token).to eq token }
|
54
54
|
end
|
55
|
-
|
56
55
|
end
|
57
56
|
|
57
|
+
|
58
|
+
describe "#update_from_pingback" do
|
59
|
+
subject(:passport) { Fabricate("DoorkeeperSsoClient::Passport") }
|
60
|
+
let(:the_time) { Time.now }
|
61
|
+
let(:pingback_data) {
|
62
|
+
HashWithIndifferentAccess.new(
|
63
|
+
revoked_at: the_time,
|
64
|
+
revoke_reason: 'logout',
|
65
|
+
activity_at: the_time
|
66
|
+
)
|
67
|
+
}
|
68
|
+
|
69
|
+
before() { passport.update_from_pingback(pingback_data) }
|
70
|
+
it { expect(passport.revoked_at).to eq the_time }
|
71
|
+
it { expect(passport.revoke_reason).to eq 'logout' }
|
72
|
+
it { expect(passport.last_login_at).to eq the_time }
|
73
|
+
end
|
58
74
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doorkeeper_sso_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Wong
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: omniauth
|
@@ -348,9 +348,7 @@ files:
|
|
348
348
|
- lib/doorkeeper_sso_client/mixins/devise/test_helpers.rb
|
349
349
|
- lib/doorkeeper_sso_client/mixins/mongoid/passport.rb
|
350
350
|
- lib/doorkeeper_sso_client/mixins/passport_base.rb
|
351
|
-
- lib/doorkeeper_sso_client/passport_verifier.rb
|
352
351
|
- lib/doorkeeper_sso_client/version.rb
|
353
|
-
- lib/doorkeeper_sso_client/warden/hooks/after_fetch.rb
|
354
352
|
- lib/doorkeeper_sso_client/warden/support.rb
|
355
353
|
- lib/omniauth/strategies/doorkeeper_sso.rb
|
356
354
|
- lib/tasks/doorkeeper_sso_client_tasks.rake
|
@@ -1,146 +0,0 @@
|
|
1
|
-
module DoorkeeperSsoClient
|
2
|
-
class PassportVerifier
|
3
|
-
|
4
|
-
attr_reader :passport_id, :passport_state, :passport_secret, :user_ip, :user_agent, :device_id
|
5
|
-
|
6
|
-
def initialize(options = {})
|
7
|
-
options = ActionController::Parameters.new(options)
|
8
|
-
options.require(:passport_id, :passport_state, :passport_secret, :user_ip)
|
9
|
-
options.permit(:user_agent, :device_id)
|
10
|
-
|
11
|
-
options.each { |k,v| instance_variable_set("@#{k}",v) }
|
12
|
-
end
|
13
|
-
|
14
|
-
def call
|
15
|
-
fetch_response { |failure| return failure }
|
16
|
-
interpret_response
|
17
|
-
|
18
|
-
rescue ::JSON::ParserError
|
19
|
-
error { 'SSO Server response is not valid JSON.' }
|
20
|
-
error { response.inspect }
|
21
|
-
Operations.failure :server_response_not_parseable, object: response
|
22
|
-
end
|
23
|
-
|
24
|
-
def human_readable_timeout_in_ms
|
25
|
-
"#{timeout_in_milliseconds}ms"
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def fetch_response
|
31
|
-
yield Operations.failure(:server_unreachable, object: response) unless response.code.to_s == '200'
|
32
|
-
yield Operations.failure(:server_response_not_parseable, object: response) unless parsed_response
|
33
|
-
yield Operations.failure(:server_response_missing_success_flag, object: response) unless response_has_success_flag?
|
34
|
-
Operations.success :server_response_looks_legit
|
35
|
-
end
|
36
|
-
|
37
|
-
def interpret_response
|
38
|
-
debug { "Interpreting response code #{response_code.inspect}" }
|
39
|
-
|
40
|
-
case response_code
|
41
|
-
when :passpord_unmodified then Operations.success(:passport_valid)
|
42
|
-
when :passport_changed then Operations.success(:passport_valid_and_modified, object: received_passport)
|
43
|
-
when :passport_invalid then Operations.failure(:passport_invalid)
|
44
|
-
else Operations.failure(:unexpected_server_response_status, object: response)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def response_code
|
49
|
-
return :unknown_response_code if parsed_response['code'].to_s == ''
|
50
|
-
parsed_response['code'].to_s.to_sym
|
51
|
-
end
|
52
|
-
|
53
|
-
def received_passport
|
54
|
-
::DoorkeeperSsoClient::Passport.new received_passport_attributes
|
55
|
-
|
56
|
-
rescue ArgumentError
|
57
|
-
error { "Could not instantiate Passport from serialized response #{received_passport_attributes.inspect}" }
|
58
|
-
raise
|
59
|
-
end
|
60
|
-
|
61
|
-
def received_passport_attributes
|
62
|
-
attributes = parsed_response['passport']
|
63
|
-
attributes.keys.each do |key|
|
64
|
-
attributes[(key.to_sym rescue key) || key] = attributes.delete(key)
|
65
|
-
end
|
66
|
-
attributes
|
67
|
-
end
|
68
|
-
|
69
|
-
def params
|
70
|
-
result = { ip: user_ip, agent: user_agent, device_id: device_id, state: passport_state }
|
71
|
-
result.merge! insider_id: insider_id, insider_signature: insider_signature
|
72
|
-
result
|
73
|
-
end
|
74
|
-
|
75
|
-
def insider_id
|
76
|
-
::Sso.config.oauth_client_id
|
77
|
-
end
|
78
|
-
|
79
|
-
def insider_secret
|
80
|
-
::Sso.config.oauth_client_secret
|
81
|
-
end
|
82
|
-
|
83
|
-
def insider_signature
|
84
|
-
::OpenSSL::HMAC.hexdigest signature_digest, insider_secret, user_ip
|
85
|
-
end
|
86
|
-
|
87
|
-
def signature_digest
|
88
|
-
OpenSSL::Digest.new 'sha1'
|
89
|
-
end
|
90
|
-
|
91
|
-
def token
|
92
|
-
Signature::Token.new passport_id, passport_secret
|
93
|
-
end
|
94
|
-
|
95
|
-
def signature_request
|
96
|
-
Signature::Request.new('GET', path, params)
|
97
|
-
end
|
98
|
-
|
99
|
-
def auth_hash
|
100
|
-
signature_request.sign token
|
101
|
-
end
|
102
|
-
|
103
|
-
def timeout_in_milliseconds
|
104
|
-
::Sso.config.passport_verification_timeout_ms.to_i
|
105
|
-
end
|
106
|
-
|
107
|
-
def timeout_in_seconds
|
108
|
-
(timeout_in_milliseconds / 1000).round 2
|
109
|
-
end
|
110
|
-
|
111
|
-
# TODO: Needs to be configurable
|
112
|
-
def path
|
113
|
-
::OmniAuth::Strategies::DoorkeeperSso.sessions_path
|
114
|
-
end
|
115
|
-
|
116
|
-
def base_endpoint
|
117
|
-
::OmniAuth::Strategies::DoorkeeperSso.endpoint
|
118
|
-
end
|
119
|
-
|
120
|
-
def endpoint
|
121
|
-
URI.join(base_endpoint, path).to_s
|
122
|
-
end
|
123
|
-
|
124
|
-
def query_params
|
125
|
-
params.merge auth_hash
|
126
|
-
end
|
127
|
-
|
128
|
-
def response
|
129
|
-
@response ||= response!
|
130
|
-
end
|
131
|
-
|
132
|
-
def response!
|
133
|
-
debug { "Fetching Passport from #{endpoint.inspect}" }
|
134
|
-
::HTTParty.get endpoint, timeout: timeout_in_seconds, query: query_params, headers: { 'Accept' => 'application/json' }
|
135
|
-
end
|
136
|
-
|
137
|
-
def parsed_response
|
138
|
-
response.parsed_response
|
139
|
-
end
|
140
|
-
|
141
|
-
def response_has_success_flag?
|
142
|
-
parsed_response && parsed_response.respond_to?(:key?) && (parsed_response.key?('success') || parsed_response.key?(:success))
|
143
|
-
end
|
144
|
-
|
145
|
-
end
|
146
|
-
end
|
@@ -1,134 +0,0 @@
|
|
1
|
-
module DoorkeeperSsoClient
|
2
|
-
module Warden
|
3
|
-
module Hooks
|
4
|
-
# This is a helpful `Warden::Manager.after_fetch` hook for Alpha and Beta.
|
5
|
-
# Whenever Carol is fetched out of the session, we also verify her resource.
|
6
|
-
#
|
7
|
-
# Usage:
|
8
|
-
#
|
9
|
-
# SSO::Client::Warden::Hooks::AfterFetch.activate scope: :vip
|
10
|
-
#
|
11
|
-
class AfterFetch
|
12
|
-
include ::DoorkeeperSsoClient::Logging
|
13
|
-
|
14
|
-
attr_reader :resource, :warden, :options
|
15
|
-
delegate :request, to: :warden
|
16
|
-
delegate :params, to: :request
|
17
|
-
|
18
|
-
def self.activate(warden_options)
|
19
|
-
::Warden::Manager.after_fetch(warden_options) do |resource, warden, options|
|
20
|
-
self.new(resource, warden, options).call
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def initialize(resource, warden, options)
|
25
|
-
@resource, @warden, @options = resource, warden, options
|
26
|
-
end
|
27
|
-
|
28
|
-
def call
|
29
|
-
return unless resource.is_a?(Session)
|
30
|
-
verify
|
31
|
-
|
32
|
-
rescue ::Timeout::Error
|
33
|
-
error { 'SSO Server timed out. Continuing with last known authentication/authorization...' }
|
34
|
-
Operations.failure :server_request_timed_out
|
35
|
-
|
36
|
-
rescue => exception
|
37
|
-
raise exception
|
38
|
-
Operations.failure :client_exception_caught
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def verifier
|
44
|
-
::DoorkeeperSsoClient::PassportVerifier.new resource_id: resource.id, resource_state: resource.state, resource_secret: resource.secret, user_ip: ip, user_agent: agent, device_id: device_id
|
45
|
-
end
|
46
|
-
|
47
|
-
def verification
|
48
|
-
@verification ||= verifier.call
|
49
|
-
end
|
50
|
-
|
51
|
-
def verification_code
|
52
|
-
verification.code
|
53
|
-
end
|
54
|
-
|
55
|
-
def verification_object
|
56
|
-
verification.object
|
57
|
-
end
|
58
|
-
|
59
|
-
def verify
|
60
|
-
debug { "Validating Passport #{resource.id.inspect} of logged in #{resource.user.class} in scope #{warden_scope.inspect}" }
|
61
|
-
|
62
|
-
case verification_code
|
63
|
-
when :server_unreachable then server_unreachable!
|
64
|
-
when :server_response_not_parseable then server_response_not_parseable!
|
65
|
-
when :server_response_missing_success_flag then server_response_missing_success_flag!
|
66
|
-
when :resource_valid then resource_valid!
|
67
|
-
when :resource_valid_and_modified then resource_valid_and_modified!(verification.object)
|
68
|
-
when :resource_invalid then resource_invalid!
|
69
|
-
else unexpected_server_response_status!
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def resource_valid_and_modified!(modified_resource)
|
74
|
-
debug { 'Valid resource, but state changed' }
|
75
|
-
resource.verified!
|
76
|
-
resource.modified!
|
77
|
-
resource.user = modified_resource.user
|
78
|
-
resource.state = modified_resource.state
|
79
|
-
Operations.success :valid_and_modified
|
80
|
-
end
|
81
|
-
|
82
|
-
def resource_valid!
|
83
|
-
debug { 'Valid resource, no changes' }
|
84
|
-
resource.verified!
|
85
|
-
Operations.success :valid
|
86
|
-
end
|
87
|
-
|
88
|
-
def resource_invalid!
|
89
|
-
info { 'Your Passport is not valid any more.' }
|
90
|
-
warden.logout warden_scope
|
91
|
-
Operations.failure :invalid
|
92
|
-
end
|
93
|
-
|
94
|
-
def server_unreachable!
|
95
|
-
error { "SSO Server responded with an unexpected HTTP status code (#{verification_code.inspect} instead of 200). #{verification_object.inspect}" }
|
96
|
-
Operations.failure :server_unreachable
|
97
|
-
end
|
98
|
-
|
99
|
-
def server_response_missing_success_flag!
|
100
|
-
error { 'SSO Server response did not include the expected success flag.' }
|
101
|
-
Operations.failure :server_response_missing_success_flag
|
102
|
-
end
|
103
|
-
|
104
|
-
def unexpected_server_response_status!
|
105
|
-
error { "SSO Server response did not include a known resource status code. #{verification_code.inspect}" }
|
106
|
-
Operations.failure :unexpected_server_response_status
|
107
|
-
end
|
108
|
-
|
109
|
-
def server_response_not_parseable!
|
110
|
-
error { 'SSO Server response could not be parsed at all.' }
|
111
|
-
Operations.failure :server_response_not_parseable
|
112
|
-
end
|
113
|
-
|
114
|
-
# TODO: Use ActionDispatch remote IP or you might get the Load Balancer's IP instead :(
|
115
|
-
def ip
|
116
|
-
request.ip
|
117
|
-
end
|
118
|
-
|
119
|
-
def agent
|
120
|
-
request.user_agent
|
121
|
-
end
|
122
|
-
|
123
|
-
def device_id
|
124
|
-
params['device_id']
|
125
|
-
end
|
126
|
-
|
127
|
-
def warden_scope
|
128
|
-
options[:scope]
|
129
|
-
end
|
130
|
-
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|