forest_liana 5.3.0 → 6.0.0.pre.beta.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/forest_liana/actions_controller.rb +0 -82
  3. data/app/controllers/forest_liana/application_controller.rb +1 -7
  4. data/app/controllers/forest_liana/authentication_controller.rb +122 -0
  5. data/app/controllers/forest_liana/base_controller.rb +4 -0
  6. data/app/controllers/forest_liana/router.rb +2 -2
  7. data/app/controllers/forest_liana/sessions_controller.rb +1 -1
  8. data/app/controllers/forest_liana/stats_controller.rb +5 -5
  9. data/app/helpers/forest_liana/adapter_helper.rb +1 -1
  10. data/app/models/forest_liana/model/action.rb +1 -2
  11. data/app/serializers/forest_liana/schema_serializer.rb +2 -2
  12. data/app/services/forest_liana/apimap_sorter.rb +1 -2
  13. data/app/services/forest_liana/authentication.rb +59 -0
  14. data/app/services/forest_liana/authorization_getter.rb +12 -20
  15. data/app/services/forest_liana/forest_api_requester.rb +14 -5
  16. data/app/services/forest_liana/ip_whitelist_checker.rb +1 -1
  17. data/app/services/forest_liana/login_handler.rb +3 -11
  18. data/app/services/forest_liana/oidc_client_manager.rb +34 -0
  19. data/app/services/forest_liana/oidc_configuration_retriever.rb +12 -0
  20. data/app/services/forest_liana/oidc_dynamic_client_registrator.rb +67 -0
  21. data/app/services/forest_liana/permissions_checker.rb +1 -1
  22. data/app/services/forest_liana/query_stat_getter.rb +5 -5
  23. data/app/services/forest_liana/resources_getter.rb +3 -3
  24. data/app/services/forest_liana/token.rb +27 -0
  25. data/config/initializers/error-messages.rb +20 -0
  26. data/config/routes.rb +5 -2
  27. data/lib/forest_liana.rb +1 -0
  28. data/lib/forest_liana/bootstrapper.rb +1 -20
  29. data/lib/forest_liana/collection.rb +2 -2
  30. data/lib/forest_liana/engine.rb +9 -0
  31. data/lib/forest_liana/json_printer.rb +1 -1
  32. data/lib/forest_liana/schema_file_updater.rb +0 -1
  33. data/lib/forest_liana/version.rb +1 -1
  34. data/spec/dummy/config/initializers/forest_liana.rb +1 -0
  35. data/spec/requests/authentications_spec.rb +107 -0
  36. data/spec/requests/sessions_spec.rb +55 -0
  37. data/spec/services/forest_liana/apimap_sorter_spec.rb +4 -6
  38. metadata +57 -9
  39. data/app/helpers/forest_liana/is_same_data_structure_helper.rb +0 -44
  40. data/spec/helpers/forest_liana/is_same_data_structure_helper_spec.rb +0 -87
  41. data/spec/requests/actions_controller_spec.rb +0 -136
@@ -0,0 +1,55 @@
1
+ require 'rails_helper'
2
+ require 'openid_connect'
3
+ require 'json'
4
+
5
+ RSpec.describe "Authentications", type: :request do
6
+ before() do
7
+ allow(ForestLiana::IpWhitelist).to receive(:retrieve) { true }
8
+ allow(ForestLiana::IpWhitelist).to receive(:is_ip_whitelist_retrieved) { true }
9
+ allow(ForestLiana::IpWhitelist).to receive(:is_ip_valid) { true }
10
+
11
+ body = '{"data":{"id":"654","type":"users","attributes":{"email":"user@email.com","first_name":"FirstName","last_name":"LastName","teams":["Operations"]}},"relationships":{"renderings":{"data":[{"id":1,"type":"renderings"}]}}}'
12
+ allow(ForestLiana::ForestApiRequester).to receive(:get).with(
13
+ "/liana/v2/renderings/42/authorization", { :headers => { "forest-token" => "google-access-token" }, :query=> {} }
14
+ ).and_return(
15
+ instance_double(HTTParty::Response, :body => body, :code => 200)
16
+ )
17
+ end
18
+
19
+ after() do
20
+ Rails.cache.delete(URI.join(ForestLiana.application_url, ForestLiana::Engine.routes.url_helpers.authentication_callback_path).to_s)
21
+ end
22
+
23
+ headers = {
24
+ 'Accept' => 'application/json',
25
+ 'Content-Type' => 'application/json',
26
+ }
27
+
28
+ describe "POST /forest/sessions-google" do
29
+ before() do
30
+ post ForestLiana::Engine.routes.url_helpers.sessions_google_path, { :renderingId => 42, :forestToken => "google-access-token" }, :headers => headers
31
+ end
32
+
33
+ it "should respond with a 200 code" do
34
+ expect(response).to have_http_status(200)
35
+ end
36
+
37
+ it "should return a valid authentication token" do
38
+ response_body = JSON.parse(response.body, :symbolize_names => true)
39
+ expect(response_body).to have_key(:token)
40
+
41
+ token = response_body[:token]
42
+ decoded = JWT.decode(token, ForestLiana.auth_secret, true, { algorithm: 'HS256' })[0]
43
+
44
+ expected_token_data = {
45
+ "id" => '654',
46
+ "email" => 'user@email.com',
47
+ "first_name" => 'FirstName',
48
+ "last_name" => 'LastName',
49
+ "rendering_id" => "42",
50
+ "team" => 'Operations'
51
+ }
52
+ expect(decoded).to include(expected_token_data);
53
+ end
54
+ end
55
+ end
@@ -75,8 +75,7 @@ module ForestLiana
75
75
  type: 'File',
76
76
  field: 'File'
77
77
  }],
78
- http_method: nil,
79
- hooks: nil,
78
+ http_method: nil
80
79
  }
81
80
  }, {
82
81
  attributes: {
@@ -96,8 +95,7 @@ module ForestLiana
96
95
  download: nil,
97
96
  endpoint: nil,
98
97
  redirect: nil,
99
- 'http_method': nil,
100
- hooks: nil,
98
+ 'http_method': nil
101
99
  }
102
100
  }]
103
101
  }
@@ -150,8 +148,8 @@ module ForestLiana
150
148
  end
151
149
 
152
150
  it 'should sort the included actions and segments objects attributes values' do
153
- expect(apimap_sorted['included'][0]['attributes'].keys).to eq(['name', 'endpoint', 'http_method', 'redirect', 'download', 'hooks'])
154
- expect(apimap_sorted['included'][1]['attributes'].keys).to eq(['name', 'http_method', 'fields', 'hooks'])
151
+ expect(apimap_sorted['included'][0]['attributes'].keys).to eq(['name', 'endpoint', 'http_method', 'redirect', 'download'])
152
+ expect(apimap_sorted['included'][1]['attributes'].keys).to eq(['name', 'http_method', 'fields'])
155
153
  expect(apimap_sorted['included'][2]['attributes'].keys).to eq(['name'])
156
154
  expect(apimap_sorted['included'][3]['attributes'].keys).to eq(['name'])
157
155
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forest_liana
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.3.0
4
+ version: 6.0.0.pre.beta.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sandro Munda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-07 00:00:00.000000000 Z
11
+ date: 2020-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -178,6 +178,48 @@ dependencies:
178
178
  - - ">="
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: json
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: json-jwt
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :runtime
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: openid_connect
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :runtime
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
181
223
  description: Forest is a modern admin interface that works on all major web frameworks.
182
224
  forest_liana is the gem that makes Forest admin work on any Rails application (Rails
183
225
  >= 4.0).
@@ -197,6 +239,7 @@ files:
197
239
  - app/controllers/forest_liana/apimaps_controller.rb
198
240
  - app/controllers/forest_liana/application_controller.rb
199
241
  - app/controllers/forest_liana/associations_controller.rb
242
+ - app/controllers/forest_liana/authentication_controller.rb
200
243
  - app/controllers/forest_liana/base_controller.rb
201
244
  - app/controllers/forest_liana/devise_controller.rb
202
245
  - app/controllers/forest_liana/intercom_controller.rb
@@ -211,7 +254,6 @@ files:
211
254
  - app/helpers/forest_liana/adapter_helper.rb
212
255
  - app/helpers/forest_liana/application_helper.rb
213
256
  - app/helpers/forest_liana/decoration_helper.rb
214
- - app/helpers/forest_liana/is_same_data_structure_helper.rb
215
257
  - app/helpers/forest_liana/query_helper.rb
216
258
  - app/helpers/forest_liana/schema_helper.rb
217
259
  - app/models/forest_liana/model/action.rb
@@ -231,6 +273,7 @@ files:
231
273
  - app/serializers/forest_liana/stripe_payment_serializer.rb
232
274
  - app/serializers/forest_liana/stripe_subscription_serializer.rb
233
275
  - app/services/forest_liana/apimap_sorter.rb
276
+ - app/services/forest_liana/authentication.rb
234
277
  - app/services/forest_liana/authorization_getter.rb
235
278
  - app/services/forest_liana/base_getter.rb
236
279
  - app/services/forest_liana/belongs_to_updater.rb
@@ -252,6 +295,9 @@ files:
252
295
  - app/services/forest_liana/login_handler.rb
253
296
  - app/services/forest_liana/mixpanel_last_events_getter.rb
254
297
  - app/services/forest_liana/objective_stat_getter.rb
298
+ - app/services/forest_liana/oidc_client_manager.rb
299
+ - app/services/forest_liana/oidc_configuration_retriever.rb
300
+ - app/services/forest_liana/oidc_dynamic_client_registrator.rb
255
301
  - app/services/forest_liana/operator_date_interval_parser.rb
256
302
  - app/services/forest_liana/permissions_checker.rb
257
303
  - app/services/forest_liana/permissions_getter.rb
@@ -276,11 +322,13 @@ files:
276
322
  - app/services/forest_liana/stripe_sources_getter.rb
277
323
  - app/services/forest_liana/stripe_subscription_getter.rb
278
324
  - app/services/forest_liana/stripe_subscriptions_getter.rb
325
+ - app/services/forest_liana/token.rb
279
326
  - app/services/forest_liana/two_factor_registration_confirmer.rb
280
327
  - app/services/forest_liana/user_secret_creator.rb
281
328
  - app/services/forest_liana/value_stat_getter.rb
282
329
  - app/views/layouts/forest_liana/application.html.erb
283
330
  - config/initializers/arel-helpers.rb
331
+ - config/initializers/error-messages.rb
284
332
  - config/initializers/errors.rb
285
333
  - config/initializers/logger.rb
286
334
  - config/initializers/time_formats.rb
@@ -337,12 +385,12 @@ files:
337
385
  - spec/dummy/db/migrate/20190716130830_add_age_to_tree.rb
338
386
  - spec/dummy/db/migrate/20190716135241_add_type_to_user.rb
339
387
  - spec/dummy/db/schema.rb
340
- - spec/helpers/forest_liana/is_same_data_structure_helper_spec.rb
341
388
  - spec/helpers/forest_liana/query_helper_spec.rb
342
389
  - spec/helpers/forest_liana/schema_helper_spec.rb
343
390
  - spec/rails_helper.rb
344
- - spec/requests/actions_controller_spec.rb
391
+ - spec/requests/authentications_spec.rb
345
392
  - spec/requests/resources_spec.rb
393
+ - spec/requests/sessions_spec.rb
346
394
  - spec/services/forest_liana/apimap_sorter_spec.rb
347
395
  - spec/services/forest_liana/filters_parser_spec.rb
348
396
  - spec/services/forest_liana/ip_whitelist_checker_spec.rb
@@ -454,9 +502,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
454
502
  version: '0'
455
503
  required_rubygems_version: !ruby/object:Gem::Requirement
456
504
  requirements:
457
- - - ">="
505
+ - - ">"
458
506
  - !ruby/object:Gem::Version
459
- version: '0'
507
+ version: 1.3.1
460
508
  requirements: []
461
509
  rubygems_version: 3.0.8
462
510
  signing_key:
@@ -559,7 +607,8 @@ test_files:
559
607
  - spec/services/forest_liana/apimap_sorter_spec.rb
560
608
  - spec/services/forest_liana/filters_parser_spec.rb
561
609
  - spec/spec_helper.rb
562
- - spec/requests/actions_controller_spec.rb
610
+ - spec/requests/sessions_spec.rb
611
+ - spec/requests/authentications_spec.rb
563
612
  - spec/requests/resources_spec.rb
564
613
  - spec/dummy/README.rdoc
565
614
  - spec/dummy/app/views/layouts/application.html.erb
@@ -602,6 +651,5 @@ test_files:
602
651
  - spec/dummy/config/initializers/backtrace_silencers.rb
603
652
  - spec/dummy/config/database.yml
604
653
  - spec/helpers/forest_liana/schema_helper_spec.rb
605
- - spec/helpers/forest_liana/is_same_data_structure_helper_spec.rb
606
654
  - spec/helpers/forest_liana/query_helper_spec.rb
607
655
  - spec/rails_helper.rb
@@ -1,44 +0,0 @@
1
- require 'set'
2
-
3
- module ForestLiana
4
- module IsSameDataStructureHelper
5
- class Analyser
6
- def initialize(object, other, deep = 0)
7
- @object = object
8
- @other = other
9
- @deep = deep
10
- end
11
-
12
- def are_objects(object, other)
13
- object && other && object.is_a?(Hash) && other.is_a?(Hash)
14
- end
15
-
16
- def check_keys(object, other, step = 0)
17
- unless are_objects(object, other)
18
- return false
19
- end
20
-
21
- object_keys = object.keys
22
- other_keys = other.keys
23
-
24
- if object_keys.length != other_keys.length
25
- return false
26
- end
27
-
28
- object_keys_set = object_keys.to_set
29
- other_keys.each { |key|
30
- if !object_keys_set.member?(key) || (step + 1 <= @deep && !check_keys(object[key], other[key], step + 1))
31
- return false
32
- end
33
- }
34
-
35
- return true
36
- end
37
-
38
- def perform
39
- check_keys(@object, @other)
40
- end
41
- end
42
- end
43
- end
44
-
@@ -1,87 +0,0 @@
1
- module ForestLiana
2
- context 'IsSameDataStructure class' do
3
- it 'should: be valid with simple data' do
4
- object = {:a => 'a', :b => 'b'}
5
- other = {:a => 'a', :b => 'b'}
6
- result = IsSameDataStructureHelper::Analyser.new(object, other).perform
7
- expect(result).to be true
8
- end
9
-
10
- it 'should: be invalid with simple data' do
11
- object = {:a => 'a', :b => 'b'}
12
- other = {:a => 'a', :c => 'c'}
13
- result = IsSameDataStructureHelper::Analyser.new(object, other).perform
14
- expect(result).to be false
15
- end
16
-
17
- it 'should: be invalid with not same hash' do
18
- object = {:a => 'a', :b => 'b'}
19
- other = {:a => 'a', :b => 'b', :c => 'c'}
20
- result = IsSameDataStructureHelper::Analyser.new(object, other).perform
21
- expect(result).to be false
22
- end
23
-
24
- it 'should: be invalid with nil' do
25
- object = nil
26
- other = {:a => 'a', :b => 'b', :c => 'c'}
27
- result = IsSameDataStructureHelper::Analyser.new(object, other).perform
28
- expect(result).to be false
29
- end
30
-
31
- it 'should: be invalid with not hash' do
32
- object = nil
33
- other = {:a => 'a', :b => 'b', :c => 'c'}
34
- result = IsSameDataStructureHelper::Analyser.new(object, other).perform
35
- expect(result).to be false
36
- end
37
-
38
- it 'should: be invalid with integer' do
39
- object = 1
40
- other = {:a => 'a', :b => 'b', :c => 'c'}
41
- result = IsSameDataStructureHelper::Analyser.new(object, other).perform
42
- expect(result).to be false
43
- end
44
-
45
- it 'should: be invalid with string' do
46
- object = 'a'
47
- other = {:a => 'a', :b => 'b', :c => 'c'}
48
- result = IsSameDataStructureHelper::Analyser.new(object, other).perform
49
- expect(result).to be false
50
- end
51
-
52
- it 'should: be valid with depth 1' do
53
- object = {:a => {:c => 'c'}, :b => {:d => 'd'}}
54
- other = {:a => {:c => 'c'}, :b => {:d => 'd'}}
55
- result = IsSameDataStructureHelper::Analyser.new(object, other, 1).perform
56
- expect(result).to be true
57
- end
58
-
59
- it 'should: be invalid with depth 1' do
60
- object = {:a => {:c => 'c'}, :b => {:d => 'd'}}
61
- other = {:a => {:c => 'c'}, :b => {:e => 'e'}}
62
- result = IsSameDataStructureHelper::Analyser.new(object, other, 1).perform
63
- expect(result).to be false
64
- end
65
-
66
- it 'should: be invalid with depth 1 and nil' do
67
- object = {:a => {:c => 'c'}, :b => {:d => 'd'}}
68
- other = {:a => {:c => 'c'}, :b => nil}
69
- result = IsSameDataStructureHelper::Analyser.new(object, other, 1).perform
70
- expect(result).to be false
71
- end
72
-
73
- it 'should: be invalid with depth 1 and integer' do
74
- object = {:a => {:c => 'c'}, :b => {:d => 'd'}}
75
- other = {:a => {:c => 'c'}, :b => 1}
76
- result = IsSameDataStructureHelper::Analyser.new(object, other, 1).perform
77
- expect(result).to be false
78
- end
79
-
80
- it 'should: be invalid with depth 1 and string' do
81
- object = {:a => {:c => 'c'}, :b => {:d => 'd'}}
82
- other = {:a => {:c => 'c'}, :b => 'b'}
83
- result = IsSameDataStructureHelper::Analyser.new(object, other, 1).perform
84
- expect(result).to be false
85
- end
86
- end
87
- end
@@ -1,136 +0,0 @@
1
- require 'rails_helper'
2
-
3
- describe 'Requesting Actions routes', :type => :request do
4
- before(:each) do
5
- allow(ForestLiana::IpWhitelist).to receive(:is_ip_whitelist_retrieved) { true }
6
- allow(ForestLiana::IpWhitelist).to receive(:is_ip_valid) { true }
7
- Island.create(name: 'Corsica')
8
- end
9
-
10
- after(:each) do
11
- Island.destroy_all
12
- end
13
-
14
- describe 'call /values' do
15
- it 'should respond 200' do
16
- post '/forest/actions/foo/values', {}
17
- expect(response.status).to eq(200)
18
- expect(response.body).to be {}
19
- end
20
- end
21
-
22
- describe 'hooks' do
23
- foo = {
24
- field: 'foo',
25
- type: 'String',
26
- default_value: nil,
27
- enums: nil,
28
- is_required: false,
29
- reference: nil,
30
- description: nil,
31
- widget: nil,
32
- }
33
- action_definition = {
34
- name: 'my_action',
35
- fields: [foo],
36
- hooks: {
37
- :load => -> (context) {
38
- context[:fields]
39
- },
40
- :change => {
41
- 'foo' => -> (context) {
42
- fields = context[:fields]
43
- fields['foo'][:value] = 'baz'
44
- return fields
45
- }
46
- }
47
- }
48
- }
49
- fail_action_definition = {
50
- name: 'fail_action',
51
- fields: [foo],
52
- hooks: {
53
- :load => -> (context) {
54
- 1
55
- },
56
- :change => {
57
- 'foo' => -> (context) {
58
- 1
59
- }
60
- }
61
- }
62
- }
63
- cheat_action_definition = {
64
- name: 'cheat_action',
65
- fields: [foo],
66
- hooks: {
67
- :load => -> (context) {
68
- context[:fields]['baz'] = foo.clone.update({field: 'baz'})
69
- context[:fields]
70
- },
71
- :change => {
72
- 'foo' => -> (context) {
73
- context[:fields]['baz'] = foo.clone.update({field: 'baz'})
74
- context[:fields]
75
- }
76
- }
77
- }
78
- }
79
- action = ForestLiana::Model::Action.new(action_definition)
80
- fail_action = ForestLiana::Model::Action.new(fail_action_definition)
81
- cheat_action = ForestLiana::Model::Action.new(cheat_action_definition)
82
- island = ForestLiana.apimap.find {|collection| collection.name.to_s == ForestLiana.name_for(Island)}
83
- island.actions = [action, fail_action, cheat_action]
84
-
85
- describe 'call /load' do
86
- params = {recordIds: [1], collectionName: 'Island'}
87
-
88
- it 'should respond 200' do
89
- post '/forest/actions/my_action/hooks/load', JSON.dump(params), 'CONTENT_TYPE' => 'application/json'
90
- expect(response.status).to eq(200)
91
- expect(JSON.parse(response.body)).to eq({'fields' => [foo.merge({:value => nil}).stringify_keys]})
92
- end
93
-
94
- it 'should respond 500 with bad params' do
95
- post '/forest/actions/my_action/hooks/load', {}
96
- expect(response.status).to eq(500)
97
- end
98
-
99
- it 'should respond 500 with bad hook result type' do
100
- post '/forest/actions/fail_action/hooks/load', JSON.dump(params), 'CONTENT_TYPE' => 'application/json'
101
- expect(response.status).to eq(500)
102
- end
103
-
104
- it 'should respond 500 with bad hook result data structure' do
105
- post '/forest/actions/cheat_action/hooks/load', JSON.dump(params), 'CONTENT_TYPE' => 'application/json'
106
- expect(response.status).to eq(500)
107
- end
108
- end
109
-
110
- describe 'call /change' do
111
- updated_foo = foo.clone.merge({:previousValue => nil, :value => 'bar'})
112
- params = {recordIds: [1], fields: [updated_foo], collectionName: 'Island'}
113
-
114
- it 'should respond 200' do
115
- post '/forest/actions/my_action/hooks/change', JSON.dump(params), 'CONTENT_TYPE' => 'application/json'
116
- expect(response.status).to eq(200)
117
- expect(JSON.parse(response.body)).to eq({'fields' => [updated_foo.merge({:value => 'baz'}).stringify_keys]})
118
- end
119
-
120
- it 'should respond 500 with bad params' do
121
- post '/forest/actions/my_action/hooks/change', {}
122
- expect(response.status).to eq(500)
123
- end
124
-
125
- it 'should respond 500 with bad hook result type' do
126
- post '/forest/actions/fail_action/hooks/change', JSON.dump(params), 'CONTENT_TYPE' => 'application/json'
127
- expect(response.status).to eq(500)
128
- end
129
-
130
- it 'should respond 500 with bad hook result data structure' do
131
- post '/forest/actions/cheat_action/hooks/change', JSON.dump(params), 'CONTENT_TYPE' => 'application/json'
132
- expect(response.status).to eq(500)
133
- end
134
- end
135
- end
136
- end