maitre_d 0.2.0 → 0.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 +7 -0
- data/.travis.yml +0 -3
- data/Gemfile +0 -4
- data/HISTORY +4 -0
- data/config/routes.rb +1 -0
- data/lib/maitre_d.rb +1 -0
- data/lib/maitre_d/broadstack.rb +40 -0
- data/lib/maitre_d/broadstack/api.rb +49 -0
- data/lib/maitre_d/broadstack/api_helpers.rb +44 -0
- data/maitre_d.gemspec +2 -1
- data/spec/api/broadstack/provisioning_spec.rb +94 -0
- data/spec/api/broadstack/single_sign_on_spec.rb +49 -0
- data/spec/internal/app/listeners/broadstack_listener.rb +30 -0
- data/spec/internal/config/initializers/broadstack.rb +6 -0
- data/spec/spec_helper.rb +3 -3
- metadata +32 -15
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
data/Gemfile
CHANGED
data/HISTORY
CHANGED
data/config/routes.rb
CHANGED
data/lib/maitre_d.rb
CHANGED
@@ -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.
|
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
|
data/spec/spec_helper.rb
CHANGED
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.
|
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:
|
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:
|
142
|
+
rubygems_version: 2.0.2
|
130
143
|
signing_key:
|
131
|
-
specification_version:
|
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
|