kensa 1.2.0rc7 → 1.2.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.
- data/.gitignore +1 -1
- data/Gemfile +5 -4
- data/Gemfile.lock +21 -27
- data/README.md +1 -1
- data/Rakefile +18 -10
- data/bin/kensa +10 -30
- data/kensa.gemspec +27 -20
- data/lib/heroku/kensa.rb +7 -9
- data/lib/heroku/kensa/check.rb +499 -0
- data/lib/heroku/kensa/client.rb +67 -89
- data/lib/heroku/kensa/git.rb +39 -0
- data/lib/heroku/kensa/manifest.rb +41 -8
- data/lib/heroku/kensa/screen.rb +37 -0
- data/lib/heroku/kensa/sso.rb +22 -22
- data/lib/heroku/kensa/version.rb +1 -2
- data/test/all_check_test.rb +25 -0
- data/test/create_test.rb +40 -6
- data/test/deprovision_check_test.rb +39 -0
- data/test/helper.rb +74 -11
- data/test/init_test.rb +54 -0
- data/test/manifest_check_test.rb +94 -0
- data/test/manifest_test.rb +37 -33
- data/test/plan_change_check_test.rb +31 -0
- data/test/provision_check_test.rb +51 -0
- data/test/provision_response_check_test.rb +81 -0
- data/test/resources/runner.rb +1 -0
- data/test/resources/server.rb +227 -0
- data/test/sso_check_test.rb +58 -0
- data/test/sso_test.rb +113 -53
- metadata +97 -91
- data/test.rb +0 -1
- data/test/deprovision_test.rb +0 -30
- data/test/lib/dependencies.rb +0 -12
- data/test/lib/formatter.rb +0 -84
- data/test/lib/http.rb +0 -60
- data/test/lib/response.rb +0 -12
- data/test/manifest_generation_test.rb +0 -32
- data/test/plan_change_test.rb +0 -30
- data/test/provision_test.rb +0 -84
- data/test/resources/provider_server.rb +0 -81
- data/test/resources/views/index.haml +0 -6
- data/test/sso_launch_test.rb +0 -130
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class PlanChangeCheckTest < Test::Unit::TestCase
|
4
|
+
include Heroku::Kensa
|
5
|
+
|
6
|
+
%w{get post}.each do |method|
|
7
|
+
context "with sso #{method}" do
|
8
|
+
setup do
|
9
|
+
@data = Manifest.new(:method => method).skeleton.merge :id => 123, :plan => 'premium'
|
10
|
+
@data['api']['password'] = 'secret'
|
11
|
+
end
|
12
|
+
|
13
|
+
def check ; PlanChangeCheck ; end
|
14
|
+
|
15
|
+
test "working plan change call" do
|
16
|
+
use_provider_endpoint "working"
|
17
|
+
assert_valid
|
18
|
+
end
|
19
|
+
|
20
|
+
test "detects invalid status" do
|
21
|
+
use_provider_endpoint "invalid-status"
|
22
|
+
assert_invalid
|
23
|
+
end
|
24
|
+
|
25
|
+
test "detects missing auth" do
|
26
|
+
use_provider_endpoint "invalid-missing-auth"
|
27
|
+
assert_invalid
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class ProvisionCheckTest < Test::Unit::TestCase
|
4
|
+
include Heroku::Kensa
|
5
|
+
|
6
|
+
def check ; ProvisionCheck ; end
|
7
|
+
|
8
|
+
['get', 'post'].each do |method|
|
9
|
+
context "with sso #{method}" do
|
10
|
+
setup do
|
11
|
+
@data = Manifest.new(:method => method).skeleton
|
12
|
+
@data['api']['password'] = 'secret'
|
13
|
+
end
|
14
|
+
|
15
|
+
test "trims url" do
|
16
|
+
c = check.new(@data)
|
17
|
+
assert_equal c.url, 'http://localhost:4567'
|
18
|
+
end
|
19
|
+
|
20
|
+
test "working provision call" do
|
21
|
+
use_provider_endpoint "working"
|
22
|
+
assert_valid
|
23
|
+
end
|
24
|
+
|
25
|
+
test "detects invalid JSON" do
|
26
|
+
use_provider_endpoint "invalid-json"
|
27
|
+
assert_invalid
|
28
|
+
end
|
29
|
+
|
30
|
+
test "detects invalid response" do
|
31
|
+
use_provider_endpoint "invalid-response"
|
32
|
+
assert_invalid
|
33
|
+
end
|
34
|
+
|
35
|
+
test "detects invalid status" do
|
36
|
+
use_provider_endpoint "invalid-status"
|
37
|
+
assert_invalid
|
38
|
+
end
|
39
|
+
|
40
|
+
test "detects missing id" do
|
41
|
+
use_provider_endpoint "invalid-missing-id"
|
42
|
+
assert_invalid
|
43
|
+
end
|
44
|
+
|
45
|
+
test "detects missing auth" do
|
46
|
+
use_provider_endpoint "invalid-missing-auth"
|
47
|
+
assert_invalid
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class ProvisionResponseCheckTest < Test::Unit::TestCase
|
4
|
+
include Heroku::Kensa
|
5
|
+
|
6
|
+
def check ; ProvisionResponseCheck ; end
|
7
|
+
|
8
|
+
setup do
|
9
|
+
@response = { "id" => "123",
|
10
|
+
"config" => {
|
11
|
+
"MYADDON_URL" => "http://example.com/resource",
|
12
|
+
"MYADDON_CONFIG" => "value"
|
13
|
+
}}
|
14
|
+
@data = Manifest.new.skeleton.merge(:provision_response => @response)
|
15
|
+
@data['api']['config_vars'] << "MYADDON_CONFIG"
|
16
|
+
end
|
17
|
+
|
18
|
+
test "is valid if no errors" do
|
19
|
+
assert_valid
|
20
|
+
end
|
21
|
+
|
22
|
+
test "has an id" do
|
23
|
+
@response.delete("id")
|
24
|
+
assert_invalid
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "when config is present" do
|
28
|
+
|
29
|
+
test "is a hash" do
|
30
|
+
@response["config"] = ""
|
31
|
+
assert_invalid
|
32
|
+
end
|
33
|
+
|
34
|
+
test "each key is previously set in the manifest" do
|
35
|
+
@response["config"]["MYSQL_URL"] = "http://..."
|
36
|
+
assert_invalid
|
37
|
+
end
|
38
|
+
|
39
|
+
test "each value is a string" do
|
40
|
+
@response["config"]["MYADDON_URL"] = {}
|
41
|
+
assert_invalid
|
42
|
+
end
|
43
|
+
|
44
|
+
test "asserts _URL vars are valid URIs" do
|
45
|
+
@response["config"]["MYADDON_URL"] = "abc:"
|
46
|
+
assert_invalid
|
47
|
+
end
|
48
|
+
|
49
|
+
test "asserts _URL vars have a host" do
|
50
|
+
@response["config"]["MYADDON_URL"] = "path"
|
51
|
+
assert_invalid
|
52
|
+
end
|
53
|
+
|
54
|
+
test "asserts _URL vars have a scheme" do
|
55
|
+
@response["config"]["MYADDON_URL"] = "//host/path"
|
56
|
+
assert_invalid
|
57
|
+
end
|
58
|
+
|
59
|
+
test "doesn't run URI test against other vars" do
|
60
|
+
@response["config"]['MYADDON_CONFIG'] = "abc:"
|
61
|
+
assert_valid
|
62
|
+
end
|
63
|
+
|
64
|
+
test "doesn't allow localhost URIs on production" do
|
65
|
+
@data[:env] = 'production'
|
66
|
+
@response["config"]["MYADDON_URL"] = "http://localhost/abc"
|
67
|
+
assert_invalid
|
68
|
+
end
|
69
|
+
|
70
|
+
test "asserts all vars in manifest are in response" do
|
71
|
+
@response["config"].delete('MYADDON_CONFIG')
|
72
|
+
assert_invalid
|
73
|
+
end
|
74
|
+
|
75
|
+
test "is valid otherwise" do
|
76
|
+
@response["config"]["MYADDON_URL"] = "http://localhost/abc"
|
77
|
+
assert_valid
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
exit(1) if ARGV.first == 'fail'
|
@@ -0,0 +1,227 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
enable :sessions
|
6
|
+
|
7
|
+
helpers do
|
8
|
+
def heroku_only!
|
9
|
+
unless auth_heroku?
|
10
|
+
response['WWW-Authenticate'] = %(Basic realm="Kensa Test Server")
|
11
|
+
unauthorized!(401)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def auth_heroku?
|
16
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
17
|
+
@auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == ['myaddon', 'secret']
|
18
|
+
end
|
19
|
+
|
20
|
+
def unauthorized!(status=403)
|
21
|
+
throw(:halt, [status, "Not authorized\n"])
|
22
|
+
end
|
23
|
+
|
24
|
+
def make_token
|
25
|
+
Digest::SHA1.hexdigest([params[:id], 'SSO_SALT', params[:timestamp]].join(':'))
|
26
|
+
end
|
27
|
+
|
28
|
+
def json_must_include(keys)
|
29
|
+
params = JSON.parse(request.body.read)
|
30
|
+
keys.each do |param|
|
31
|
+
raise "#{param} not included with request" unless params.keys.include? param
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def login(heroku_user=true)
|
36
|
+
session.clear
|
37
|
+
session[:logged_in] = true
|
38
|
+
session[:heroku] = heroku_user
|
39
|
+
redirect '/'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
post '/heroku/resources' do
|
44
|
+
heroku_only!
|
45
|
+
{ :id => 123 }.to_json
|
46
|
+
end
|
47
|
+
|
48
|
+
post '/working/heroku/resources' do
|
49
|
+
json_must_include(%w{heroku_id plan callback_url logplex_token options})
|
50
|
+
heroku_only!
|
51
|
+
{ :id => 123 }.to_json
|
52
|
+
end
|
53
|
+
|
54
|
+
post '/cmd-line-options/heroku/resources' do
|
55
|
+
heroku_only!
|
56
|
+
{ :id => 123 }.to_json
|
57
|
+
end
|
58
|
+
|
59
|
+
post '/invalid-json/heroku/resources' do
|
60
|
+
heroku_only!
|
61
|
+
'invalidjson'
|
62
|
+
end
|
63
|
+
|
64
|
+
post '/invalid-response/heroku/resources' do
|
65
|
+
heroku_only!
|
66
|
+
nil.to_json
|
67
|
+
end
|
68
|
+
|
69
|
+
post '/invalid-status/heroku/resources' do
|
70
|
+
heroku_only!
|
71
|
+
status 422
|
72
|
+
{ :id => 123 }.to_json
|
73
|
+
end
|
74
|
+
|
75
|
+
post '/invalid-missing-id/heroku/resources' do
|
76
|
+
heroku_only!
|
77
|
+
{ :noid => 123 }.to_json
|
78
|
+
end
|
79
|
+
|
80
|
+
post '/invalid-missing-auth/heroku/resources' do
|
81
|
+
{ :id => 123 }.to_json
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
put '/working/heroku/resources/:id' do
|
86
|
+
json_must_include(%w{heroku_id plan})
|
87
|
+
heroku_only!
|
88
|
+
{}.to_json
|
89
|
+
end
|
90
|
+
|
91
|
+
put '/invalid-missing-auth/heroku/resources/:id' do
|
92
|
+
{ :id => 123 }.to_json
|
93
|
+
end
|
94
|
+
|
95
|
+
put '/invalid-status/heroku/resources/:id' do
|
96
|
+
heroku_only!
|
97
|
+
status 422
|
98
|
+
{}.to_json
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
delete '/working/heroku/resources/:id' do
|
103
|
+
heroku_only!
|
104
|
+
"Ok"
|
105
|
+
end
|
106
|
+
|
107
|
+
def sso
|
108
|
+
unauthorized! unless params[:id] && params[:token]
|
109
|
+
unauthorized! unless params[:timestamp].to_i > (Time.now-60*2).to_i
|
110
|
+
unauthorized! unless params[:token] == make_token
|
111
|
+
response.set_cookie('heroku-nav-data', params['nav-data'])
|
112
|
+
login
|
113
|
+
end
|
114
|
+
|
115
|
+
get '/working/heroku/resources/:id' do
|
116
|
+
sso
|
117
|
+
end
|
118
|
+
|
119
|
+
post '/working/sso/login' do
|
120
|
+
puts params.inspect
|
121
|
+
sso
|
122
|
+
end
|
123
|
+
|
124
|
+
def notoken
|
125
|
+
unauthorized! unless params[:id] && params[:token]
|
126
|
+
unauthorized! unless params[:timestamp].to_i > (Time.now-60*2).to_i
|
127
|
+
response.set_cookie('heroku-nav-data', params['nav-data'])
|
128
|
+
login
|
129
|
+
end
|
130
|
+
|
131
|
+
get '/notoken/heroku/resources/:id' do
|
132
|
+
notoken
|
133
|
+
end
|
134
|
+
|
135
|
+
post '/notoken/sso/login' do
|
136
|
+
notoken
|
137
|
+
end
|
138
|
+
|
139
|
+
def notimestamp
|
140
|
+
unauthorized! unless params[:id] && params[:token]
|
141
|
+
unauthorized! unless params[:token] == make_token
|
142
|
+
response.set_cookie('heroku-nav-data', params['nav-data'])
|
143
|
+
login
|
144
|
+
end
|
145
|
+
|
146
|
+
get '/notimestamp/heroku/resources/:id' do
|
147
|
+
notimestamp
|
148
|
+
end
|
149
|
+
|
150
|
+
post '/notimestamp/sso/login' do
|
151
|
+
notimestamp
|
152
|
+
end
|
153
|
+
|
154
|
+
def nolayout
|
155
|
+
unauthorized! unless params[:id] && params[:token]
|
156
|
+
unauthorized! unless params[:timestamp].to_i > (Time.now-60*2).to_i
|
157
|
+
unauthorized! unless params[:token] == make_token
|
158
|
+
response.set_cookie('heroku-nav-data', params['nav-data'])
|
159
|
+
login(false)
|
160
|
+
end
|
161
|
+
|
162
|
+
get '/nolayout/heroku/resources/:id' do
|
163
|
+
nolayout
|
164
|
+
end
|
165
|
+
|
166
|
+
post '/nolayout/sso/login' do
|
167
|
+
nolayout
|
168
|
+
end
|
169
|
+
|
170
|
+
def nocookie
|
171
|
+
unauthorized! unless params[:id] && params[:token]
|
172
|
+
unauthorized! unless params[:timestamp].to_i > (Time.now-60*2).to_i
|
173
|
+
unauthorized! unless params[:token] == make_token
|
174
|
+
login
|
175
|
+
end
|
176
|
+
|
177
|
+
get '/nocookie/heroku/resources/:id' do
|
178
|
+
nocookie
|
179
|
+
end
|
180
|
+
|
181
|
+
post '/nocookie/sso/login' do
|
182
|
+
nocookie
|
183
|
+
end
|
184
|
+
|
185
|
+
def badcookie
|
186
|
+
unauthorized! unless params[:id] && params[:token]
|
187
|
+
unauthorized! unless params[:timestamp].to_i > (Time.now-60*2).to_i
|
188
|
+
unauthorized! unless params[:token] == make_token
|
189
|
+
response.set_cookie('heroku-nav-data', 'wrong value')
|
190
|
+
login
|
191
|
+
end
|
192
|
+
|
193
|
+
get '/badcookie/heroku/resources/:id' do
|
194
|
+
badcookie
|
195
|
+
end
|
196
|
+
|
197
|
+
post '/badcookie/sso/login' do
|
198
|
+
badcookie
|
199
|
+
end
|
200
|
+
|
201
|
+
def sso_user
|
202
|
+
head 404 unless params[:email] == 'username@example.com'
|
203
|
+
sso
|
204
|
+
end
|
205
|
+
|
206
|
+
get '/user/heroku/resources/:id' do
|
207
|
+
sso_user
|
208
|
+
end
|
209
|
+
|
210
|
+
post '/user/sso/login' do
|
211
|
+
sso_user
|
212
|
+
end
|
213
|
+
|
214
|
+
get '/' do
|
215
|
+
unauthorized! unless session[:logged_in]
|
216
|
+
haml :index
|
217
|
+
end
|
218
|
+
|
219
|
+
__END__
|
220
|
+
|
221
|
+
@@ index
|
222
|
+
%html
|
223
|
+
%body
|
224
|
+
- if session[:heroku]
|
225
|
+
#heroku-header
|
226
|
+
%h1 Heroku
|
227
|
+
%h1 Sample Addon
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class SsoCheckTest < Test::Unit::TestCase
|
4
|
+
include Heroku::Kensa
|
5
|
+
|
6
|
+
|
7
|
+
def check ; SsoCheck ; end
|
8
|
+
%w{get post}.each do |method|
|
9
|
+
context "via #{method}" do
|
10
|
+
setup do
|
11
|
+
@data = Manifest.new(:sso => true, :method => method).
|
12
|
+
skeleton.merge :id => 123
|
13
|
+
@data['api']['sso_salt'] = 'SSO_SALT'
|
14
|
+
end
|
15
|
+
|
16
|
+
test "working sso request" do
|
17
|
+
use_provider_endpoint('working', 'sso')
|
18
|
+
assert_valid
|
19
|
+
end
|
20
|
+
|
21
|
+
test "rejects bad token" do
|
22
|
+
use_provider_endpoint("notoken", 'sso')
|
23
|
+
assert_invalid
|
24
|
+
end
|
25
|
+
|
26
|
+
test "rejects old timestamp" do
|
27
|
+
use_provider_endpoint("notimestamp", 'sso')
|
28
|
+
assert_invalid
|
29
|
+
end
|
30
|
+
|
31
|
+
test "reject omitted sso salt" do
|
32
|
+
@data['api'].delete 'sso_salt'
|
33
|
+
use_provider_endpoint("working", 'sso')
|
34
|
+
assert_invalid
|
35
|
+
end
|
36
|
+
|
37
|
+
test "reject missing heroku layout" do
|
38
|
+
use_provider_endpoint("nolayout", 'sso')
|
39
|
+
assert_invalid
|
40
|
+
end
|
41
|
+
|
42
|
+
test "reject missing cookie" do
|
43
|
+
use_provider_endpoint("nocookie", 'sso')
|
44
|
+
assert_invalid
|
45
|
+
end
|
46
|
+
|
47
|
+
test "reject invalid cookie value" do
|
48
|
+
use_provider_endpoint("badcookie", 'sso')
|
49
|
+
assert_invalid
|
50
|
+
end
|
51
|
+
|
52
|
+
test "sends email param" do
|
53
|
+
use_provider_endpoint("user", 'sso')
|
54
|
+
assert_valid
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|