maestrano-rails 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -12,7 +12,10 @@ Maestrano Cloud Integration is currently in closed beta. Want to know more? Send
12
12
  * [User Model](#user-model)
13
13
  * [Group Model](#group-model)
14
14
  * [Controller Setup](#controller-setup)
15
- 3. [API](https://github.com/maestrano/maestrano-ruby#api)
15
+ 3. [Account Webhooks](#account-webhooks)
16
+ * [Groups Controller](#groups-controller-service-cancellation)
17
+ * [Group Users Controller](#group-users-controller-business-member-removal)
18
+ 4. [API](https://github.com/maestrano/maestrano-ruby#api)
16
19
  * [Bill](https://github.com/maestrano/maestrano-ruby#bill)
17
20
  * [Recurring Bill](https://github.com/maestrano/maestrano-ruby#recurring-bill)
18
21
 
@@ -46,7 +49,8 @@ After you install Maestrano and add it to your Gemfile, you need to run the gene
46
49
  rails generate maestrano:install
47
50
  ```
48
51
 
49
- The generator will install an initializer which describes ALL Maestrano's configuration options. You will need to take a look at it as this is where you set your API key.
52
+ The generator will install an initializer which describes ALL Maestrano's configuration options. You will need to take a look at it as this is where you set your API key. This configuration will also be used to automatically generate a '/maestrano/metadata' endpoint in your application that Maestrano will fetch automatically at regular intervals (or by hitting 'refresh metadata' in your cloud partner dashboard on maestrano.com).
53
+
50
54
  The generator also generates a SamlController for single sign-on that you will need to customize (see below) as well as the required routes.
51
55
 
52
56
  When you are done, you can start maestrano-izing your user and group model using the generators.
@@ -167,6 +171,89 @@ class Maestrano::Auth::SamlController < Maestrano::Rails::SamlBaseController
167
171
  end
168
172
  ```
169
173
 
174
+ ## Account Webhooks
175
+ Single sign on has been setup into your app and Maestrano users are now able to use your service. Great! Wait what happens when a business (group) decides to stop using your service? Also what happens when a user gets removed from a business? Well the controllers generated under RAILS_ROOT/app/controllers/maestrano/account/ are typically for Maestrano to be able to notify you of such events.
176
+
177
+ ### Groups Controller (service cancellation)
178
+ Sad as it is a business might decide to stop using your service at some point. On Maestrano billing entities are represented by groups (used for collaboration & billing). So when a business decides to stop using your service we will issue a DELETE request to the webhook.account.groups_path endpoint (typically /maestrano/account/groups/:id).
179
+
180
+ Maestrano only uses this controller for service cancellation so there is no need to implement any other type of action - ie: GET, PUT/PATCH or POST. The use of other http verbs might come in the future to improve the communication between Maestrano and your service but as of now it is not required.
181
+
182
+ Below is an example of what your groups destroy action might look like:
183
+ ```ruby
184
+ class Maestrano::Account::GroupsController < Maestrano::Rails::WebHookController
185
+
186
+ # DELETE /maestrano/account/groups/cld-1
187
+ # Delete an entire group
188
+ def destroy
189
+ group_uid = params[:id]
190
+
191
+ # Perform deletion steps here
192
+ # --
193
+ # If you need to perform a final checkout
194
+ # then you can call Maestrano::Account::Bill.create({.. final checkout details ..})
195
+ # --
196
+ # If Maestrano.param('sso.creation_mode') is set to virtual
197
+ # then you might want to delete/cancel/block all users under
198
+ # that group
199
+ # --
200
+ # E.g:
201
+ organization = Organization.find_by_provider_and_uid('maestrano',group_uid)
202
+
203
+ amount_cents = organization.calculate_total_due_remaining
204
+ Maestrano::Account::Bill.create({
205
+ group_id: group_uid,
206
+ price_cents: amount_cents,
207
+ description: "Final Payout"
208
+ })
209
+
210
+ if Maestrano.param('sso.creation_mode') == 'virtual'
211
+ organization.members.where(provider:'maestrano').each do |user|
212
+ user.destroy
213
+ end
214
+
215
+ organization.destroy
216
+ render json: {success: true}, status: :success
217
+ end
218
+ end
219
+ ```
220
+
221
+ ### Group Users Controller (business member removal)
222
+ A business might decide at some point to revoke access to your services for one of its member. In such case we will issue a DELETE request to the webhook.account.group_users_path endpoint (typically /maestrano/account/groups/:group_id/users/:id).
223
+
224
+ Maestrano only uses this controller for user membership cancellation so there is no need to implement any other type of action - ie: GET, PUT/PATCH or POST. The use of other http verbs might come in the future to improve the communication between Maestrano and your service but as of now it is not required.
225
+
226
+
227
+ Below is an example of what your group users destroy action might look like:
228
+ ```ruby
229
+ class Maestrano::Account::GroupUsersController < Maestrano::Rails::WebHookController
230
+
231
+ # DELETE /maestrano/account/groups/cld-1/users/usr-1
232
+ # Remove a user from a group
233
+ def destroy
234
+ # Set the right uid based on Maestrano.param('sso.creation_mode')
235
+ user_uid = Maestrano.mask_user(params[:id],params[:group_id])
236
+ group_uid = params[:group_id]
237
+
238
+ # Perform association deletion steps here
239
+ # --
240
+ # If Maestrano.param('sso.creation_mode') is set to virtual
241
+ # then you might want to just delete/cancel/block the user
242
+ #
243
+ # E.g
244
+ user = User.find_by_provider_and_uid('maestrano',user_uid)
245
+ organization = Organization.find_by_provider_and_uid('maestrano',group_uid)
246
+
247
+ if Maestrano.param('sso.creation_mode') == 'virtual'
248
+ user.destroy
249
+ else
250
+ organization.remove_user(user)
251
+ user.block_access! if user.reload.organizations.empty?
252
+ end
253
+ end
254
+ end
255
+ ```
256
+
170
257
  ## API
171
258
  The maestrano-rails gem also provides bindings to its REST API allowing you to access, create, update or delete various entities under your account (e.g: billing).
172
259
 
@@ -0,0 +1,8 @@
1
+ class Maestrano::Rails::MetadataController < Maestrano::Rails::WebHookController
2
+
3
+ # GET /maestrano/metadata
4
+ # Return the Maestrano configuration for this application
5
+ def index
6
+ render json: Maestrano.to_metadata
7
+ end
8
+ end
@@ -12,12 +12,12 @@ module Maestrano
12
12
  template "saml_controller.rb", "app/controllers/maestrano/auth/saml_controller.rb"
13
13
  end
14
14
 
15
- def copy_account_hook_groups_controller
16
- template "groups_controller.rb", "app/controllers/maestrano/account_hook/groups_controller.rb"
15
+ def copy_account_groups_controller
16
+ template "groups_controller.rb", "app/controllers/maestrano/account/groups_controller.rb"
17
17
  end
18
18
 
19
- def copy_account_hook_group_users_controller
20
- template "group_users_controller.rb", "app/controllers/maestrano/account_hook/group_users_controller.rb"
19
+ def copy_account_group_users_controller
20
+ template "group_users_controller.rb", "app/controllers/maestrano/account/group_users_controller.rb"
21
21
  end
22
22
 
23
23
  def add_maestrano_routes
@@ -1,22 +1,22 @@
1
- class Maestrano::AccountHook::GroupUsersController < Maestrano::Rails::WebHookController
1
+ class Maestrano::Account::GroupUsersController < Maestrano::Rails::WebHookController
2
2
 
3
3
  # DELETE /maestrano/account/groups/cld-1/users/usr-1
4
4
  # Remove a user from a group
5
5
  def destroy
6
- # Set the right uid based on Maestrano.param('user_creation_mode')
6
+ # Set the right uid based on Maestrano.param('sso.creation_mode')
7
7
  user_uid = Maestrano.mask_user(params[:id],params[:group_id])
8
8
  group_uid = params[:group_id]
9
9
 
10
10
  # Perform association deletion steps here
11
11
  # --
12
- # If Maestrano.param('user_creation_mode') is set to virtual
12
+ # If Maestrano.param('sso.creation_mode') is set to virtual
13
13
  # then you might want to just delete/cancel/block the user
14
14
  #
15
15
  # E.g
16
16
  # user = User.find_by_provider_and_uid('maestrano',user_uid)
17
17
  # organization = Organization.find_by_provider_and_uid('maestrano',group_uid)
18
18
  #
19
- # if Maestrano.param('user_creation_mode') == 'virtual'
19
+ # if Maestrano.param('sso.creation_mode') == 'virtual'
20
20
  # user.destroy
21
21
  # else
22
22
  # organization.remove_user(user)
@@ -1,4 +1,4 @@
1
- class Maestrano::AccountHook::GroupsController < Maestrano::Rails::WebHookController
1
+ class Maestrano::Account::GroupsController < Maestrano::Rails::WebHookController
2
2
 
3
3
  # DELETE /maestrano/account/groups/cld-1
4
4
  # Delete an entire group
@@ -10,7 +10,7 @@ class Maestrano::AccountHook::GroupsController < Maestrano::Rails::WebHookContro
10
10
  # If you need to perform a final checkout
11
11
  # then you can call Maestrano::Account::Bill.create({.. final checkout details ..})
12
12
  # --
13
- # If Maestrano.param('user_creation_mode') is set to virtual
13
+ # If Maestrano.param('sso.creation_mode') is set to virtual
14
14
  # then you might want to delete/cancel/block all users under
15
15
  # that group
16
16
  # --
@@ -24,7 +24,7 @@ class Maestrano::AccountHook::GroupsController < Maestrano::Rails::WebHookContro
24
24
  # description: "Final Payout"
25
25
  # })
26
26
  #
27
- # if Maestrano.param('user_creation_mode') == 'virtual'
27
+ # if Maestrano.param('sso.creation_mode') == 'virtual'
28
28
  # organization.members.where(provider:'maestrano').each do |user|
29
29
  # user.destroy
30
30
  # end
@@ -1,5 +1,3 @@
1
- # Use this block to configure the behaviour of Maestrano
2
- # in your app
3
1
  Maestrano.configure do |config|
4
2
 
5
3
  # ==> Environment configuration
@@ -9,25 +7,38 @@ Maestrano.configure do |config|
9
7
  # If set to 'test' then requests will be made to api-sandbox.maestrano.io
10
8
  # The api-sandbox allows you to easily test integration scenarios.
11
9
  # More details on http://api-sandbox.maestrano.io
12
- config.environment = Rails.env.production? ? 'production' : 'test'
10
+ #
11
+ config.environment = 'test' # or 'production'
12
+
13
+ # ==> Application host
14
+ # This is your application host (e.g: my-app.com) which is ultimately
15
+ # used to redirect users to the right SAML url during SSO handshake.
16
+ #
17
+ config.app.host = (config.environment == 'production' ? 'https://my-app.com' : 'http://localhost:3000')
13
18
 
14
19
  # ==> App ID & API key
15
20
  # Your application App ID and API key which you can retrieve on http://maestrano.com
16
21
  # via your cloud partner dashboard.
17
- # For testing you can retrieve/generate an api_key from the API Sandbox directly
22
+ # For testing you can retrieve/generate an api.id and api.key from the API Sandbox directly
18
23
  # on http://api-sandbox.maestrano.io
19
- config.app_id = Rails.env.production? ? 'prod_app_id' : 'sandbox_app_id'
20
- config.api_key = Rails.env.production? ? 'prod_api_key' : 'sandbox_api_key'
24
+ #
25
+ config.api.id = (config.environment == 'production' ? 'prod_app_id' : 'sandbox_app_id')
26
+ config.api.key = (config.environment == 'production' ? 'prod_api_key' : 'sandbox_api_key')
21
27
 
22
28
  # ==> Single Sign-On activation
23
29
  # Enable/Disable single sign-on. When troubleshooting authentication issues
24
30
  # you might want to disable SSO temporarily
25
- config.sso_enabled = true
31
+ #
32
+ # config.sso.enabled = true
26
33
 
27
- # ==> Application host
28
- # This is your application host (e.g: mysuperapp.com) which is ultimately
29
- # used to redirect users to the right SAML url during SSO handshake.
30
- config.app_host = Rails.env.production? ? 'https://my-production-app.com' : 'http://localhost:3000'
34
+ # ==> Single Sign-On Identity Manager
35
+ # By default we consider that the domain managing user identification
36
+ # is the same as your application host (see above config.app.host parameter)
37
+ # If you have a dedicated domain managing user identification and therefore
38
+ # responsible for the single sign-on handshake (e.g: https://idp.my-app.com)
39
+ # then you can specify it below
40
+ #
41
+ # config.sso.idm = (config.environment == 'production' ? 'https://idp.my-app.com' : 'http://localhost:3000')
31
42
 
32
43
  # ==> SSO Initialization endpoint
33
44
  # This is your application path to the SAML endpoint that allows users to
@@ -36,19 +47,23 @@ Maestrano.configure do |config|
36
47
  # to Maestrano. Maestrano will then authenticate and authorize the user. Upon
37
48
  # authorization the user gets redirected to your application consumer endpoint
38
49
  # (see below) for initial setup and/or login.
50
+ #
39
51
  # The controller for this path is automatically
40
52
  # generated when you run 'rake maestrano:install' and is available at
41
53
  # <rails_root>/app/controllers/maestrano/auth/saml.rb
42
- config.sso_app_init_path = '/maestrano/auth/saml/init'
54
+ #
55
+ # config.sso.init_path = '/maestrano/auth/saml/init'
43
56
 
44
57
  # ==> SSO Consumer endpoint
45
58
  # This is your application path to the SAML endpoint that allows users to
46
59
  # finalize SSO authentication. During the 'consume' action your application
47
60
  # sets users (and associated group) up and/or log them in.
61
+ #
48
62
  # The controller for this path is automatically
49
63
  # generated when you run 'rake maestrano:install' and is available at
50
64
  # <rails_root>/app/controllers/maestrano/auth/saml.rb
51
- config.sso_app_consume_path = '/maestrano/auth/saml/consume'
65
+ #
66
+ # config.sso.consume_path = '/maestrano/auth/saml/consume'
52
67
 
53
68
  # ==> SSO User creation mode
54
69
  # !IMPORTANT
@@ -68,18 +83,36 @@ Maestrano.configure do |config|
68
83
  #
69
84
  # == mode: 'real'
70
85
  # In an ideal world a user should be able to belong to several groups in your application.
71
- # In this case you would set the 'user_creation_mode' to 'real' which means that the uid
86
+ # In this case you would set the 'sso.creation_mode' to 'real' which means that the uid
72
87
  # and email we pass to you are the actual user email and maestrano universal id.
73
88
  #
74
89
  # == mode: 'virtual'
75
- # Now let's say that due to technical constraint your application cannot authorize a user
90
+ # Now let's say that due to technical constraints your application cannot authorize a user
76
91
  # to belong to several groups. Well next time John logs in via a different group there will
77
92
  # be a problem: the user already exists (based on uid or email) and cannot be assigned
78
- # to a second group. To fix this you can set the 'user_creation_mode' to 'virtual'. In this
93
+ # to a second group. To fix this you can set the 'sso.creation_mode' to 'virtual'. In this
79
94
  # mode users get assigned a truly unique uid and email across groups. So next time John logs
80
95
  # in a whole new user account can be created for him without any validation problem. In this
81
96
  # mode the email we assign to him looks like "usr-sdf54.cld-45aa2@mail.maestrano.com". But don't
82
97
  # worry we take care of forwarding any email you would send to this address
83
98
  #
84
- config.user_creation_mode = 'virtual' # or 'real'
99
+ # config.sso.creation_mode = 'real' # or 'virtual'
100
+
101
+ # ==> Account Webhooks
102
+ # Single sign on has been setup into your app and Maestrano users are now able
103
+ # to use your service. Great! Wait what happens when a business (group) decides to
104
+ # stop using your service? Also what happens when a user gets removed from a business?
105
+ # Well the endpoints below are for Maestrano to be able to notify you of such
106
+ # events.
107
+ #
108
+ # Even if the routes look restful we issue only issue DELETE requests for the moment
109
+ # to notify you of any service cancellation (group deletion) or any user being
110
+ # removed from a group.
111
+ #
112
+ # The controllers for these hooks path are automatically generated when
113
+ # you run 'rake maestrano:install' and is available under
114
+ # <rails_root>/app/controllers/maestrano/account/
115
+ #
116
+ # config.webhook.account.groups_path = '/maestrano/account/groups/:id',
117
+ # config.webhook.account.group_users_path = '/maestrano/account/groups/:group_id/users/:id',
85
118
  end
@@ -2,6 +2,14 @@ module ActionDispatch::Routing
2
2
  class Mapper
3
3
  def maestrano_routes
4
4
  namespace :maestrano do
5
+ scope module: :rails do
6
+ get '/metadata' => 'metadata#index'
7
+ end
8
+
9
+ namespace :rails do
10
+ get '/maestrano/metadata'
11
+ end
12
+
5
13
  namespace :auth do
6
14
  resources :saml, only:[] do
7
15
  get 'init', on: :collection
@@ -9,7 +17,7 @@ module ActionDispatch::Routing
9
17
  end
10
18
  end
11
19
 
12
- namespace :account_hook do
20
+ namespace :account do
13
21
  resources :groups, only: [:destroy] do
14
22
  resources :users, only: [:destroy], controller: 'group_users'
15
23
  end
@@ -1,5 +1,5 @@
1
1
  module Maestrano
2
2
  module Rails
3
- VERSION = "0.5.0"
3
+ VERSION = "0.6.0"
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class GroupUsersControllerTest < ActionController::TestCase
4
- tests Maestrano::AccountHook::GroupUsersController
4
+ tests Maestrano::Account::GroupUsersController
5
5
 
6
6
  context "unauthenticated" do
7
7
  should "deny access" do
@@ -12,7 +12,7 @@ class GroupUsersControllerTest < ActionController::TestCase
12
12
 
13
13
  context "authenticated" do
14
14
  setup do
15
- @request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64.encode64("#{Maestrano.param('app_id')}:#{Maestrano.param('api_key')}")
15
+ @request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64.encode64("#{Maestrano.param('api.id')}:#{Maestrano.param('api.key')}")
16
16
  end
17
17
 
18
18
  should "be successful" do
@@ -1,7 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class GroupsControllerTest < ActionController::TestCase
4
- tests Maestrano::AccountHook::GroupsController
4
+ tests Maestrano::Account::GroupsController
5
5
 
6
6
  context "unauthenticated" do
7
7
  should "deny access" do
@@ -12,7 +12,7 @@ class GroupsControllerTest < ActionController::TestCase
12
12
 
13
13
  context "authenticated" do
14
14
  setup do
15
- @request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64.encode64("#{Maestrano.param('app_id')}:#{Maestrano.param('api_key')}")
15
+ @request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64.encode64("#{Maestrano.param('api.id')}:#{Maestrano.param('api.key')}")
16
16
  end
17
17
 
18
18
  should "be successful" do
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class MetadataControllerTest < ActionController::TestCase
4
+ tests Maestrano::Rails::MetadataController
5
+
6
+ context "unauthenticated" do
7
+ should "deny access" do
8
+ get :index
9
+ assert_equal '401', response.code
10
+ end
11
+ end
12
+
13
+ context "authenticated" do
14
+ setup do
15
+ @request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64.encode64("#{Maestrano.param('api.id')}:#{Maestrano.param('api.key')}")
16
+ end
17
+
18
+ should "be successful" do
19
+ get :index
20
+ assert_equal '200', response.code
21
+ assert_equal Maestrano.to_metadata.to_json, response.body
22
+ end
23
+ end
24
+
25
+ end
@@ -1,23 +1,23 @@
1
- class Maestrano::AccountHook::GroupUsersController < Maestrano::Rails::WebHookController
1
+ class Maestrano::Account::GroupUsersController < Maestrano::Rails::WebHookController
2
2
 
3
3
  # DELETE /maestrano/account/groups/cld-1/users/usr-1
4
4
  # Remove a user from a group
5
5
  def destroy
6
- # Set the right uid based on Maestrano.param('user_creation_mode')
6
+ # Set the right uid based on Maestrano.param('sso.creation_mode')
7
7
  user_uid = Maestrano.mask_user(params[:id],params[:group_id])
8
8
  group_uid = params[:group_id]
9
9
  render text: "Yay!"
10
10
 
11
11
  # Perform association deletion steps here
12
12
  # --
13
- # If Maestrano.param('user_creation_mode') is set to virtual
13
+ # If Maestrano.param('sso.creation_mode') is set to virtual
14
14
  # then you might want to just delete/cancel/block the user
15
15
  #
16
16
  # E.g
17
17
  # user = User.find_by_provider_and_uid('maestrano',user_uid)
18
18
  # organization = Organization.find_by_provider_and_uid('maestrano',group_uid)
19
19
  #
20
- # if Maestrano.param('user_creation_mode') == 'virtual'
20
+ # if Maestrano.param('sso.creation_mode') == 'virtual'
21
21
  # user.destroy
22
22
  # else
23
23
  # organization.remove_user(user)
@@ -1,4 +1,4 @@
1
- class Maestrano::AccountHook::GroupsController < Maestrano::Rails::WebHookController
1
+ class Maestrano::Account::GroupsController < Maestrano::Rails::WebHookController
2
2
 
3
3
  # DELETE /maestrano/account/groups/cld-1
4
4
  # Delete an entire group
@@ -11,7 +11,7 @@ class Maestrano::AccountHook::GroupsController < Maestrano::Rails::WebHookContro
11
11
  # If you need to perform a final checkout
12
12
  # then you can call Maestrano::Account::Bill.create({.. final checkout details ..})
13
13
  # --
14
- # If Maestrano.param('user_creation_mode') is set to virtual
14
+ # If Maestrano.param('sso.creation_mode') is set to virtual
15
15
  # then you might want to delete/cancel/block all users under
16
16
  # that group
17
17
  # --
@@ -25,7 +25,7 @@ class Maestrano::AccountHook::GroupsController < Maestrano::Rails::WebHookContro
25
25
  # description: "Final Payout"
26
26
  # })
27
27
  #
28
- # if Maestrano.param('user_creation_mode') == 'virtual'
28
+ # if Maestrano.param('sso.creation_mode') == 'virtual'
29
29
  # organization.members.where(provider:'maestrano').each do |user|
30
30
  # user.destroy
31
31
  # end
@@ -68,18 +68,18 @@ Maestrano.configure do |config|
68
68
  #
69
69
  # == mode: 'real'
70
70
  # In an ideal world a user should be able to belong to several groups in your application.
71
- # In this case you would set the 'user_creation_mode' to 'real' which means that the uid
71
+ # In this case you would set the 'sso.creation_mode' to 'real' which means that the uid
72
72
  # and email we pass to you are the actual user email and maestrano universal id.
73
73
  #
74
74
  # == mode: 'virtual'
75
75
  # Now let's say that due to technical constraint your application cannot authorize a user
76
76
  # to belong to several groups. Well next time John logs in via a different group there will
77
77
  # be a problem: the user already exists (based on uid or email) and cannot be assigned
78
- # to a second group. To fix this you can set the 'user_creation_mode' to 'virtual'. In this
78
+ # to a second group. To fix this you can set the 'sso.creation_mode' to 'virtual'. In this
79
79
  # mode users get assigned a truly unique uid and email across groups. So next time John logs
80
80
  # in a whole new user account can be created for him without any validation problem. In this
81
81
  # mode the email we assign to him looks like "usr-sdf54.cld-45aa2@mail.maestrano.com". But don't
82
82
  # worry we take care of forwarding any email you would send to this address
83
83
  #
84
- config.user_creation_mode = 'virtual' # or 'real'
84
+ config.sso.creation_mode = 'virtual' # or 'real'
85
85
  end