maitre_d 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1e79119958343605dabd87304c21e2e9c770711b
4
+ data.tar.gz: 4ed73d17abf94091dfb18e566984637699e8569a
5
+ SHA512:
6
+ metadata.gz: 36feafdb16cd476413a95b34da6dfc675c43fa47772b04d6ec34117aeb71c42646556700920582689dda9fa845667451c93f8812408d340e14cd76eb5fe6cb3a
7
+ data.tar.gz: aa9b728329779092e8f1482e50db5dbfe45751cce6957135ec35f8d7f959b162cd55fbcd0e093db3534b7bf82249becbccdc3604981f217dc780b61b5d7c10bd
data/.travis.yml CHANGED
@@ -1,7 +1,4 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.8.7
4
- - 1.9.2
5
3
  - 1.9.3
6
- - ree
7
4
  script: bundle exec rspec spec
data/Gemfile CHANGED
@@ -1,9 +1,5 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gem 'combustion',
4
- :git => 'git://github.com/pat/combustion',
5
- :ref => 'd7a6836269a8fb528bc3721e9b8c06b5a62ef3cc'
6
-
7
3
  gemspec
8
4
 
9
5
  # Until a new Grape release is out:
data/HISTORY CHANGED
@@ -1,3 +1,7 @@
1
+ 0.3.0 - July 27th 2013
2
+ * No longer supporting 1.8.7/ree/1.9.2. Use 1.9.3 or 2.0.0.
3
+ * Broadstack support.
4
+
1
5
  0.2.0 - December 12th 2012
2
6
  * Support region parameter from Heroku.
3
7
  * Adding tentative CloudControl support.
data/config/routes.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  Rails.application.routes.draw do
2
+ mount MaitreD::Broadstack::API => '/broadstack'
2
3
  mount MaitreD::Heroku::API => '/heroku'
3
4
  mount MaitreD::CloudControl::API => '/cloudcontrol'
4
5
  mount MaitreD::Opperator::API => '/opperator'
data/lib/maitre_d.rb CHANGED
@@ -3,6 +3,7 @@ require 'grape'
3
3
  module MaitreD
4
4
  end
5
5
 
6
+ require 'maitre_d/broadstack'
6
7
  require 'maitre_d/heroku'
7
8
  require 'maitre_d/cloud_control'
8
9
  require 'maitre_d/opperator'
@@ -0,0 +1,40 @@
1
+ module MaitreD::Broadstack
2
+ def self.configure
3
+ yield self
4
+ end
5
+
6
+ def self.listener
7
+ @listener
8
+ end
9
+
10
+ def self.listener=(listener)
11
+ @listener = listener
12
+ end
13
+
14
+ def self.id
15
+ @id
16
+ end
17
+
18
+ def self.id=(id)
19
+ @id = id
20
+ end
21
+
22
+ def self.password
23
+ @password
24
+ end
25
+
26
+ def self.password=(password)
27
+ @password = password
28
+ end
29
+
30
+ def self.sso_salt
31
+ @sso_salt
32
+ end
33
+
34
+ def self.sso_salt=(salt)
35
+ @sso_salt = salt
36
+ end
37
+ end
38
+
39
+ require 'maitre_d/broadstack/api_helpers'
40
+ require 'maitre_d/broadstack/api'
@@ -0,0 +1,49 @@
1
+ class MaitreD::Broadstack::API < Grape::API
2
+ helpers MaitreD::Broadstack::APIHelpers
3
+
4
+ resources :sso do
5
+ post do
6
+ error!('403 Forbidden', 403) unless valid_token? && valid_timestamp?
7
+
8
+ hash = listener.single_sign_on(params[:id])
9
+
10
+ hash[:session] ||= {}
11
+ hash[:session].each { |key, value| session[key] = value }
12
+
13
+ if env['action_dispatch.cookies']
14
+ env['action_dispatch.cookies']['heroku-nav-data'] = params['nav-data']
15
+ else
16
+ Rack::Utils.set_cookie_header! header, 'heroku-nav-data',
17
+ :value => params['nav-data']
18
+ end
19
+
20
+ status 302
21
+ header 'Location', hash[:uri]
22
+ end
23
+ end
24
+
25
+ resources :resources do
26
+ post do
27
+ authenticate!
28
+
29
+ listener.provision(
30
+ provider_id, params[:plan], params[:region],
31
+ params[:callback_url], params[:logplex_token], params[:options]
32
+ )
33
+ end
34
+
35
+ put ':id' do
36
+ authenticate!
37
+
38
+ listener.plan_change(
39
+ params[:id], provider_id, params[:plan]
40
+ )
41
+ end
42
+
43
+ delete ':id' do
44
+ authenticate!
45
+
46
+ listener.deprovision params[:id]
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,44 @@
1
+ module MaitreD::Broadstack::APIHelpers
2
+ def authenticate!
3
+ error!('401 Unauthorized', 401) unless valid_authorization?
4
+ end
5
+
6
+ def listener
7
+ MaitreD::Broadstack.listener.new
8
+ end
9
+
10
+ def provider_id
11
+ params[:broadstack_id]
12
+ end
13
+
14
+ def session
15
+ env['rack.session']
16
+ end
17
+
18
+ def valid_timestamp?
19
+ params[:timestamp].to_i >= (Time.now - 5*60).to_i
20
+ end
21
+
22
+ def valid_token?
23
+ expected_token == params[:token]
24
+ end
25
+
26
+ private
27
+
28
+ def expected_token
29
+ @expected_token ||= Digest::SHA1.hexdigest(
30
+ "#{params[:id]}:#{MaitreD::Broadstack.sso_salt}:#{params[:timestamp]}"
31
+ ).to_s
32
+ end
33
+
34
+ def valid_authorization?
35
+ valid_authorization.strip == env['HTTP_AUTHORIZATION'].strip
36
+ end
37
+
38
+ def valid_authorization
39
+ encoded_authorization = Base64.encode64(
40
+ "#{MaitreD::Broadstack.id}:#{MaitreD::Broadstack.password}"
41
+ )
42
+ "Basic #{encoded_authorization}"
43
+ end
44
+ end
data/maitre_d.gemspec CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path('../lib', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'maitre_d'
6
- s.version = '0.2.0'
6
+ s.version = '0.3.0'
7
7
  s.authors = ['Pat Allan']
8
8
  s.email = ['pat@freelancing-gods.com']
9
9
  s.homepage = 'http://github.com/flying-sphinx/maitre_d'
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = ['lib']
19
19
 
20
+ s.add_development_dependency 'combustion', '0.5.1'
20
21
  s.add_development_dependency 'kensa', '1.3.0'
21
22
  s.add_development_dependency 'rails', '3.1.3'
22
23
  s.add_development_dependency 'rspec-rails', '2.7.0'
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Broadstack Provisioning API' do
4
+ let(:authorisation) { "Basic #{Base64.encode64('foo:bar')}" }
5
+ let(:json_response) { JSON.parse response.body }
6
+
7
+ describe 'Provisioning' do
8
+ let(:params) {
9
+ {
10
+ :plan => 'basic',
11
+ :callback_url => 'https://domain/vendor/apps/app123%40broadstack.com',
12
+ :broadstack_id => 'app123@broadstack.com'
13
+ }
14
+ }
15
+
16
+ it "returns a 401 if the HTTP authorisation does not match" do
17
+ post '/broadstack/resources', params,
18
+ {'HTTP_AUTHORIZATION' => 'Basic foobarbaz'}
19
+
20
+ response.status.should == 401
21
+ end
22
+
23
+ it "returns the resource id" do
24
+ post '/broadstack/resources', params, {'HTTP_AUTHORIZATION' => authorisation}
25
+
26
+ json_response['id'].should == '123'
27
+ end
28
+
29
+ it "returns the resource configuration" do
30
+ post '/broadstack/resources', params, {'HTTP_AUTHORIZATION' => authorisation}
31
+
32
+ json_response['config'].should == {'FOO_PROVISIONED' => "true"}
33
+ end
34
+
35
+ it "returns a custom message" do
36
+ post '/broadstack/resources', params, {'HTTP_AUTHORIZATION' => authorisation}
37
+
38
+ json_response['message'].should == 'Add-on provisioned!'
39
+ end
40
+
41
+ it "returns the region if it exists" do
42
+ post '/broadstack/resources', params.merge(:region => 'us-west'),
43
+ {'HTTP_AUTHORIZATION' => authorisation}
44
+
45
+ json_response['region'].should == 'us-west'
46
+ end
47
+ end
48
+
49
+ describe 'Changing Plans' do
50
+ let(:params) {
51
+ {:broadstack_id => 'app123@broadstack.com', :plan => 'premium'}
52
+ }
53
+
54
+ it "returns a 401 if the HTTP authorisation does not match" do
55
+ put '/broadstack/resources/7', params,
56
+ {'HTTP_AUTHORIZATION' => 'Basic foobarbaz'}
57
+
58
+ response.status.should == 401
59
+ end
60
+
61
+ it "returns the new resource configuration" do
62
+ put '/broadstack/resources/7', params, {'HTTP_AUTHORIZATION' => authorisation}
63
+
64
+ json_response['config'].should == {'FOO_PROVISIONED' => "false"}
65
+ end
66
+
67
+ it "returns a custom message" do
68
+ put '/broadstack/resources/7', params, {'HTTP_AUTHORIZATION' => authorisation}
69
+
70
+ json_response['message'].should == 'Add-on upgraded or downgraded.'
71
+ end
72
+ end
73
+
74
+ describe 'Deprovisioning' do
75
+ it "returns a 401 if the HTTP authorisation does not match" do
76
+ delete '/broadstack/resources/28', {},
77
+ {'HTTP_AUTHORIZATION' => 'Basic foobarbaz'}
78
+
79
+ response.status.should == 401
80
+ end
81
+
82
+ it "returns with a status of 200" do
83
+ delete '/broadstack/resources/28', {}, {'HTTP_AUTHORIZATION' => authorisation}
84
+
85
+ response.status.should == 200
86
+ end
87
+
88
+ it "returns a custom message" do
89
+ delete '/broadstack/resources/28', {}, {'HTTP_AUTHORIZATION' => authorisation}
90
+
91
+ json_response['message'].should == 'Add-on removed.'
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Broadstack SSO API' do
4
+ let(:timestamp) { Time.now.to_i }
5
+ let(:nav_data) { 'heroku-nav-data-goes-here' }
6
+ let(:token) {
7
+ pre_token = "789:sea salt:#{timestamp.to_s}"
8
+ Digest::SHA1.hexdigest(pre_token).to_s
9
+ }
10
+
11
+ it "renders a 403 if the token is incorrect" do
12
+ post '/broadstack/sso', :token => 'foo', :id => '789',
13
+ :timestamp => timestamp, 'nav-data' => nav_data
14
+
15
+ response.status.should == 403
16
+ end
17
+
18
+ it "renders a 403 if the timestamp is older than 5 minutes" do
19
+ timestamp = 5.minutes.ago.to_i - 1
20
+ pre_token = "789:sea salt:#{timestamp.to_s}"
21
+ token = Digest::SHA1.hexdigest(pre_token).to_s
22
+
23
+ post '/broadstack/sso', :token => token, :id => '789',
24
+ :timestamp => timestamp, 'nav-data' => nav_data
25
+
26
+ response.status.should == 403
27
+ end
28
+
29
+ it "sets the heroku nav data cookie" do
30
+ post '/broadstack/sso', :token => token, :id => '789',
31
+ :timestamp => timestamp, 'nav-data' => nav_data
32
+
33
+ cookies['heroku-nav-data'].should == nav_data
34
+ end
35
+
36
+ it "redirects to the appropriate URL" do
37
+ post '/broadstack/sso', :token => token, :id => '789',
38
+ :timestamp => timestamp, 'nav-data' => nav_data
39
+
40
+ response.should redirect_to('/my/dashboard')
41
+ end
42
+
43
+ it "should set the provided session variables" do
44
+ post '/broadstack/sso', :token => token, :id => '789',
45
+ :timestamp => timestamp, 'nav-data' => nav_data
46
+
47
+ session[:app_id].should == '789'
48
+ end
49
+ end
@@ -0,0 +1,30 @@
1
+ class BroadstackListener
2
+ def provision(heroku_id, plan, region, callback_url, logplex_token, options)
3
+ {
4
+ :id => '123',
5
+ :config => {'FOO_PROVISIONED' => 'true'},
6
+ :message => 'Add-on provisioned!',
7
+ :region => region
8
+ }
9
+ end
10
+
11
+ def plan_change(resource_id, heroku_id, plan)
12
+ {
13
+ :config => {'FOO_PROVISIONED' => 'false'},
14
+ :message => 'Add-on upgraded or downgraded.'
15
+ }
16
+ end
17
+
18
+ def deprovision(resource_id)
19
+ {
20
+ :message => 'Add-on removed.'
21
+ }
22
+ end
23
+
24
+ def single_sign_on(resource_id)
25
+ {
26
+ :uri => '/my/dashboard',
27
+ :session => {:app_id => resource_id}
28
+ }
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ MaitreD::Broadstack.configure do |config|
2
+ config.id = 'foo'
3
+ config.password = 'bar'
4
+ config.sso_salt = 'sea salt'
5
+ config.listener = BroadstackListener
6
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,7 @@
1
- require 'rubygems'
2
- require 'bundler'
1
+ require 'bundler/setup'
3
2
 
4
- Bundler.require :default, :development
3
+ require 'combustion'
4
+ require 'maitre_d'
5
5
 
6
6
  Combustion.initialize! :action_controller
7
7
 
metadata CHANGED
@@ -1,20 +1,32 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: maitre_d
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
5
- prerelease:
4
+ version: 0.3.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Pat Allan
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-12-12 00:00:00.000000000 Z
11
+ date: 2013-07-27 00:00:00.000000000 Z
13
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: combustion
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.1
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.1
14
27
  - !ruby/object:Gem::Dependency
15
28
  name: kensa
16
29
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
30
  requirements:
19
31
  - - '='
20
32
  - !ruby/object:Gem::Version
@@ -22,7 +34,6 @@ dependencies:
22
34
  type: :development
23
35
  prerelease: false
24
36
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
37
  requirements:
27
38
  - - '='
28
39
  - !ruby/object:Gem::Version
@@ -30,7 +41,6 @@ dependencies:
30
41
  - !ruby/object:Gem::Dependency
31
42
  name: rails
32
43
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
44
  requirements:
35
45
  - - '='
36
46
  - !ruby/object:Gem::Version
@@ -38,7 +48,6 @@ dependencies:
38
48
  type: :development
39
49
  prerelease: false
40
50
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
51
  requirements:
43
52
  - - '='
44
53
  - !ruby/object:Gem::Version
@@ -46,7 +55,6 @@ dependencies:
46
55
  - !ruby/object:Gem::Dependency
47
56
  name: rspec-rails
48
57
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
58
  requirements:
51
59
  - - '='
52
60
  - !ruby/object:Gem::Version
@@ -54,7 +62,6 @@ dependencies:
54
62
  type: :development
55
63
  prerelease: false
56
64
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
65
  requirements:
59
66
  - - '='
60
67
  - !ruby/object:Gem::Version
@@ -78,6 +85,9 @@ files:
78
85
  - config.ru
79
86
  - config/routes.rb
80
87
  - lib/maitre_d.rb
88
+ - lib/maitre_d/broadstack.rb
89
+ - lib/maitre_d/broadstack/api.rb
90
+ - lib/maitre_d/broadstack/api_helpers.rb
81
91
  - lib/maitre_d/cloud_control.rb
82
92
  - lib/maitre_d/cloud_control/api.rb
83
93
  - lib/maitre_d/cloud_control/api_helpers.rb
@@ -91,14 +101,18 @@ files:
91
101
  - lib/maitre_d/opperator/api_helpers.rb
92
102
  - lib/maitre_d/opperator/listener.rb
93
103
  - maitre_d.gemspec
104
+ - spec/api/broadstack/provisioning_spec.rb
105
+ - spec/api/broadstack/single_sign_on_spec.rb
94
106
  - spec/api/cloud_control/provisioning_spec.rb
95
107
  - spec/api/cloud_control/single_sign_on_spec.rb
96
108
  - spec/api/heroku/provisioning_spec.rb
97
109
  - spec/api/heroku/single_sign_on_spec.rb
98
110
  - spec/api/opperator/provisioning_spec.rb
111
+ - spec/internal/app/listeners/broadstack_listener.rb
99
112
  - spec/internal/app/listeners/cloud_control_listener.rb
100
113
  - spec/internal/app/listeners/heroku_listener.rb
101
114
  - spec/internal/app/listeners/opperator_listener.rb
115
+ - spec/internal/config/initializers/broadstack.rb
102
116
  - spec/internal/config/initializers/cloud_control.rb
103
117
  - spec/internal/config/initializers/heroku.rb
104
118
  - spec/internal/config/initializers/opperator.rb
@@ -108,37 +122,40 @@ files:
108
122
  - spec/spec_helper.rb
109
123
  homepage: http://github.com/flying-sphinx/maitre_d
110
124
  licenses: []
125
+ metadata: {}
111
126
  post_install_message:
112
127
  rdoc_options: []
113
128
  require_paths:
114
129
  - lib
115
130
  required_ruby_version: !ruby/object:Gem::Requirement
116
- none: false
117
131
  requirements:
118
- - - ! '>='
132
+ - - '>='
119
133
  - !ruby/object:Gem::Version
120
134
  version: '0'
121
135
  required_rubygems_version: !ruby/object:Gem::Requirement
122
- none: false
123
136
  requirements:
124
- - - ! '>='
137
+ - - '>='
125
138
  - !ruby/object:Gem::Version
126
139
  version: '0'
127
140
  requirements: []
128
141
  rubyforge_project: maitre_d
129
- rubygems_version: 1.8.23
142
+ rubygems_version: 2.0.2
130
143
  signing_key:
131
- specification_version: 3
144
+ specification_version: 4
132
145
  summary: Rack API and Rails Engine for Heroku and Opperator add-ons
133
146
  test_files:
147
+ - spec/api/broadstack/provisioning_spec.rb
148
+ - spec/api/broadstack/single_sign_on_spec.rb
134
149
  - spec/api/cloud_control/provisioning_spec.rb
135
150
  - spec/api/cloud_control/single_sign_on_spec.rb
136
151
  - spec/api/heroku/provisioning_spec.rb
137
152
  - spec/api/heroku/single_sign_on_spec.rb
138
153
  - spec/api/opperator/provisioning_spec.rb
154
+ - spec/internal/app/listeners/broadstack_listener.rb
139
155
  - spec/internal/app/listeners/cloud_control_listener.rb
140
156
  - spec/internal/app/listeners/heroku_listener.rb
141
157
  - spec/internal/app/listeners/opperator_listener.rb
158
+ - spec/internal/config/initializers/broadstack.rb
142
159
  - spec/internal/config/initializers/cloud_control.rb
143
160
  - spec/internal/config/initializers/heroku.rb
144
161
  - spec/internal/config/initializers/opperator.rb