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 +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
|