omniauth_crowd 2.2.3 → 2.3.0
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/.travis.yml +4 -0
- data/Gemfile.lock +30 -25
- data/lib/omniauth/strategies/crowd.rb +45 -4
- data/lib/omniauth/strategies/crowd/configuration.rb +13 -1
- data/lib/omniauth/strategies/crowd/crowd_validator.rb +100 -37
- data/lib/omniauth_crowd/version.rb +1 -1
- data/spec/omniauth/strategies/crowd_spec.rb +251 -25
- data/spec/spec_helper.rb +1 -0
- metadata +26 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6496c1f734a4cc164441c2cceb75039fa3751b2
|
4
|
+
data.tar.gz: 9d8e8b2cff8787f2d346dcb45f06486a1596d08d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 598ab5299d7381c0804b8afc81bd7227eea20d868ff2afd3dd38d4e9c518c6486706dc90a7d1b936c46c86e2d6bd6763fa2a7df0285bc6928564fb530a0e4cb2
|
7
|
+
data.tar.gz: 7f88dc8845d027da6983af8a3e05e3c544e5dea8075977eb376708917140298fbd3f30b26173f929877433057aaf1ca56cf8fdec588f933eea463c268f4e638d
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
omniauth_crowd (2.
|
4
|
+
omniauth_crowd (2.3.0)
|
5
5
|
activesupport
|
6
6
|
nokogiri (>= 1.4.4)
|
7
7
|
omniauth (~> 1.0)
|
@@ -9,49 +9,51 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: http://rubygems.org/
|
11
11
|
specs:
|
12
|
-
activesupport (4.1
|
13
|
-
i18n (~> 0.
|
12
|
+
activesupport (4.2.5.1)
|
13
|
+
i18n (~> 0.7)
|
14
14
|
json (~> 1.7, >= 1.7.7)
|
15
15
|
minitest (~> 5.1)
|
16
|
-
thread_safe (~> 0.
|
16
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
17
17
|
tzinfo (~> 1.1)
|
18
|
-
addressable (2.
|
19
|
-
crack (0.4.
|
18
|
+
addressable (2.4.0)
|
19
|
+
crack (0.4.3)
|
20
20
|
safe_yaml (~> 1.0.0)
|
21
21
|
diff-lcs (1.2.5)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
22
|
+
hashdiff (0.3.0)
|
23
|
+
hashie (3.4.3)
|
24
|
+
i18n (0.7.0)
|
25
|
+
json (1.8.3)
|
26
|
+
mini_portile2 (2.0.0)
|
27
|
+
minitest (5.8.4)
|
28
|
+
nokogiri (1.6.7.2)
|
29
|
+
mini_portile2 (~> 2.0.0.rc2)
|
30
|
+
omniauth (1.3.1)
|
30
31
|
hashie (>= 1.2, < 4)
|
31
|
-
rack (
|
32
|
-
rack (1.
|
33
|
-
rack-test (0.6.
|
32
|
+
rack (>= 1.0, < 3)
|
33
|
+
rack (1.6.4)
|
34
|
+
rack-test (0.6.3)
|
34
35
|
rack (>= 1.0)
|
35
|
-
rake (10.
|
36
|
+
rake (10.5.0)
|
36
37
|
rspec (3.0.0)
|
37
38
|
rspec-core (~> 3.0.0)
|
38
39
|
rspec-expectations (~> 3.0.0)
|
39
40
|
rspec-mocks (~> 3.0.0)
|
40
|
-
rspec-core (3.0.
|
41
|
+
rspec-core (3.0.4)
|
41
42
|
rspec-support (~> 3.0.0)
|
42
|
-
rspec-expectations (3.0.
|
43
|
+
rspec-expectations (3.0.4)
|
43
44
|
diff-lcs (>= 1.2.0, < 2.0)
|
44
45
|
rspec-support (~> 3.0.0)
|
45
|
-
rspec-mocks (3.0.
|
46
|
+
rspec-mocks (3.0.4)
|
46
47
|
rspec-support (~> 3.0.0)
|
47
|
-
rspec-support (3.0.
|
48
|
-
safe_yaml (1.0.
|
49
|
-
thread_safe (0.3.
|
48
|
+
rspec-support (3.0.4)
|
49
|
+
safe_yaml (1.0.4)
|
50
|
+
thread_safe (0.3.5)
|
50
51
|
tzinfo (1.2.2)
|
51
52
|
thread_safe (~> 0.1)
|
52
|
-
webmock (1.
|
53
|
+
webmock (1.24.1)
|
53
54
|
addressable (>= 2.3.6)
|
54
55
|
crack (>= 0.3.2)
|
56
|
+
hashdiff
|
55
57
|
|
56
58
|
PLATFORMS
|
57
59
|
ruby
|
@@ -64,3 +66,6 @@ DEPENDENCIES
|
|
64
66
|
rake
|
65
67
|
rspec (~> 3.0.0)
|
66
68
|
webmock
|
69
|
+
|
70
|
+
BUNDLED WITH
|
71
|
+
1.11.2
|
@@ -18,7 +18,13 @@ module OmniAuth
|
|
18
18
|
|
19
19
|
def request_phase
|
20
20
|
if env['REQUEST_METHOD'] == 'GET'
|
21
|
-
|
21
|
+
|
22
|
+
if @configuration.use_sso? && request.cookies[@configuration.session_cookie]
|
23
|
+
redirect callback_url
|
24
|
+
else
|
25
|
+
get_credentials
|
26
|
+
end
|
27
|
+
|
22
28
|
elsif (env['REQUEST_METHOD'] == 'POST') && (not request.params['username'])
|
23
29
|
get_credentials
|
24
30
|
else
|
@@ -27,17 +33,52 @@ module OmniAuth
|
|
27
33
|
end
|
28
34
|
end
|
29
35
|
|
36
|
+
def get_client_ip
|
37
|
+
env['HTTP_X_FORWARDED_FOR'] ? env['HTTP_X_FORWARDED_FOR'] : env['REMOTE_ADDRESS']
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_sso_tokens
|
41
|
+
env['HTTP_COOKIE'].split(';').select { |val|
|
42
|
+
val.strip.start_with?(@configuration.session_cookie)
|
43
|
+
}.map { |val|
|
44
|
+
val.strip.split('=').last
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
30
48
|
def get_credentials
|
49
|
+
|
50
|
+
configuration = @configuration
|
51
|
+
|
31
52
|
OmniAuth::Form.build(:title => (options[:title] || "Crowd Authentication")) do
|
32
53
|
text_field 'Login', 'username'
|
33
54
|
password_field 'Password', 'password'
|
55
|
+
|
56
|
+
if configuration.use_sso? && configuration.sso_url
|
57
|
+
fieldset 'SSO' do
|
58
|
+
html "<a href=\"#{configuration.sso_url}/users/auth/crowd/callback\">" + (configuration.sso_url_image ? "<img src=\"#{configuration.sso_url_image}\" />" : '') + "</a>"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
34
62
|
end.to_response
|
35
|
-
end
|
36
63
|
|
64
|
+
end
|
65
|
+
|
37
66
|
def callback_phase
|
67
|
+
|
38
68
|
creds = session.delete 'omniauth.crowd'
|
39
|
-
|
40
|
-
|
69
|
+
username = creds.nil? ? nil : creds['username']
|
70
|
+
password = creds.nil? ? nil : creds['password']
|
71
|
+
|
72
|
+
unless creds
|
73
|
+
if @configuration.use_sso? && request.cookies[@configuration.session_cookie]
|
74
|
+
validator = CrowdValidator.new(@configuration, username, password, get_client_ip, get_sso_tokens)
|
75
|
+
else
|
76
|
+
return fail!(:no_credentials)
|
77
|
+
end
|
78
|
+
else
|
79
|
+
validator = CrowdValidator.new(@configuration, username, password, get_client_ip, nil)
|
80
|
+
end
|
81
|
+
|
41
82
|
@user_info = validator.user_info
|
42
83
|
|
43
84
|
return fail!(:invalid_credentials) if @user_info.nil? || @user_info.empty?
|
@@ -8,8 +8,9 @@ module OmniAuth
|
|
8
8
|
DEFAULT_AUTHENTICATION_URL = "%s/rest/usermanagement/latest/authentication"
|
9
9
|
DEFAULT_USER_GROUP_URL = "%s/rest/usermanagement/latest/user/group/direct"
|
10
10
|
DEFAULT_CONTENT_TYPE = 'application/xml'
|
11
|
+
DEFAULT_SESSION_COOKIE = 'crowd.token_key'
|
11
12
|
|
12
|
-
attr_reader :crowd_application_name, :crowd_password, :disable_ssl_verification, :include_users_groups, :use_sessions, :session_url, :content_type
|
13
|
+
attr_reader :crowd_application_name, :crowd_password, :disable_ssl_verification, :include_users_groups, :use_sessions, :session_url, :content_type, :session_cookie, :sso_url, :sso_url_image
|
13
14
|
|
14
15
|
alias :"disable_ssl_verification?" :disable_ssl_verification
|
15
16
|
alias :"include_users_groups?" :include_users_groups
|
@@ -29,6 +30,10 @@ module OmniAuth
|
|
29
30
|
# @option params [String, nil] :crowd_user_group_url (:crowd_server_url + '/rest/usermanagement/latest/user/group/direct') the URL to which to
|
30
31
|
# use for retrieving users groups optional if `:crowd_server_url` is specified, or if `:include_user_groups` is false
|
31
32
|
# required otherwise.
|
33
|
+
# @option params [Boolean, false] :use_sessions Use Crowd sessions. If the user logins with user and password create a new Crowd session. Update the session if only a session token is sent (Cookie name set by option session_cookie)
|
34
|
+
# @option params [String, 'crowd.token_key'] :session_cookie Session cookie name. Defaults to: 'crowd.token_key'
|
35
|
+
# @option params [String, nil] :sso_url URL of the external SSO page. If this parameter is defined the login form will have a link which will redirect to the SSO page. The SSO must return to the URL of the page using omniauth_crowd (Path portion '/users/auth/crowd/callback' is appended to the URL)
|
36
|
+
# @option params [String, nil] :sso_url_image Optional image URL to be used in SSO link in the login form
|
32
37
|
def initialize(params)
|
33
38
|
parse_params params
|
34
39
|
end
|
@@ -46,6 +51,10 @@ module OmniAuth
|
|
46
51
|
@user_group_url.nil? ? nil : append_username( @user_group_url, username)
|
47
52
|
end
|
48
53
|
|
54
|
+
def use_sso?()
|
55
|
+
@use_sessions && @sso_url ? true : false
|
56
|
+
end
|
57
|
+
|
49
58
|
private
|
50
59
|
def parse_params(options)
|
51
60
|
options= {:include_user_groups => true}.merge(options || {})
|
@@ -56,6 +65,9 @@ module OmniAuth
|
|
56
65
|
@crowd_password = options[:application_password]
|
57
66
|
@use_sessions = options[:use_sessions]
|
58
67
|
@content_type = options[:content_type] || DEFAULT_CONTENT_TYPE
|
68
|
+
@session_cookie = options[:session_cookie] || DEFAULT_SESSION_COOKIE
|
69
|
+
@sso_url = options[:sso_url]
|
70
|
+
@sso_url_image = options[:sso_url_image]
|
59
71
|
|
60
72
|
unless options.include?(:crowd_server_url) || options.include?(:crowd_authentication_url)
|
61
73
|
raise ArgumentError.new("Either :crowd_server_url or :crowd_authentication_url MUST be provided")
|
@@ -6,22 +6,16 @@ module OmniAuth
|
|
6
6
|
module Strategies
|
7
7
|
class Crowd
|
8
8
|
class CrowdValidator
|
9
|
-
SESSION_REQUEST_BODY = <<-BODY.strip
|
10
|
-
<authentication-context>
|
11
|
-
<username>%s</username>
|
12
|
-
<password>%s</password>
|
13
|
-
</authentication-context>
|
14
|
-
BODY
|
15
9
|
AUTHENTICATION_REQUEST_BODY = "<password><value>%s</value></password>"
|
16
|
-
def initialize(configuration, username, password)
|
17
|
-
@configuration, @username, @password = configuration, username, password
|
10
|
+
def initialize(configuration, username, password, client_ip, tokens)
|
11
|
+
@configuration, @username, @password, @client_ip, @tokens = configuration, username, password, client_ip, tokens
|
18
12
|
@authentiction_uri = URI.parse(@configuration.authentication_url(@username))
|
19
13
|
@session_uri = URI.parse(@configuration.session_url) if @configuration.use_sessions
|
20
|
-
@user_group_uri = @configuration.include_users_groups? ? URI.parse(@configuration.user_group_url(@username)) : nil
|
21
14
|
end
|
22
15
|
|
23
16
|
def user_info
|
24
17
|
user_info_hash = retrieve_user_info!
|
18
|
+
|
25
19
|
if user_info_hash && @configuration.include_users_groups?
|
26
20
|
user_info_hash = add_user_groups!(user_info_hash)
|
27
21
|
else
|
@@ -29,27 +23,36 @@ BODY
|
|
29
23
|
end
|
30
24
|
|
31
25
|
if user_info_hash && @configuration.use_sessions?
|
32
|
-
user_info_hash =
|
26
|
+
user_info_hash = set_session!(user_info_hash)
|
33
27
|
end
|
34
28
|
|
35
29
|
user_info_hash
|
36
30
|
end
|
37
31
|
|
38
32
|
private
|
39
|
-
def
|
40
|
-
|
33
|
+
def set_session!(user_info_hash)
|
34
|
+
|
35
|
+
response = nil
|
36
|
+
|
37
|
+
if user_info_hash["sso_token"]
|
38
|
+
response = make_session_request(user_info_hash["sso_token"])
|
39
|
+
else
|
40
|
+
response = make_session_request(nil)
|
41
|
+
end
|
42
|
+
|
41
43
|
if response.kind_of?(Net::HTTPSuccess) && response.body
|
42
44
|
doc = Nokogiri::XML(response.body)
|
43
45
|
user_info_hash["sso_token"] = doc.xpath('//token/text()').to_s
|
44
46
|
else
|
45
|
-
OmniAuth.logger.send(:warn, "(crowd) [
|
46
|
-
OmniAuth.logger.send(:warn, "(crowd) [
|
47
|
+
OmniAuth.logger.send(:warn, "(crowd) [set_session!] response code: #{response.code.to_s}")
|
48
|
+
OmniAuth.logger.send(:warn, "(crowd) [set_session!] response body: #{response.body}")
|
47
49
|
end
|
50
|
+
|
48
51
|
user_info_hash
|
49
52
|
end
|
50
53
|
|
51
54
|
def add_user_groups!(user_info_hash)
|
52
|
-
response = make_user_group_request
|
55
|
+
response = make_user_group_request(user_info_hash['user'])
|
53
56
|
unless response.code.to_i != 200 || response.body.nil? || response.body == ''
|
54
57
|
doc = Nokogiri::XML(response.body)
|
55
58
|
user_info_hash["groups"] = doc.xpath("//groups/group/@name").map(&:to_s)
|
@@ -59,18 +62,32 @@ BODY
|
|
59
62
|
|
60
63
|
def retrieve_user_info!
|
61
64
|
response = make_authorization_request
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
65
|
+
|
66
|
+
unless response === nil
|
67
|
+
unless response.code.to_i != 200 || response.body.nil? || response.body == ''
|
68
|
+
|
69
|
+
doc = Nokogiri::XML(response.body)
|
70
|
+
result = {
|
71
|
+
"user" => doc.xpath("//user/@name").to_s,
|
72
|
+
"name" => doc.xpath("//user/display-name/text()").to_s,
|
73
|
+
"first_name" => doc.xpath("//user/first-name/text()").to_s,
|
74
|
+
"last_name" => doc.xpath("//user/last-name/text()").to_s,
|
75
|
+
"email" => doc.xpath("//user/email/text()").to_s
|
76
|
+
}
|
77
|
+
|
78
|
+
if doc.at_xpath("//token")
|
79
|
+
result["sso_token"] = doc.xpath("//token/text()").to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
result
|
83
|
+
|
84
|
+
else
|
85
|
+
OmniAuth.logger.send(:warn, "(crowd) [retrieve_user_info!] response code: #{response.code.to_s}")
|
86
|
+
OmniAuth.logger.send(:warn, "(crowd) [retrieve_user_info!] response body: #{response.body}")
|
87
|
+
nil
|
88
|
+
end
|
71
89
|
else
|
72
|
-
OmniAuth.logger.send(:warn, "(crowd) [retrieve_user_info!]
|
73
|
-
OmniAuth.logger.send(:warn, "(crowd) [retrieve_user_info!] response body: #{response.body}")
|
90
|
+
OmniAuth.logger.send(:warn, "(crowd) [retrieve_user_info!] None of the session tokens were valid")
|
74
91
|
nil
|
75
92
|
end
|
76
93
|
end
|
@@ -91,18 +108,58 @@ BODY
|
|
91
108
|
end
|
92
109
|
end
|
93
110
|
|
94
|
-
def make_user_group_request
|
95
|
-
make_request(@
|
111
|
+
def make_user_group_request(username)
|
112
|
+
make_request(URI.parse(@configuration.user_group_url(username)))
|
96
113
|
end
|
97
114
|
|
98
115
|
def make_authorization_request
|
99
|
-
make_request(@authentiction_uri, make_authentication_request_body(@password))
|
100
|
-
end
|
101
116
|
|
102
|
-
|
103
|
-
|
117
|
+
if @configuration.use_sessions? && @tokens.kind_of?(Array)
|
118
|
+
make_session_retrieval_request
|
119
|
+
else
|
120
|
+
make_request(@authentiction_uri, make_authentication_request_body(@password))
|
121
|
+
end
|
104
122
|
end
|
105
123
|
|
124
|
+
def make_session_request(token)
|
125
|
+
|
126
|
+
root = url = validation_factor = nil
|
127
|
+
doc = Nokogiri::XML::Document.new
|
128
|
+
|
129
|
+
if token === nil
|
130
|
+
|
131
|
+
url = @session_uri
|
132
|
+
root = doc.create_element('authentication-context')
|
133
|
+
|
134
|
+
doc.root = root
|
135
|
+
root.add_child(doc.create_element('username', @username))
|
136
|
+
root.add_child(doc.create_element('password', @password))
|
137
|
+
|
138
|
+
else
|
139
|
+
url = URI.parse(@session_uri.to_s() + "/#{token}")
|
140
|
+
end
|
141
|
+
|
142
|
+
if @configuration.use_sessions? || @client_ip
|
143
|
+
|
144
|
+
if root === nil
|
145
|
+
root = doc.create_element('validation-factors')
|
146
|
+
doc.root = root
|
147
|
+
else
|
148
|
+
root.add_child(doc.create_element('validation-factors'))
|
149
|
+
end
|
150
|
+
|
151
|
+
validation_factor = doc.create_element('validation-factor')
|
152
|
+
validation_factor.add_child(doc.create_element('name', 'remote_address'))
|
153
|
+
validation_factor.add_child(doc.create_element('value', @client_ip))
|
154
|
+
|
155
|
+
doc.xpath('//validation-factors').first.add_child(validation_factor)
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
make_request(url, doc.to_s)
|
160
|
+
|
161
|
+
end
|
162
|
+
|
106
163
|
# create the body using Nokogiri so proper encoding of passwords can be ensured
|
107
164
|
def make_authentication_request_body(password)
|
108
165
|
request_body = Nokogiri::XML(AUTHENTICATION_REQUEST_BODY)
|
@@ -111,11 +168,17 @@ BODY
|
|
111
168
|
return request_body.root.to_s # return the body without the xml header
|
112
169
|
end
|
113
170
|
|
114
|
-
def
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
171
|
+
def make_session_retrieval_request
|
172
|
+
|
173
|
+
response = nil
|
174
|
+
|
175
|
+
@tokens.any? { |token|
|
176
|
+
response = make_request(URI.parse(@session_uri.to_s() + "/#{token}"))
|
177
|
+
response.code.to_i == 200 && !response.body.nil? && response.body != ''
|
178
|
+
}
|
179
|
+
|
180
|
+
response
|
181
|
+
|
119
182
|
end
|
120
183
|
end
|
121
184
|
end
|
@@ -9,12 +9,17 @@ describe OmniAuth::Strategies::Crowd, :type=>:strategy do
|
|
9
9
|
[OmniAuth::Strategies::Crowd, {:crowd_server_url => @crowd_server_url,
|
10
10
|
:application_name => @application_name,
|
11
11
|
:application_password => @application_password,
|
12
|
-
:use_sessions => @using_sessions
|
12
|
+
:use_sessions => @using_sessions,
|
13
|
+
:sso_url => @sso_url,
|
14
|
+
:sso_url_image => @sso_url_image
|
15
|
+
}]
|
13
16
|
end
|
14
17
|
|
15
18
|
@using_sessions = false
|
19
|
+
@sso_url = nil
|
20
|
+
@sso_url_image = nil
|
16
21
|
let(:config) { OmniAuth::Strategies::Crowd::Configuration.new(strategy[1]) }
|
17
|
-
let(:validator) { OmniAuth::Strategies::Crowd::CrowdValidator.new(config, 'foo', 'bar') }
|
22
|
+
let(:validator) { OmniAuth::Strategies::Crowd::CrowdValidator.new(config, 'foo', 'bar', nil, nil) }
|
18
23
|
|
19
24
|
describe 'Authentication Request Body' do
|
20
25
|
|
@@ -37,28 +42,6 @@ BODY
|
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
40
|
-
describe 'Session Request Body' do
|
41
|
-
it 'should send username and password in session request' do
|
42
|
-
body = <<-BODY.strip
|
43
|
-
<authentication-context>
|
44
|
-
<username>foo</username>
|
45
|
-
<password>bar</password>
|
46
|
-
</authentication-context>
|
47
|
-
BODY
|
48
|
-
expect(validator.send(:make_session_request_body, 'foo', 'bar')).to eq(body)
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'should escape special characters username and password in session request' do
|
52
|
-
body = <<-BODY.strip
|
53
|
-
<authentication-context>
|
54
|
-
<username>foo</username>
|
55
|
-
<password>bar<</password>
|
56
|
-
</authentication-context>
|
57
|
-
BODY
|
58
|
-
expect(validator.send(:make_session_request_body, 'foo', 'bar<')).to eq(body)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
45
|
describe 'GET /auth/crowd' do
|
63
46
|
it 'should show the login form' do
|
64
47
|
get '/auth/crowd'
|
@@ -150,7 +133,7 @@ BODY
|
|
150
133
|
describe 'GET /auth/crowd/callback with credentials will fail' do
|
151
134
|
before do
|
152
135
|
stub_request(:post, "https://bogus_app:bogus_app_password@crowd.example.org/rest/usermanagement/latest/authentication?username=foo").
|
153
|
-
to_return(:
|
136
|
+
to_return(:status=>400)
|
154
137
|
get '/auth/crowd/callback', nil, 'rack.session'=>{'omniauth.crowd'=> {"username"=>"foo", "password"=>"ba"}}
|
155
138
|
end
|
156
139
|
it 'should fail' do
|
@@ -158,4 +141,247 @@ BODY
|
|
158
141
|
expect(last_response.headers['Location']).to match(/invalid_credentials/)
|
159
142
|
end
|
160
143
|
end
|
144
|
+
|
145
|
+
describe 'GET /auth/crowd without credentials will redirect to login form' do
|
146
|
+
|
147
|
+
sso_url = 'https://foo.bar'
|
148
|
+
|
149
|
+
before do
|
150
|
+
@using_sessions = true
|
151
|
+
@sso_url = sso_url
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should have the SSO button in the response body' do
|
155
|
+
|
156
|
+
found_legend = found_anchor = nil
|
157
|
+
|
158
|
+
get '/auth/crowd'
|
159
|
+
|
160
|
+
Nokogiri::HTML(last_response.body).xpath('//html/body/form/fieldset/*').each do |element|
|
161
|
+
|
162
|
+
if element.name === 'legend' && element.content() === 'SSO'
|
163
|
+
found_legend = true
|
164
|
+
elsif element.name === 'a' && element.attr('href') === "#{sso_url}/users/auth/crowd/callback"
|
165
|
+
found_anchor = true
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
expect(found_legend).to(be(true))
|
170
|
+
expect(found_anchor).to(be(true))
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
after do
|
175
|
+
@using_sessions = false
|
176
|
+
@sso_url = nil
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
describe 'GET /auth/crowd without credentials will redirect to login form which has custom image in the SSO link' do
|
182
|
+
|
183
|
+
sso_url = 'https://foo.bar'
|
184
|
+
sso_url_image = 'https://foo.bar/image.png'
|
185
|
+
|
186
|
+
before do
|
187
|
+
@using_sessions = true
|
188
|
+
@sso_url = sso_url
|
189
|
+
@sso_url_image = 'https://foo.bar/image.png'
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'should have the SSO button with a custom image in the response body' do
|
193
|
+
|
194
|
+
found_legend = found_anchor = found_image = false
|
195
|
+
|
196
|
+
get '/auth/crowd'
|
197
|
+
|
198
|
+
Nokogiri::HTML(last_response.body).xpath('//html/body/form/fieldset/*').each do |element|
|
199
|
+
|
200
|
+
if element.name === 'legend' && element.content() === 'SSO'
|
201
|
+
found_legend = true
|
202
|
+
elsif element.name === 'a' && element.attr('href') === "#{sso_url}/users/auth/crowd/callback"
|
203
|
+
|
204
|
+
found_anchor = true
|
205
|
+
|
206
|
+
if element.children.length === 1 && element.children.first.name === 'img' && element.children.first.attr('src') === sso_url_image
|
207
|
+
found_image = true
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
expect(found_legend).to(be(true))
|
214
|
+
expect(found_anchor).to(be(true))
|
215
|
+
expect(found_image).to(be(true))
|
216
|
+
|
217
|
+
end
|
218
|
+
|
219
|
+
after do
|
220
|
+
@using_sessions = false
|
221
|
+
@sso_url = nil
|
222
|
+
@sso_url_image = nil
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
describe 'GET /auth/crowd without credentials but with SSO cookie will redirect to callback' do
|
228
|
+
|
229
|
+
sso_url = 'https://foo.bar'
|
230
|
+
|
231
|
+
before do
|
232
|
+
|
233
|
+
@using_sessions = true
|
234
|
+
@sso_url = sso_url
|
235
|
+
|
236
|
+
set_cookie('crowd.token_key=foobar')
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'should redirect to callback' do
|
241
|
+
get '/auth/crowd'
|
242
|
+
expect(last_response).to be_redirect
|
243
|
+
expect(last_response.headers['Location']).to eq('http://example.org/auth/crowd/callback')
|
244
|
+
end
|
245
|
+
|
246
|
+
after do
|
247
|
+
|
248
|
+
@using_sessions = false
|
249
|
+
@sso_url = nil
|
250
|
+
|
251
|
+
clear_cookies()
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
describe 'POST /auth/crowd/callback without credentials but with SSO cookie will redirect to login form because session is invalid' do
|
258
|
+
|
259
|
+
sso_url = 'https://foo.bar'
|
260
|
+
token = 'foobar'
|
261
|
+
|
262
|
+
before do
|
263
|
+
|
264
|
+
@using_sessions = true
|
265
|
+
@sso_url = sso_url
|
266
|
+
|
267
|
+
stub_request(:get, "https://bogus_app:bogus_app_password@crowd.example.org/rest/usermanagement/latest/session/#{token}").
|
268
|
+
to_return(:status => [404])
|
269
|
+
|
270
|
+
set_cookie("crowd.token_key=#{token}")
|
271
|
+
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'should redirect to login form' do
|
275
|
+
post '/auth/crowd/callback'
|
276
|
+
expect(last_response).to be_redirect
|
277
|
+
expect(last_response.headers['Location']).to match(/invalid_credentials/)
|
278
|
+
end
|
279
|
+
|
280
|
+
after do
|
281
|
+
|
282
|
+
@using_sessions = false
|
283
|
+
@sso_url = nil
|
284
|
+
|
285
|
+
clear_cookies()
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
describe 'GET /auth/crowd/callback without credentials but with SSO cookie will succeed' do
|
292
|
+
|
293
|
+
sso_url = 'https://foo.bar'
|
294
|
+
token = 'rtk8eMvqq00EiGn5iJCMZQ00'
|
295
|
+
|
296
|
+
before do
|
297
|
+
|
298
|
+
@using_sessions = true
|
299
|
+
@sso_url = sso_url
|
300
|
+
|
301
|
+
stub_request(:get, "https://bogus_app:bogus_app_password@crowd.example.org/rest/usermanagement/latest/session/#{token}").
|
302
|
+
to_return(:status => 200, :body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'session.xml')))
|
303
|
+
stub_request(:post, "https://bogus_app:bogus_app_password@crowd.example.org/rest/usermanagement/latest/session/#{token}").
|
304
|
+
to_return(:status => 200)
|
305
|
+
stub_request(:get, "https://bogus_app:bogus_app_password@crowd.example.org/rest/usermanagement/latest/user/group/direct?username=foo").
|
306
|
+
to_return(:body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'groups.xml')))
|
307
|
+
|
308
|
+
set_cookie("crowd.token_key=#{token}")
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
it 'should return user data' do
|
313
|
+
|
314
|
+
auth = nil
|
315
|
+
|
316
|
+
get '/auth/crowd/callback'
|
317
|
+
|
318
|
+
auth = last_request.env['omniauth.auth']
|
319
|
+
|
320
|
+
expect(auth['provider']).to eq(:crowd)
|
321
|
+
expect(auth['uid']).to eq('foo')
|
322
|
+
expect(auth['info']).to be_kind_of(Hash)
|
323
|
+
expect(auth['info']['groups'].sort).to eq(["Developers", "jira-users"].sort)
|
324
|
+
|
325
|
+
end
|
326
|
+
|
327
|
+
after do
|
328
|
+
|
329
|
+
@using_sessions = false
|
330
|
+
@sso_url = nil
|
331
|
+
|
332
|
+
clear_cookies()
|
333
|
+
|
334
|
+
end
|
335
|
+
|
336
|
+
end
|
337
|
+
|
338
|
+
describe 'GET /auth/crowd/callback without credentials but with multiple SSO cookies will succeed because one of them is valid' do
|
339
|
+
|
340
|
+
sso_url = 'https://foo.bar'
|
341
|
+
|
342
|
+
before do
|
343
|
+
|
344
|
+
@using_sessions = true
|
345
|
+
@sso_url = sso_url
|
346
|
+
|
347
|
+
stub_request(:get, "https://bogus_app:bogus_app_password@crowd.example.org/rest/usermanagement/latest/session/foo").
|
348
|
+
to_return(:status => 404)
|
349
|
+
stub_request(:get, "https://bogus_app:bogus_app_password@crowd.example.org/rest/usermanagement/latest/session/fubar").
|
350
|
+
to_return(:status => 404)
|
351
|
+
stub_request(:get, "https://bogus_app:bogus_app_password@crowd.example.org/rest/usermanagement/latest/session/rtk8eMvqq00EiGn5iJCMZQ00").
|
352
|
+
to_return(:status => 200, :body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'session.xml')))
|
353
|
+
stub_request(:post, "https://bogus_app:bogus_app_password@crowd.example.org/rest/usermanagement/latest/session/rtk8eMvqq00EiGn5iJCMZQ00").
|
354
|
+
to_return(:status => 200)
|
355
|
+
stub_request(:get, "https://bogus_app:bogus_app_password@crowd.example.org/rest/usermanagement/latest/user/group/direct?username=foo").
|
356
|
+
to_return(:body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'groups.xml')))
|
357
|
+
|
358
|
+
header('Cookie', "crowd.token_key=foo;crowd.token_key=rtk8eMvqq00EiGn5iJCMZQ00;crowd.token_key=fubar")
|
359
|
+
|
360
|
+
end
|
361
|
+
|
362
|
+
it 'should return user data' do
|
363
|
+
|
364
|
+
auth = nil
|
365
|
+
|
366
|
+
get '/auth/crowd/callback'
|
367
|
+
|
368
|
+
auth = last_request.env['omniauth.auth']
|
369
|
+
|
370
|
+
expect(auth['provider']).to eq(:crowd)
|
371
|
+
expect(auth['uid']).to eq('foo')
|
372
|
+
expect(auth['info']).to be_kind_of(Hash)
|
373
|
+
expect(auth['info']['groups'].sort).to eq(["Developers", "jira-users"].sort)
|
374
|
+
|
375
|
+
end
|
376
|
+
|
377
|
+
after do
|
378
|
+
|
379
|
+
@using_sessions = false
|
380
|
+
@sso_url = nil
|
381
|
+
|
382
|
+
header('Cookie', nil)
|
383
|
+
|
384
|
+
end
|
385
|
+
|
386
|
+
end
|
161
387
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,139 +1,139 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omniauth_crowd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Di Marco
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: omniauth
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: nokogiri
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 1.4.4
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 1.4.4
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: activesupport
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rack
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rack-test
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: rspec
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - ~>
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: 3.0.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - ~>
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: 3.0.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: webmock
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- -
|
115
|
+
- - ">="
|
116
116
|
- !ruby/object:Gem::Version
|
117
117
|
version: '0'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- -
|
122
|
+
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: bundler
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
|
-
- -
|
129
|
+
- - ">"
|
130
130
|
- !ruby/object:Gem::Version
|
131
131
|
version: 1.0.0
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
|
-
- -
|
136
|
+
- - ">"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 1.0.0
|
139
139
|
description: This is an OmniAuth provider for Atlassian Crowd's REST API. It allows
|
@@ -144,9 +144,9 @@ executables: []
|
|
144
144
|
extensions: []
|
145
145
|
extra_rdoc_files: []
|
146
146
|
files:
|
147
|
-
- .document
|
148
|
-
- .gitignore
|
149
|
-
- .travis.yml
|
147
|
+
- ".document"
|
148
|
+
- ".gitignore"
|
149
|
+
- ".travis.yml"
|
150
150
|
- Gemfile
|
151
151
|
- Gemfile.lock
|
152
152
|
- LICENSE.txt
|
@@ -172,17 +172,17 @@ require_paths:
|
|
172
172
|
- lib
|
173
173
|
required_ruby_version: !ruby/object:Gem::Requirement
|
174
174
|
requirements:
|
175
|
-
- -
|
175
|
+
- - ">="
|
176
176
|
- !ruby/object:Gem::Version
|
177
177
|
version: '0'
|
178
178
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
179
179
|
requirements:
|
180
|
-
- -
|
180
|
+
- - ">="
|
181
181
|
- !ruby/object:Gem::Version
|
182
182
|
version: '0'
|
183
183
|
requirements: []
|
184
184
|
rubyforge_project:
|
185
|
-
rubygems_version: 2.
|
185
|
+
rubygems_version: 2.4.5.1
|
186
186
|
signing_key:
|
187
187
|
specification_version: 4
|
188
188
|
summary: An OmniAuth provider for Atlassian Crowd REST API
|