forest_liana 2.12.0 → 2.13.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: df754c6c7de93be5e155ea18ca2a236e737ff9ed
4
- data.tar.gz: fb4fb5714e04982a5db0e474491c153cbbf28b47
3
+ metadata.gz: 90cfcbc6a189d0f813ab9be3b691b651147080b1
4
+ data.tar.gz: 20a7fb7fe5095658f63cd4e83f926959f90d45c3
5
5
  SHA512:
6
- metadata.gz: 9b9dd0d21d2a2001d980b6aee0d8f519731a331d559d58e394e5d8723033a5e17c1327da5ba8e1db83352189d3b4917c8d85abbe46b2ae5f54e8d23a140f34eb
7
- data.tar.gz: 9f10c5cca47362935d125593bb107eeea8d0119bf46ac275d3d096a134f8410ca7fca16e08ea01962ab7b9f9b6059f9f0c465e19e2f7c5e91e23ca1da72f48c9
6
+ metadata.gz: 33199e1098b84e64b5a90fc289b4f4aa67e40d77296a55887d77f8cd15332eac37eac91ec27df47679d97978366047b6ae3a05ad394d74dce26251c00e53071e
7
+ data.tar.gz: 59668615c97545bd736bff03f24273fd08e37ee89c51d0b3af2ea331776579c5f2deda5686158f58de8652f7f0e320f284dc43eedc6828d9889b6b205f6eba39
@@ -2,5 +2,35 @@ module ForestLiana
2
2
  class BaseController < ::ActionController::Base
3
3
  skip_before_action :verify_authenticity_token, raise: false
4
4
  wrap_parameters false
5
+ before_action :reject_unauthorized_ip
6
+
7
+ private
8
+
9
+ def reject_unauthorized_ip
10
+ begin
11
+ ip = request.remote_ip
12
+
13
+ if !IpWhitelist.is_ip_whitelist_retrieved || !IpWhitelist.is_ip_valid(ip)
14
+ unless IpWhitelist.retrieve
15
+ raise Errors::HTTP403Error.new("IP whitelist not retrieved")
16
+ end
17
+
18
+ unless IpWhitelist.is_ip_valid(ip)
19
+ raise Errors::HTTP403Error.new("IP address rejected (#{ip})")
20
+ end
21
+ end
22
+ rescue Errors::ExpectedError => exception
23
+ exception.display_error
24
+ error_data = JSONAPI::Serializer.serialize_errors([{
25
+ status: exception.error_code,
26
+ detail: exception.message
27
+ }])
28
+ render(serializer: nil, json: error_data, status: exception.status)
29
+ rescue => exception
30
+ FOREST_LOGGER.error(exception)
31
+ FOREST_LOGGER.error(exception.backtrace.join("\n"))
32
+ render(serializer: nil, json: nil, status: :internal_server_error)
33
+ end
34
+ end
5
35
  end
6
36
  end
@@ -53,7 +53,12 @@ module ForestLiana
53
53
  raise Errors::HTTP401Error
54
54
  end
55
55
 
56
- # TODO: Add ip whitelist retrieving when it exists.
56
+ # NOTICE: The IP Whitelist is retrieved on any request if it was not retrieved yet, or when
57
+ # an IP is rejected, to ensure the IP is still rejected (meaning the configuration
58
+ # on the projects has not changed). To handle the last case, which is rejecting an
59
+ # IP which was not initaliy rejected, we need periodically refresh the whitelist.
60
+ # This is done here on the login of any user.
61
+ IpWhitelist.retrieve
57
62
 
58
63
  reponse_data = LoginHandler.new(
59
64
  rendering_id,
@@ -0,0 +1,40 @@
1
+ module ForestLiana
2
+ class IpWhitelist
3
+ @@use_ip_whitelist = true
4
+ @@ip_whitelist_rules = nil
5
+
6
+ def self.retrieve
7
+ begin
8
+ response = ForestApiRequester.get('/liana/v1/ip-whitelist-rules')
9
+
10
+ if response.is_a?(Net::HTTPOK)
11
+ body = JSON.parse(response.body)
12
+ ip_whitelist_data = body['data']['attributes']
13
+
14
+ @@use_ip_whitelist = ip_whitelist_data['use_ip_whitelist']
15
+ @@ip_whitelist_rules = ip_whitelist_data['rules']
16
+ true
17
+ else
18
+ raise "Cannot retrieve the data from the Forest server. Forest API returned an #{Errors::HTTPErrorHelper.format(response)}"
19
+ end
20
+ rescue => exception
21
+ FOREST_LOGGER.error 'Cannot retrieve the IP Whitelist from the Forest server.'
22
+ FOREST_LOGGER.error 'Which was caused by:'
23
+ Errors::ExceptionHelper.recursively_print(exception, margin: ' ', is_error: true)
24
+ false
25
+ end
26
+ end
27
+
28
+ def self.is_ip_whitelist_retrieved
29
+ !@@use_ip_whitelist || !@@ip_whitelist_rules.nil?
30
+ end
31
+
32
+ def self.is_ip_valid(ip)
33
+ if @@use_ip_whitelist
34
+ return IpWhitelistChecker.is_ip_matches_any_rule(ip, @@ip_whitelist_rules)
35
+ end
36
+
37
+ true
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,71 @@
1
+ require 'ipaddress'
2
+
3
+ module ForestLiana
4
+ class IpWhitelistChecker
5
+ module RuleType
6
+ IP = 0
7
+ RANGE = 1
8
+ SUBNET = 2
9
+ end
10
+
11
+ def self.is_ip_matches_any_rule(ip, rules)
12
+ rules.any? { |rule| IpWhitelistChecker.is_ip_matches_rule(ip, rule) }
13
+ end
14
+
15
+ def self.is_ip_matches_rule(ip, rule)
16
+ if rule['type'] == RuleType::IP
17
+ return IpWhitelistChecker.is_ip_match_ip(ip, rule['ip'])
18
+ elsif rule['type'] == RuleType::RANGE
19
+ return IpWhitelistChecker.is_ip_match_range(ip, rule)
20
+ elsif rule['type'] == RuleType::SUBNET
21
+ return IpWhitelistChecker.is_ip_match_subnet(ip, rule['range'])
22
+ end
23
+
24
+ raise 'Invalid rule type'
25
+ end
26
+
27
+ def self.ip_version(ip)
28
+ (IPAddress ip).is_a?(IPAddress::IPv4) ? :ip_v4 : :ip_v6
29
+ end
30
+
31
+ def self.is_same_ip_version(ip1, ip2)
32
+ ip1_version = IpWhitelistChecker.ip_version(ip1)
33
+ ip2_version = IpWhitelistChecker.ip_version(ip2)
34
+
35
+ ip1_version == ip2_version
36
+ end
37
+
38
+ def self.is_both_loopback(ip1, ip2)
39
+ IPAddress(ip1).loopback? && IPAddress(ip2).loopback?
40
+ end
41
+
42
+ def self.is_ip_match_ip(ip1, ip2)
43
+ if !IpWhitelistChecker.is_same_ip_version(ip1, ip2)
44
+ return IpWhitelistChecker.is_both_loopback(ip1, ip2)
45
+ end
46
+
47
+ if IPAddress(ip1) == IPAddress(ip2)
48
+ true
49
+ else
50
+ IpWhitelistChecker.is_both_loopback(ip1, ip2)
51
+ end
52
+ end
53
+
54
+ def self.is_ip_match_range(ip, rule)
55
+ return false if !IpWhitelistChecker.is_same_ip_version(ip, rule['ip_minimum'])
56
+
57
+ ip_range_minimum = (IPAddress rule['ip_minimum']).to_i
58
+ ip_range_maximum = (IPAddress rule['ip_maximum']).to_i
59
+ ip_value = (IPAddress ip).to_i
60
+
61
+ return ip_value >= ip_range_minimum && ip_value <= ip_range_maximum;
62
+ end
63
+
64
+ def self.is_ip_match_subnet(ip, subnet)
65
+ return false if !IpWhitelistChecker.is_same_ip_version(ip, subnet)
66
+
67
+ IPAddress(subnet).include?(IPAddress(ip))
68
+ end
69
+ end
70
+
71
+ end
@@ -22,7 +22,7 @@ module ForestLiana
22
22
  @message = message
23
23
  end
24
24
 
25
- def display_error()
25
+ def display_error
26
26
  ExceptionHelper.recursively_print(self)
27
27
  end
28
28
  end
@@ -33,6 +33,12 @@ module ForestLiana
33
33
  end
34
34
  end
35
35
 
36
+ class HTTP403Error < ExpectedError
37
+ def initialize(message = "Forbidden")
38
+ super(403, :forbidden, message)
39
+ end
40
+ end
41
+
36
42
  class ExceptionHelper
37
43
  def self.recursively_print(error, margin: '', is_error: false)
38
44
  logger = is_error ?
@@ -1,3 +1,3 @@
1
1
  module ForestLiana
2
- VERSION = "2.12.0"
2
+ VERSION = "2.13.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forest_liana
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.12.0
4
+ version: 2.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sandro Munda
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: ipaddress
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
167
181
  description: Forest is a modern admin interface that works on all major web frameworks.
168
182
  forest_liana is the gem that makes Forest admin work on any Rails application (Rails
169
183
  >= 4.0).
@@ -227,6 +241,8 @@ files:
227
241
  - app/services/forest_liana/intercom_attributes_getter.rb
228
242
  - app/services/forest_liana/intercom_conversation_getter.rb
229
243
  - app/services/forest_liana/intercom_conversations_getter.rb
244
+ - app/services/forest_liana/ip_whitelist.rb
245
+ - app/services/forest_liana/ip_whitelist_checker.rb
230
246
  - app/services/forest_liana/line_stat_getter.rb
231
247
  - app/services/forest_liana/live_query_checker.rb
232
248
  - app/services/forest_liana/login_handler.rb