kensa 1.1.3 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source :gemcutter
2
+ gemspec
3
+ group :development do
4
+ gem 'json'
5
+ gem 'contest'
6
+ gem 'haml'
7
+ gem 'jeweler'
8
+ gem 'rr'
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,58 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ kensa (1.1.4)
5
+ kensa
6
+ launchy (>= 0.3.2)
7
+ mechanize (~> 1.0.0)
8
+ rest-client (< 1.7.0, >= 1.4.0)
9
+ term-ansicolor (~> 1.0)
10
+ yajl-ruby (~> 0.6)
11
+
12
+ GEM
13
+ remote: http://rubygems.org/
14
+ specs:
15
+ addressable (2.2.6)
16
+ ansi (1.3.0)
17
+ contest (0.1.3)
18
+ git (1.2.5)
19
+ haml (3.1.2)
20
+ jeweler (1.6.4)
21
+ bundler (~> 1.0)
22
+ git (>= 1.2.5)
23
+ rake
24
+ json (1.5.3)
25
+ launchy (2.0.5)
26
+ addressable (~> 2.2.6)
27
+ mechanize (1.0.0)
28
+ nokogiri (>= 1.2.1)
29
+ mime-types (1.16)
30
+ nokogiri (1.5.0)
31
+ rack (1.3.2)
32
+ rake (0.9.2)
33
+ rest-client (1.6.3)
34
+ mime-types (>= 1.16)
35
+ rr (1.0.3)
36
+ sinatra (1.2.6)
37
+ rack (~> 1.1)
38
+ tilt (>= 1.2.2, < 2.0)
39
+ term-ansicolor (1.0.6)
40
+ tilt (1.3.2)
41
+ timecop (0.3.5)
42
+ turn (0.8.2)
43
+ ansi (>= 1.2.2)
44
+ yajl-ruby (0.8.3)
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ contest
51
+ haml
52
+ jeweler
53
+ json
54
+ kensa!
55
+ rr
56
+ sinatra (>= 0.9)
57
+ timecop (>= 0.3.5)
58
+ turn
data/Rakefile CHANGED
@@ -2,8 +2,9 @@ desc 'Run all unit tests'
2
2
  task :test do
3
3
  fork do
4
4
  exec "ruby test/resources/server.rb > /dev/null 2>&1"
5
+ #exec "ruby test/resources/server.rb > log.txt 2>&1"
5
6
  end
6
- system "turn"
7
+ system "turn test"
7
8
  system "ps -ax | grep test/resources/server.rb | grep -v grep | awk '{print $1}' | xargs kill"
8
9
  end
9
10
 
@@ -19,7 +20,7 @@ begin
19
20
  gemspec.description = "Kensa is a command-line tool to help add-on providers integrating their services with Heroku. It manages manifest files, and provides a TDD-like approach for programmers to test and develop their APIs."
20
21
  gemspec.email = "pedro@heroku.com"
21
22
  gemspec.homepage = "http://provider.heroku.com/resources"
22
- gemspec.authors = ["Blake Mizerany", "Pedro Belo", "Adam Wiggins"]
23
+ gemspec.authors = ["Blake Mizerany", "Pedro Belo", "Adam Wiggins", "Chris Continanza"]
23
24
 
24
25
  gemspec.add_development_dependency(%q<turn>, [">= 0"])
25
26
  gemspec.add_development_dependency(%q<contest>, [">= 0"])
data/bin/kensa CHANGED
@@ -1,5 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'rubygems'
3
7
  require 'optparse'
4
8
  require 'heroku/kensa'
5
9
  require 'heroku/kensa/client'
@@ -56,6 +60,9 @@ OPTIONS
56
60
  --without-sso
57
61
  Skip single sign-on authentication when doing provision calls
58
62
 
63
+ --post
64
+ Use HTTP POST for single sign-on instead of GET
65
+
59
66
  COMMANDS
60
67
 
61
68
  init Creates a skeleton manifest
data/kensa.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{kensa}
8
- s.version = "1.1.3"
8
+ s.version = "1.1.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Blake Mizerany", "Pedro Belo", "Adam Wiggins"]
12
- s.date = %q{2011-02-21}
11
+ s.authors = ["Blake Mizerany", "Pedro Belo", "Adam Wiggins", 'Chris Continanza']
12
+ s.date = %q{2011-08-22}
13
13
  s.default_executable = %q{kensa}
14
14
  s.description = %q{Kensa is a command-line tool to help add-on providers integrating their services with Heroku. It manages manifest files, and provides a TDD-like approach for programmers to test and develop their APIs.}
15
15
  s.email = %q{pedro@heroku.com}
@@ -18,6 +18,8 @@ Gem::Specification.new do |s|
18
18
  "README.md"
19
19
  ]
20
20
  s.files = [
21
+ "Gemfile",
22
+ "Gemfile.lock",
21
23
  "README.md",
22
24
  "Rakefile",
23
25
  "bin/kensa",
@@ -27,6 +29,7 @@ Gem::Specification.new do |s|
27
29
  "lib/heroku/kensa/client.rb",
28
30
  "lib/heroku/kensa/http.rb",
29
31
  "lib/heroku/kensa/manifest.rb",
32
+ "lib/heroku/kensa/post_proxy.rb",
30
33
  "lib/heroku/kensa/sso.rb",
31
34
  "set-env.sh",
32
35
  "test/all_check_test.rb",
@@ -44,33 +47,23 @@ Gem::Specification.new do |s|
44
47
  ]
45
48
  s.homepage = %q{http://provider.heroku.com/resources}
46
49
  s.require_paths = ["lib"]
47
- s.rubygems_version = %q{1.3.6}
50
+ s.rubygems_version = %q{1.6.2}
48
51
  s.summary = %q{Tool to help Heroku add-on providers integrating their services}
49
- s.test_files = [
50
- "test/all_check_test.rb",
51
- "test/deprovision_check_test.rb",
52
- "test/helper.rb",
53
- "test/manifest_check_test.rb",
54
- "test/manifest_test.rb",
55
- "test/plan_change_check_test.rb",
56
- "test/provision_check_test.rb",
57
- "test/provision_response_check_test.rb",
58
- "test/resources/runner.rb",
59
- "test/resources/server.rb",
60
- "test/sso_check_test.rb",
61
- "test/sso_test.rb"
62
- ]
63
52
 
64
53
  if s.respond_to? :specification_version then
65
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
66
54
  s.specification_version = 3
67
55
 
68
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
56
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
69
57
  s.add_development_dependency(%q<turn>, [">= 0"])
70
58
  s.add_development_dependency(%q<contest>, [">= 0"])
71
59
  s.add_development_dependency(%q<timecop>, [">= 0.3.5"])
72
60
  s.add_development_dependency(%q<sinatra>, [">= 0.9"])
73
- s.add_runtime_dependency(%q<rest-client>, [">= 1.4.0", "< 1.7.0"])
61
+ s.add_development_dependency(%q<json>, [">= 0"])
62
+ s.add_development_dependency(%q<contest>, [">= 0"])
63
+ s.add_development_dependency(%q<haml>, [">= 0"])
64
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
65
+ s.add_development_dependency(%q<rr>, [">= 0"])
66
+ s.add_runtime_dependency(%q<rest-client>, ["< 1.7.0", ">= 1.4.0"])
74
67
  s.add_runtime_dependency(%q<yajl-ruby>, ["~> 0.6"])
75
68
  s.add_runtime_dependency(%q<term-ansicolor>, ["~> 1.0"])
76
69
  s.add_runtime_dependency(%q<launchy>, [">= 0.3.2"])
@@ -80,7 +73,12 @@ Gem::Specification.new do |s|
80
73
  s.add_dependency(%q<contest>, [">= 0"])
81
74
  s.add_dependency(%q<timecop>, [">= 0.3.5"])
82
75
  s.add_dependency(%q<sinatra>, [">= 0.9"])
83
- s.add_dependency(%q<rest-client>, [">= 1.4.0", "< 1.7.0"])
76
+ s.add_dependency(%q<json>, [">= 0"])
77
+ s.add_dependency(%q<contest>, [">= 0"])
78
+ s.add_dependency(%q<haml>, [">= 0"])
79
+ s.add_dependency(%q<jeweler>, [">= 0"])
80
+ s.add_dependency(%q<rr>, [">= 0"])
81
+ s.add_dependency(%q<rest-client>, ["< 1.7.0", ">= 1.4.0"])
84
82
  s.add_dependency(%q<yajl-ruby>, ["~> 0.6"])
85
83
  s.add_dependency(%q<term-ansicolor>, ["~> 1.0"])
86
84
  s.add_dependency(%q<launchy>, [">= 0.3.2"])
@@ -91,7 +89,12 @@ Gem::Specification.new do |s|
91
89
  s.add_dependency(%q<contest>, [">= 0"])
92
90
  s.add_dependency(%q<timecop>, [">= 0.3.5"])
93
91
  s.add_dependency(%q<sinatra>, [">= 0.9"])
94
- s.add_dependency(%q<rest-client>, [">= 1.4.0", "< 1.7.0"])
92
+ s.add_dependency(%q<json>, [">= 0"])
93
+ s.add_dependency(%q<contest>, [">= 0"])
94
+ s.add_dependency(%q<haml>, [">= 0"])
95
+ s.add_dependency(%q<jeweler>, [">= 0"])
96
+ s.add_dependency(%q<rr>, [">= 0"])
97
+ s.add_dependency(%q<rest-client>, ["< 1.7.0", ">= 1.4.0"])
95
98
  s.add_dependency(%q<yajl-ruby>, ["~> 0.6"])
96
99
  s.add_dependency(%q<term-ansicolor>, ["~> 1.0"])
97
100
  s.add_dependency(%q<launchy>, [">= 0.3.2"])
@@ -8,7 +8,6 @@ module Heroku
8
8
  module Kensa
9
9
 
10
10
  class NilScreen
11
-
12
11
  def test(msg)
13
12
  end
14
13
 
@@ -25,6 +24,11 @@ module Heroku
25
24
  end
26
25
  end
27
26
 
27
+ class STDOUTScreen
28
+ [:test, :check, :error, :result, :message].each do |method|
29
+ eval %{ def #{method}(*args)\n STDOUT.puts *args\n end }
30
+ end
31
+ end
28
32
 
29
33
  class Check
30
34
  attr_accessor :screen, :data
@@ -376,8 +380,12 @@ module Heroku
376
380
  @agent ||= Mechanize.new
377
381
  end
378
382
 
379
- def mechanize_get url
380
- page = agent.get(url)
383
+ def mechanize_get
384
+ if @sso.POST?
385
+ page = agent.post(@sso.post_url, @sso.query_params)
386
+ else
387
+ page = agent.get(@sso.get_url)
388
+ end
381
389
  return page, 200
382
390
  rescue Mechanize::ResponseCodeError => error
383
391
  return nil, error.response_code.to_i
@@ -385,37 +393,43 @@ module Heroku
385
393
  error("connection refused to #{url}")
386
394
  end
387
395
 
396
+ def check(msg)
397
+ @sso = Sso.new(data)
398
+ super
399
+ end
400
+
388
401
  def call!
389
402
  error("need an sso salt to perform sso test") unless data['api']['sso_salt']
390
403
 
391
- sso = Sso.new(data)
392
- t = Time.now.to_i
404
+ sso = Sso.new(data)
405
+ verb = sso.POST? ? 'POST' : 'GET'
406
+ test "#{verb} #{sso.path}"
393
407
 
394
- test "GET #{sso.path}"
395
408
  check "validates token" do
396
- page, respcode = mechanize_get sso.url + sso.path + "?token=invalid&timestamp=#{t}"
397
- error("expected 403, got 200") unless respcode == 403
409
+ @sso.token = 'invalid'
410
+ page, respcode = mechanize_get
411
+ error("expected 403, got #{respcode}") unless respcode == 403
398
412
  true
399
413
  end
400
414
 
401
415
  check "validates timestamp" do
402
- prev = (Time.now - 60*6).to_i
403
- page, respcode = mechanize_get sso.url + sso.path + "?token=#{sso.make_token(prev)}&timestamp=#{prev}"
404
- error("expected 403, got 200") unless respcode == 403
416
+ @sso.timestamp = (Time.now - 60*6).to_i
417
+ page, respcode = mechanize_get
418
+ error("expected 403, got #{respcode}") unless respcode == 403
405
419
  true
406
420
  end
407
421
 
408
422
  page_logged_in = nil
409
423
  check "logs in" do
410
- page_logged_in, respcode = mechanize_get sso.url + sso.path + sso.querystring
424
+ page_logged_in, respcode = mechanize_get
411
425
  error("expected 200, got #{respcode}") unless respcode == 200
412
426
  true
413
427
  end
414
428
 
415
429
  check "creates the heroku-nav-data cookie" do
416
- cookie = agent.cookie_jar.cookies(URI.parse(sso.full_url)).detect { |c| c.name == 'heroku-nav-data' }
430
+ cookie = agent.cookie_jar.cookies(URI.parse(@sso.full_url)).detect { |c| c.name == 'heroku-nav-data' }
417
431
  error("could not find cookie heroku-nav-data") unless cookie
418
- error("expected #{sso.sample_nav_data}, got #{cookie.value}") unless cookie.value == sso.sample_nav_data
432
+ error("expected #{@sso.sample_nav_data}, got #{cookie.value}") unless cookie.value == @sso.sample_nav_data
419
433
  true
420
434
  end
421
435
 
@@ -58,9 +58,9 @@ module Heroku
58
58
  def sso
59
59
  id = @args.shift || abort("! no id specified; see usage")
60
60
  data = Yajl::Parser.parse(resolve_manifest).merge(:id => id)
61
- sso = Sso.new(data.merge(@options))
62
- puts "Opening #{sso.full_url}"
63
- Launchy.open sso.full_url
61
+ sso = Sso.new(data.merge(@options)).start
62
+ puts sso.message
63
+ Launchy.open sso.sso_url
64
64
  end
65
65
 
66
66
  def push
@@ -0,0 +1,33 @@
1
+ require 'webrick'
2
+
3
+ class Heroku::Kensa::PostProxy < WEBrick::HTTPServer
4
+ def initialize(sso)
5
+ @params = sso.query_params
6
+ @sso = sso
7
+ super :Port => sso.proxy_port, :AccessLog => WEBrick::Log.new(StringIO.new),
8
+ :Logger => WEBrick::Log.new(StringIO.new)
9
+ end
10
+
11
+ def service(req, res)
12
+ res.status = 200
13
+ res.body = <<-HTML
14
+ <html>
15
+ <head>
16
+ <script type="text/javascript">
17
+ window.onload = function() { document.forms[0].submit() }
18
+ </script>
19
+ </head>
20
+ <body>
21
+ <form action="#{@sso.post_url}" method="POST">
22
+ #{ @params.map do |key, value|
23
+ %|<input type="hidden" name="#{key}" value="#{value}" />|
24
+ end.join("\n")
25
+ }
26
+ </form>
27
+ </body>
28
+ </html>
29
+ HTML
30
+ res["Content-Lengh"] = res.body.size
31
+ @status = :Shutdown
32
+ end
33
+ end
@@ -3,7 +3,7 @@ require 'restclient'
3
3
  module Heroku
4
4
  module Kensa
5
5
  class Sso
6
- attr_accessor :id, :url
6
+ attr_accessor :id, :url, :proxy_port, :timestamp, :token
7
7
 
8
8
  def initialize(data)
9
9
  @id = data[:id]
@@ -11,15 +11,42 @@ module Heroku
11
11
 
12
12
  env = data.fetch :env, 'test'
13
13
  @url = data["api"][env].chomp('/')
14
+ @use_post = data['api']['sso'].to_s.match(/post/i)
15
+ @proxy_port = find_available_port
16
+ @timestamp = Time.now.to_i
17
+ @token = make_token(@timestamp)
14
18
  end
15
19
 
16
20
  def path
17
- "/heroku/resources/#{id}"
21
+ extra = self.POST? ? '/sso' : ''
22
+ "/heroku/resources/#{id}#{extra}"
23
+ end
24
+
25
+ def POST?
26
+ @use_post
27
+ end
28
+
29
+ def sso_url
30
+ if self.POST?
31
+ "http://localhost:#{@proxy_port}/"
32
+ else
33
+ full_url
34
+ end
18
35
  end
19
36
 
20
37
  def full_url
21
38
  [ url, path, querystring ].join
22
39
  end
40
+ alias get_url full_url
41
+
42
+ def post_url
43
+ [ url, path ].join
44
+ end
45
+
46
+ def timestamp=(other)
47
+ @timestamp = other
48
+ @token = make_token(@timestamp)
49
+ end
23
50
 
24
51
  def make_token(t)
25
52
  Digest::SHA1.hexdigest([@id, @salt, t].join(':'))
@@ -27,9 +54,18 @@ module Heroku
27
54
 
28
55
  def querystring
29
56
  return '' unless @salt
57
+ '?' + query_data
58
+ end
59
+
60
+ def query_data
61
+ query_params.map{|p| p.join('=')}.join('&')
62
+ end
30
63
 
31
- t = Time.now.to_i
32
- "?token=#{make_token(t)}&timestamp=#{t}&nav-data=#{sample_nav_data}"
64
+ def query_params
65
+ { 'token' => @token,
66
+ 'timestamp' => @timestamp.to_s,
67
+ 'nav-data' => sample_nav_data,
68
+ 'user' => 'username@example.com' }
33
69
  end
34
70
 
35
71
  def sample_nav_data
@@ -50,6 +86,37 @@ module Heroku
50
86
  base64.tr('+/','-_')
51
87
  end
52
88
 
89
+ def message
90
+ if self.POST?
91
+ "POSTing #{query_data} to #{post_url} via proxy on port #{@proxy_port}"
92
+ else
93
+ "Opening #{full_url}"
94
+ end
95
+ end
96
+
97
+ def start
98
+ run_proxy
99
+ self
100
+ end
101
+
102
+ def find_available_port
103
+ server = TCPServer.new('127.0.0.1', 0)
104
+ server.addr[1]
105
+ ensure
106
+ server.close if server
107
+ end
108
+
109
+ def run_proxy
110
+ return unless self.POST?
111
+ server = PostProxy.new self
112
+ @proxy = server
113
+
114
+ trap("INT") { server.stop }
115
+ pid = fork do
116
+ server.start
117
+ end
118
+ at_exit { server.stop; Process.waitpid pid }
119
+ end
53
120
  end
54
121
  end
55
122
  end
data/lib/heroku/kensa.rb CHANGED
@@ -2,9 +2,10 @@ require 'heroku/kensa/http'
2
2
  require 'heroku/kensa/manifest'
3
3
  require 'heroku/kensa/check'
4
4
  require 'heroku/kensa/sso'
5
+ require 'heroku/kensa/post_proxy'
5
6
 
6
7
  module Heroku
7
8
  module Kensa
8
- VERSION = "1.1.3"
9
+ VERSION = "1.1.4"
9
10
  end
10
- end
11
+ end
@@ -15,21 +15,21 @@ class DeprovisionCheckTest < Test::Unit::TestCase
15
15
 
16
16
  test "valid on 200" do
17
17
  assert_valid do |check|
18
- stub :delete, check, @responses
18
+ kensa_stub :delete, check, @responses
19
19
  end
20
20
  end
21
21
 
22
22
  test "status other than 200" do
23
23
  @responses[0] = [500, ""]
24
24
  assert_invalid do |check|
25
- stub :delete, check, @responses
25
+ kensa_stub :delete, check, @responses
26
26
  end
27
27
  end
28
28
 
29
29
  test "runs auth check" do
30
30
  @responses[1] = [200, ""]
31
31
  assert_invalid do |check|
32
- stub :delete, check, @responses
32
+ kensa_stub :delete, check, @responses
33
33
  end
34
34
  end
35
35
 
data/test/helper.rb CHANGED
@@ -1,16 +1,22 @@
1
1
  require 'heroku/kensa'
2
2
  require 'contest'
3
3
  require 'timecop'
4
+ require 'rr'
4
5
 
5
6
  class Test::Unit::TestCase
7
+ include RR::Adapters::TestUnit
6
8
 
9
+ # in your test, do
10
+ # @screen = STDOUTScreen.new
7
11
  def assert_valid(data=@data, &blk)
8
12
  check = create_check(data, &blk)
13
+ check.screen = @screen if @screen
9
14
  assert check.call
10
15
  end
11
16
 
12
17
  def assert_invalid(data=@data, &blk)
13
18
  check = create_check(data, &blk)
19
+ check.screen = @screen if @screen
14
20
  assert !check.call
15
21
  end
16
22
 
@@ -37,13 +43,12 @@ class Test::Unit::TestCase
37
43
  o
38
44
  end
39
45
 
40
- def stub(meth, o, returns)
46
+ def kensa_stub(meth, o, returns)
41
47
  o.instance_eval { @returns = Array(returns) }
42
48
  eval <<-EVAL
43
49
  def o.#{meth}(*args)
44
- @returns.shift || fail("Nothing else to return from stub'ed method")
50
+ @returns.shift or fail("Nothing else to return from stub'ed method")
45
51
  end
46
52
  EVAL
47
53
  end
48
-
49
54
  end
@@ -85,8 +85,7 @@ delete '/working/heroku/resources/:id' do
85
85
  "Ok"
86
86
  end
87
87
 
88
-
89
- get '/working/heroku/resources/:id' do
88
+ def sso
90
89
  unauthorized! unless params[:id] && params[:token]
91
90
  unauthorized! unless params[:timestamp].to_i > (Time.now-60*2).to_i
92
91
  unauthorized! unless params[:token] == make_token
@@ -94,21 +93,45 @@ get '/working/heroku/resources/:id' do
94
93
  login
95
94
  end
96
95
 
97
- get '/notoken/heroku/resources/:id' do
96
+ get '/working/heroku/resources/:id' do
97
+ sso
98
+ end
99
+
100
+ post '/working/heroku/resources/:id/sso' do
101
+ sso
102
+ end
103
+
104
+ def notoken
98
105
  unauthorized! unless params[:id] && params[:token]
99
106
  unauthorized! unless params[:timestamp].to_i > (Time.now-60*2).to_i
100
107
  response.set_cookie('heroku-nav-data', params['nav-data'])
101
108
  login
102
109
  end
103
110
 
104
- get '/notimestamp/heroku/resources/:id' do
111
+ get '/notoken/heroku/resources/:id' do
112
+ notoken
113
+ end
114
+
115
+ post '/notoken/heroku/resources/:id/sso' do
116
+ notoken
117
+ end
118
+
119
+ def notimestamp
105
120
  unauthorized! unless params[:id] && params[:token]
106
121
  unauthorized! unless params[:token] == make_token
107
122
  response.set_cookie('heroku-nav-data', params['nav-data'])
108
123
  login
109
124
  end
110
125
 
111
- get '/nolayout/heroku/resources/:id' do
126
+ get '/notimestamp/heroku/resources/:id' do
127
+ notimestamp
128
+ end
129
+
130
+ post '/notimestamp/heroku/resources/:id/sso' do
131
+ notimestamp
132
+ end
133
+
134
+ def nolayout
112
135
  unauthorized! unless params[:id] && params[:token]
113
136
  unauthorized! unless params[:timestamp].to_i > (Time.now-60*2).to_i
114
137
  unauthorized! unless params[:token] == make_token
@@ -116,14 +139,30 @@ get '/nolayout/heroku/resources/:id' do
116
139
  login(false)
117
140
  end
118
141
 
119
- get '/nocookie/heroku/resources/:id' do
142
+ get '/nolayout/heroku/resources/:id' do
143
+ nolayout
144
+ end
145
+
146
+ post '/nolayout/heroku/resources/:id/sso' do
147
+ nolayout
148
+ end
149
+
150
+ def nocookie
120
151
  unauthorized! unless params[:id] && params[:token]
121
152
  unauthorized! unless params[:timestamp].to_i > (Time.now-60*2).to_i
122
153
  unauthorized! unless params[:token] == make_token
123
154
  login
124
155
  end
125
156
 
126
- get '/badcookie/heroku/resources/:id' do
157
+ get '/nocookie/heroku/resources/:id' do
158
+ nocookie
159
+ end
160
+
161
+ post '/nocookie/heroku/resources/:id/sso' do
162
+ nocookie
163
+ end
164
+
165
+ def badcookie
127
166
  unauthorized! unless params[:id] && params[:token]
128
167
  unauthorized! unless params[:timestamp].to_i > (Time.now-60*2).to_i
129
168
  unauthorized! unless params[:token] == make_token
@@ -131,6 +170,27 @@ get '/badcookie/heroku/resources/:id' do
131
170
  login
132
171
  end
133
172
 
173
+ get '/badcookie/heroku/resources/:id' do
174
+ badcookie
175
+ end
176
+
177
+ post '/badcookie/heroku/resources/:id/sso' do
178
+ badcookie
179
+ end
180
+
181
+ def sso_user
182
+ head 404 unless params[:user] == 'username@example.com'
183
+ sso
184
+ end
185
+
186
+ get '/user/heroku/resources/:id' do
187
+ sso_user
188
+ end
189
+
190
+ post '/user/heroku/resources/:id/sso' do
191
+ sso_user
192
+ end
193
+
134
194
  get '/' do
135
195
  unauthorized! unless session[:logged_in]
136
196
  haml :index
@@ -144,4 +204,4 @@ __END__
144
204
  - if session[:heroku]
145
205
  #heroku-header
146
206
  %h1 Heroku
147
- %h1 Sample Addon
207
+ %h1 Sample Addon
@@ -10,40 +10,50 @@ class SsoCheckTest < Test::Unit::TestCase
10
10
 
11
11
  def check ; SsoCheck ; end
12
12
 
13
- test "working sso request" do
14
- @data['api']['test'] += "working"
15
- assert_valid
13
+ ['POST', 'GET'].each do |method|
14
+ context "via #{method}" do
15
+ setup { @data['api']['sso'] = method }
16
+
17
+ test "working sso request" do
18
+ @data['api']['test'] += "working"
19
+ assert_valid
20
+ end
21
+
22
+ test "rejects bad token" do
23
+ @data['api']['test'] += "notoken"
24
+ assert_invalid
25
+ end
26
+
27
+ test "rejects old timestamp" do
28
+ @data['api']['test'] += "notimestamp"
29
+ assert_invalid
30
+ end
31
+
32
+ test "reject omitted sso salt" do
33
+ @data['api'].delete 'sso_salt'
34
+ @data['api']['test'] += "working"
35
+ assert_invalid
36
+ end
37
+
38
+ test "reject missing heroku layout" do
39
+ @data['api']['test'] += "nolayout"
40
+ assert_invalid
41
+ end
42
+
43
+ test "reject missing cookie" do
44
+ @data['api']['test'] += "nocookie"
45
+ assert_invalid
46
+ end
47
+
48
+ test "reject invalid cookie value" do
49
+ @data['api']['test'] += "badcookie"
50
+ assert_invalid
51
+ end
52
+
53
+ test "sends user param" do
54
+ @data['api']['test'] += "user"
55
+ assert_valid
56
+ end
57
+ end
16
58
  end
17
-
18
- test "rejects bad token" do
19
- @data['api']['test'] += "notoken"
20
- assert_invalid
21
- end
22
-
23
- test "rejects old timestamp" do
24
- @data['api']['test'] += "notimestamp"
25
- assert_invalid
26
- end
27
-
28
- test "reject omitted sso salt" do
29
- @data['api'].delete 'sso_salt'
30
- @data['api']['test'] += "working"
31
- assert_invalid
32
- end
33
-
34
- test "reject missing heroku layout" do
35
- @data['api']['test'] += "nolayout"
36
- assert_invalid
37
- end
38
-
39
- test "reject missing cookie" do
40
- @data['api']['test'] += "nocookie"
41
- assert_invalid
42
- end
43
-
44
- test "reject invalid cookie value" do
45
- @data['api']['test'] += "badcookie"
46
- assert_invalid
47
- end
48
-
49
59
  end
data/test/sso_test.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'test/helper'
2
+ require 'cgi'
2
3
 
3
4
  class SsoTest < Test::Unit::TestCase
4
5
  include Heroku::Kensa
@@ -11,18 +12,87 @@ class SsoTest < Test::Unit::TestCase
11
12
 
12
13
  teardown { Timecop.return }
13
14
 
15
+ def builds_full_url(env)
16
+ url, query = @sso.full_url.split('?')
17
+ data = CGI.parse(query)
18
+
19
+
20
+ assert_equal "#{@data['api'][env]}heroku/resources/1", url
21
+ assert_equal 'b6010f6fbb850887a396c2bc0ab23974003008f6', data['token'].first
22
+ assert_equal '1262304000', data['timestamp'].first
23
+ assert_equal 'username@example.com', data['user'].first
24
+ end
25
+
14
26
  context 'sso' do
15
- setup { @sso = Sso.new @data }
27
+ setup do
28
+ Timecop.freeze Time.utc(2010, 1)
29
+ @sso = Sso.new @data
30
+ end
16
31
 
17
32
  test 'builds path' do
18
33
  assert_equal '/heroku/resources/1', @sso.path
19
34
  end
20
35
 
21
36
  test 'builds full url' do
22
- Timecop.freeze Time.utc(2010, 1)
23
- expected = 'http://localhost:4567/heroku/resources/1?token=b6010f6fbb850887a396c2bc0ab23974003008f6&timestamp=1262304000'
37
+ builds_full_url('test')
38
+ end
24
39
 
25
- assert @sso.full_url.include?(expected)
40
+ context 'with no "sso" field specified' do
41
+ test "defaults to GET" do
42
+ assert_equal @sso.full_url, @sso.sso_url
43
+ end
44
+ end
45
+
46
+ context 'when sso method is GET' do
47
+ setup do
48
+ @data['api']['sso'] = 'GET'
49
+ @sso = Sso.new(@data).start
50
+ end
51
+
52
+ test "#sso_url should be the #full_url" do
53
+ assert_equal @sso.full_url, @sso.sso_url
54
+ end
55
+
56
+ test "#message is Opening <full_url>" do
57
+ assert_equal "Opening #{@sso.full_url}", @sso.message
58
+ end
59
+ end
60
+
61
+ context 'when sso method is POST' do
62
+ setup do
63
+ Timecop.freeze Time.utc(2010, 1)
64
+ @data['api']['sso'] = 'post'
65
+ end
66
+
67
+ test "it starts the proxy server" do
68
+ @sso = Sso.new(@data).start
69
+ body = RestClient.get(@sso.sso_url)
70
+
71
+ assert body.include? @sso.path
72
+ assert body.include? 'b6010f6fbb850887a396c2bc0ab23974003008f6'
73
+ assert body.include? '1262304000'
74
+ assert body.include? @sso.url
75
+ assert body.include? @sso.sample_nav_data
76
+ end
77
+
78
+ context "with the proxy working" do
79
+ setup do
80
+ any_instance_of(Sso, :run_proxy => false)
81
+ @sso = Sso.new(@data).start
82
+ end
83
+
84
+ test "#sso_url should point to the proxy" do
85
+ assert_equal "http://localhost:#{@sso.proxy_port}/", @sso.sso_url
86
+ end
87
+
88
+ test "#post_url contains url and path" do
89
+ assert_equal "http://localhost:4567/heroku/resources/1/sso", @sso.post_url
90
+ end
91
+
92
+ test "#message is Posting <data> to <post_url> via proxy on port <proxy_port>" do
93
+ assert_equal "POSTing #{@sso.query_data} to http://localhost:4567/heroku/resources/1/sso via proxy on port #{@sso.proxy_port}", @sso.message
94
+ end
95
+ end
26
96
  end
27
97
  end
28
98
 
@@ -41,6 +111,7 @@ class SsoTest < Test::Unit::TestCase
41
111
 
42
112
  context 'sso in a specific environment' do
43
113
  setup do
114
+ Timecop.freeze Time.utc(2010, 1)
44
115
  env = 'production'
45
116
  @data[:env] = env
46
117
  @data['api'][env] = 'http://localhost:7654/'
@@ -49,10 +120,7 @@ class SsoTest < Test::Unit::TestCase
49
120
  end
50
121
 
51
122
  test 'builds full url' do
52
- Timecop.freeze Time.utc(2010, 1)
53
- expected = 'http://localhost:7654/heroku/resources/1?token=b6010f6fbb850887a396c2bc0ab23974003008f6&timestamp=1262304000'
54
-
55
- assert @sso.full_url.include?(expected)
123
+ builds_full_url('production')
56
124
  end
57
125
  end
58
126
  end
metadata CHANGED
@@ -5,18 +5,19 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 1
8
- - 3
9
- version: 1.1.3
8
+ - 4
9
+ version: 1.1.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - Blake Mizerany
13
13
  - Pedro Belo
14
14
  - Adam Wiggins
15
+ - Chris Continanza
15
16
  autorequire:
16
17
  bindir: bin
17
18
  cert_chain: []
18
19
 
19
- date: 2011-02-21 00:00:00 -08:00
20
+ date: 2011-08-22 00:00:00 -07:00
20
21
  default_executable: kensa
21
22
  dependencies:
22
23
  - !ruby/object:Gem::Dependency
@@ -71,17 +72,70 @@ dependencies:
71
72
  type: :development
72
73
  version_requirements: *id004
73
74
  - !ruby/object:Gem::Dependency
74
- name: rest-client
75
+ name: json
75
76
  prerelease: false
76
77
  requirement: &id005 !ruby/object:Gem::Requirement
77
78
  requirements:
78
79
  - - ">="
79
80
  - !ruby/object:Gem::Version
80
81
  segments:
81
- - 1
82
- - 4
83
82
  - 0
84
- version: 1.4.0
83
+ version: "0"
84
+ type: :development
85
+ version_requirements: *id005
86
+ - !ruby/object:Gem::Dependency
87
+ name: contest
88
+ prerelease: false
89
+ requirement: &id006 !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ segments:
94
+ - 0
95
+ version: "0"
96
+ type: :development
97
+ version_requirements: *id006
98
+ - !ruby/object:Gem::Dependency
99
+ name: haml
100
+ prerelease: false
101
+ requirement: &id007 !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ segments:
106
+ - 0
107
+ version: "0"
108
+ type: :development
109
+ version_requirements: *id007
110
+ - !ruby/object:Gem::Dependency
111
+ name: jeweler
112
+ prerelease: false
113
+ requirement: &id008 !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ segments:
118
+ - 0
119
+ version: "0"
120
+ type: :development
121
+ version_requirements: *id008
122
+ - !ruby/object:Gem::Dependency
123
+ name: rr
124
+ prerelease: false
125
+ requirement: &id009 !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ segments:
130
+ - 0
131
+ version: "0"
132
+ type: :development
133
+ version_requirements: *id009
134
+ - !ruby/object:Gem::Dependency
135
+ name: rest-client
136
+ prerelease: false
137
+ requirement: &id010 !ruby/object:Gem::Requirement
138
+ requirements:
85
139
  - - <
86
140
  - !ruby/object:Gem::Version
87
141
  segments:
@@ -89,12 +143,19 @@ dependencies:
89
143
  - 7
90
144
  - 0
91
145
  version: 1.7.0
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ segments:
149
+ - 1
150
+ - 4
151
+ - 0
152
+ version: 1.4.0
92
153
  type: :runtime
93
- version_requirements: *id005
154
+ version_requirements: *id010
94
155
  - !ruby/object:Gem::Dependency
95
156
  name: yajl-ruby
96
157
  prerelease: false
97
- requirement: &id006 !ruby/object:Gem::Requirement
158
+ requirement: &id011 !ruby/object:Gem::Requirement
98
159
  requirements:
99
160
  - - ~>
100
161
  - !ruby/object:Gem::Version
@@ -103,11 +164,11 @@ dependencies:
103
164
  - 6
104
165
  version: "0.6"
105
166
  type: :runtime
106
- version_requirements: *id006
167
+ version_requirements: *id011
107
168
  - !ruby/object:Gem::Dependency
108
169
  name: term-ansicolor
109
170
  prerelease: false
110
- requirement: &id007 !ruby/object:Gem::Requirement
171
+ requirement: &id012 !ruby/object:Gem::Requirement
111
172
  requirements:
112
173
  - - ~>
113
174
  - !ruby/object:Gem::Version
@@ -116,11 +177,11 @@ dependencies:
116
177
  - 0
117
178
  version: "1.0"
118
179
  type: :runtime
119
- version_requirements: *id007
180
+ version_requirements: *id012
120
181
  - !ruby/object:Gem::Dependency
121
182
  name: launchy
122
183
  prerelease: false
123
- requirement: &id008 !ruby/object:Gem::Requirement
184
+ requirement: &id013 !ruby/object:Gem::Requirement
124
185
  requirements:
125
186
  - - ">="
126
187
  - !ruby/object:Gem::Version
@@ -130,11 +191,11 @@ dependencies:
130
191
  - 2
131
192
  version: 0.3.2
132
193
  type: :runtime
133
- version_requirements: *id008
194
+ version_requirements: *id013
134
195
  - !ruby/object:Gem::Dependency
135
196
  name: mechanize
136
197
  prerelease: false
137
- requirement: &id009 !ruby/object:Gem::Requirement
198
+ requirement: &id014 !ruby/object:Gem::Requirement
138
199
  requirements:
139
200
  - - ~>
140
201
  - !ruby/object:Gem::Version
@@ -144,7 +205,7 @@ dependencies:
144
205
  - 0
145
206
  version: 1.0.0
146
207
  type: :runtime
147
- version_requirements: *id009
208
+ version_requirements: *id014
148
209
  description: Kensa is a command-line tool to help add-on providers integrating their services with Heroku. It manages manifest files, and provides a TDD-like approach for programmers to test and develop their APIs.
149
210
  email: pedro@heroku.com
150
211
  executables:
@@ -154,6 +215,8 @@ extensions: []
154
215
  extra_rdoc_files:
155
216
  - README.md
156
217
  files:
218
+ - Gemfile
219
+ - Gemfile.lock
157
220
  - README.md
158
221
  - Rakefile
159
222
  - bin/kensa
@@ -163,6 +226,7 @@ files:
163
226
  - lib/heroku/kensa/client.rb
164
227
  - lib/heroku/kensa/http.rb
165
228
  - lib/heroku/kensa/manifest.rb
229
+ - lib/heroku/kensa/post_proxy.rb
166
230
  - lib/heroku/kensa/sso.rb
167
231
  - set-env.sh
168
232
  - test/all_check_test.rb
@@ -207,16 +271,5 @@ rubygems_version: 1.3.6
207
271
  signing_key:
208
272
  specification_version: 3
209
273
  summary: Tool to help Heroku add-on providers integrating their services
210
- test_files:
211
- - test/all_check_test.rb
212
- - test/deprovision_check_test.rb
213
- - test/helper.rb
214
- - test/manifest_check_test.rb
215
- - test/manifest_test.rb
216
- - test/plan_change_check_test.rb
217
- - test/provision_check_test.rb
218
- - test/provision_response_check_test.rb
219
- - test/resources/runner.rb
220
- - test/resources/server.rb
221
- - test/sso_check_test.rb
222
- - test/sso_test.rb
274
+ test_files: []
275
+