nexpose_paloalto 0.1.1 → 0.1.2

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: 14c752bd0571d6cb5572c01e07eef1ee27178c72
4
- data.tar.gz: a1f4eca110f7765547a98e6b571d3e0c1bdd80b8
3
+ metadata.gz: 4031017be8639d09edbb9fef2ffb3ec43b21330e
4
+ data.tar.gz: f75c2a16d0ce151d132a77eaf11c9e3b377b2cbb
5
5
  SHA512:
6
- metadata.gz: 6bebc678b2e03d9b01720fb84362f6f97927b5a44e464d3c49170304a68abca80ba114bbc09492145a6bcd99d38e2d23e9dc2ae6e3598925e641e0801b400763
7
- data.tar.gz: ddb4b6a8a0e1456d46dd2b1b0f098892946f520cd6c428e0f39bbbb23fa88a76b2c382ad2f0eaa9947b1590f19129e99ed68d9ed2dcd8a7e8a261dcb4404db6c
6
+ metadata.gz: 410ba9dfbe608b1465fdc6bd5967f561537e1ef3b36799ff9454d9440de7a3d708f68a80ba82112b68f88ac7196a6c5941d9f9ed6c0fea48a36a88980b4a9034
7
+ data.tar.gz: 3495a3363873daa1faa9fc2956262907d37f6e7122e1ae269094c41c01cce8f12f5d910df0cda6dc579b076d271699de2252779dee83b7be5935525f79c9866c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nexpose_paloalto (0.1.0)
4
+ nexpose_paloalto (0.1.1)
5
5
  curb (~> 0.8.7)
6
6
  nexpose (~> 0.9)
7
7
  nokogiri (~> 1.6)
data/README.md CHANGED
@@ -59,5 +59,5 @@ For Windows systems, make sure they are on the Environment Variables section in
59
59
  * (Optional) Review the log file under the logs folder in the Gem path.
60
60
 
61
61
 
62
- For any support requests, please email integrations_support@rapid7.com with a description of the issue and any logs
62
+ For any support requests, please email support@rapid7.com with a description of the issue and any logs
63
63
  available.
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env ruby
1
2
  require 'paloalto'
2
3
 
3
4
  # Obtain Nexpose settings from Environment Variables.
@@ -6,6 +7,8 @@ raise 'Must configure nexpose settings before starting' if ENV['NEXPOSE_URL'].ni
6
7
  nexpose_settings[:nexpose_url] = ENV['NEXPOSE_URL']
7
8
  nexpose_settings[:nexpose_username] = ENV['NEXPOSE_USERNAME']
8
9
  nexpose_settings[:nexpose_password] = ENV['NEXPOSE_PASSWORD']
10
+ # User can change the port if Nexpose does not use port 3780
11
+ nexpose_settings[:nexpose_port] = 3780
9
12
 
10
13
  # Obtain PAN's info.
11
14
  pan_settings = Hash.new
data/lib/paloalto.rb CHANGED
@@ -16,6 +16,7 @@ module Paloalto
16
16
  nexpose_url = nexpose_settings[:nexpose_url]
17
17
  nexpose_username = nexpose_settings[:nexpose_username]
18
18
  nexpose_password = nexpose_settings[:nexpose_password]
19
+ nexpose_port = nexpose_settings[:nexpose_port]
19
20
 
20
21
  pan_url = pan_settings[:pan_url]
21
22
  pan_username = pan_settings[:pan_username]
@@ -24,7 +25,11 @@ module Paloalto
24
25
  report_timeout = nexpose_settings[:timeout]
25
26
 
26
27
  #Setup logging
27
- @log = Paloalto::NXLogger.new
28
+ @log = Paloalto::NxLogger.instance
29
+ @log.setup_statistics_collection(Paloalto::VENDOR,
30
+ Paloalto::PRODUCT,
31
+ Paloalto::VERSION)
32
+ @log.setup_logging(true, 'info')
28
33
 
29
34
  #Nexpose sites and DAGs to import. Uses Site Id and DAG ID e.g. 'sites = [1,2,3,4]'. Leave as nil to run on all sites and DAGs the user has access to or
30
35
  # set as an empty array e.g. 'dags=[]' to not run on any sites/dags.
@@ -34,9 +39,12 @@ module Paloalto
34
39
  @log.log_message("Running with user configured site IDs <#{sites}> and dynamic asset group IDs #{dags}.")
35
40
 
36
41
  # Log in to nexpose.
37
- nsc = Paloalto::NexposeHelper.login(nexpose_url, nexpose_username, nexpose_password)
42
+ nsc = Paloalto::NexposeHelper.login(nexpose_url,
43
+ nexpose_username,
44
+ nexpose_password,
45
+ nexpose_port)
38
46
 
39
- #Gather the sites
47
+ # Gather the sites
40
48
  all_sites = nsc.sites
41
49
  all_sites.delete_if {|site| !(sites.include? site.id)} unless sites.nil?
42
50
  all_sites_names = []
@@ -53,53 +61,53 @@ module Paloalto
53
61
  # Login to PAN.
54
62
  pan_key = Paloalto::Ngfw.login(pan_url, pan_username, pan_password)
55
63
 
56
- #Get the device config
64
+ # Get the device config
57
65
  device_config_xml = Paloalto::Ngfw.retrieve_device_config(pan_url, pan_key)
58
66
 
59
- #Get the device names
67
+ # Get the device names
60
68
  device_name = Paloalto::Ngfw.parse_device_name(device_config_xml)
61
69
  vsys_name = Paloalto::Ngfw.parse_vsys_name(device_config_xml)
62
70
 
63
71
  @log.log_message("Found device configuration. Name <#{device_name}> and vsys <#{vsys_name}>.")
64
72
 
65
- #Get this device's config
73
+ # Get this device's config
66
74
  vsys_config = Paloalto::Ngfw.retrieve_device_config(pan_url, pan_key, device_name, vsys_name)
67
75
 
68
- #Get the existing tags
76
+ # Get the existing tags
69
77
  existing_tags = Paloalto::Ngfw.parse_existing_tags(vsys_config)
70
78
 
71
- #Gather the tags we want to create
79
+ # Gather the tags we want to create
72
80
  wanted_tags = []
73
81
  all_sites_names.each {|site_name| wanted_tags << site_name.gsub(/[()]/, "")}
74
82
  wanted_tags << 'Nexpose'
75
83
  all_nexpose_dag_details.each {|details| wanted_tags << details[1].gsub(/[()']/, "")}
76
84
 
77
- #Find which new tags need to be created
85
+ # Finds which new tags need to be created
78
86
  tags_to_create = wanted_tags - existing_tags
79
87
 
80
88
  @log.log_message("New tags to be created <#{tags_to_create}>.")
81
89
 
82
- #Find the existing DAGs
90
+ # Find the existing DAGs
83
91
  existing_dags = Paloalto::Ngfw.parse_existing_dags(vsys_config)
84
92
 
85
- #Gather the dags we want to create
93
+ # Gather the dags we want to create
86
94
  wanted_dags = []
87
95
  all_sites_names.each {|site_name| wanted_dags << site_name.gsub(/[()]/, "")}
88
96
  wanted_dags << 'Nexpose'
89
97
  all_nexpose_dag_details.each {|details| wanted_dags << details[1].gsub(/[()']/, "")}
90
98
 
91
- #Find which new dags need to be created
99
+ # Find which new dags need to be created
92
100
  dags_to_create = wanted_dags - existing_dags
93
101
 
94
102
  @log.log_message("New DAGs to be created <#{dags_to_create}>.")
95
103
 
96
- #Create the new tags
104
+ # Create the new tags
97
105
  @log.log_message("Creating tags...")
98
106
  tags_element=''
99
107
  tags_to_create.each {|tag_to_create| tags_element << Paloalto::Ngfw.generate_tag_xml(tag_to_create, 'color3', "Nexpose tag for asset grouping: #{tag_to_create}")}
100
108
  response = Paloalto::Ngfw.create_tags(pan_url, pan_key, device_name, vsys_name, tags_element) unless tags_element.empty?
101
109
 
102
- #Create the new dags
110
+ # Create the new dags
103
111
  @log.log_message("Creating DAGs...")
104
112
  dags_element=''
105
113
  dags_to_create.each {|dag_to_create| dags_element << Paloalto::Ngfw.generate_dag_xml(dag_to_create, "'Nexpose' AND '#{dag_to_create}'", dag_to_create)}
@@ -107,7 +115,7 @@ module Paloalto
107
115
 
108
116
  @log.log_message('Committing the changes...')
109
117
 
110
- #Commit the changes
118
+ # Commit the changes
111
119
  response = Paloalto::Ngfw.commit(pan_url, pan_key)
112
120
 
113
121
  @log.log_message("Commit response <#{response}>")
@@ -5,10 +5,11 @@ module Paloalto
5
5
  require 'paloalto/nx_logger'
6
6
 
7
7
  # Logs in to Nexpose using the url, username and password.
8
- def self.login(url=nil, username=nil, password=nil)
8
+ def self.login(url=nil, username=nil, password=nil, port=3780)
9
9
  raise 'Nexpose connection must be set in environment variables.' if url.nil? || username.nil? || password.nil?
10
- nsc = Nexpose::Connection.new(url, username, password)
10
+ nsc = Nexpose::Connection.new(url, username, password, port)
11
11
  nsc.login
12
+ Paloalto::NxLogger.instance.on_connect(url, port, nsc.session_id, "{}")
12
13
  nsc
13
14
  end
14
15
 
@@ -1,27 +1,166 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+ require 'net/http'
4
+ require 'singleton'
5
+
1
6
  module Paloalto
2
- class NXLogger
3
- LOGGER_FILE = File.join(File.dirname(__FILE__), './logs/rapid7_palo_alto.log')
4
-
5
- attr_accessor :options
6
-
7
- def initialize
8
- setup_logging()
9
- end
10
-
11
- def setup_logging(enabled = true)
12
- if enabled
13
- require 'logger'
14
- directory = File.dirname(LOGGER_FILE)
15
- FileUtils.mkdir_p(directory) unless File.directory?(directory)
16
- @log = Logger.new(LOGGER_FILE, 'monthly')
17
- @log.level = Logger::INFO
18
- log_message('Logging enabled for helper.')
7
+ class NxLogger
8
+ include Singleton
9
+ LOG_PATH = "./logs/rapid7_%s.log"
10
+ KEY_FORMAT = "external.integration.%s"
11
+ PRODUCT_FORMAT = "%s_%s"
12
+
13
+ DEFAULT_LOG = 'integration'
14
+ PRODUCT_RANGE = 4..30
15
+ KEY_RANGE = 3..15
16
+
17
+ ENDPOINT = '/data/external/statistic/'
18
+
19
+ def initialize()
20
+ create_calls
21
+ @logger_file = get_log_path @product
22
+ setup_logging(true, 'info')
23
+ end
24
+
25
+ def setup_statistics_collection(vendor, product_name, gem_version)
26
+ begin
27
+ @statistic_key = get_statistic_key vendor
28
+ @product = get_product product_name, gem_version
29
+ rescue => e
30
+ #Continue
31
+ end
32
+ end
33
+
34
+ def setup_logging(enabled, log_level = 'info', stdout=false)
35
+ @stdout = stdout
36
+
37
+ log_message('Logging disabled.') unless enabled || @log.nil?
38
+ @enabled = enabled
39
+ return unless @enabled
40
+
41
+ @logger_file = get_log_path @product
42
+
43
+ require 'logger'
44
+ directory = File.dirname(@logger_file)
45
+ FileUtils.mkdir_p(directory) unless File.directory?(directory)
46
+ io = IO.for_fd(IO.sysopen(@logger_file, 'a'), 'a')
47
+ io.autoclose = false
48
+ io.sync = true
49
+ @log = Logger.new(io, 'weekly')
50
+ @log.level = if log_level.to_s.casecmp('info') == 0
51
+ Logger::INFO
52
+ else
53
+ Logger::DEBUG
54
+ end
55
+ log_message("Logging enabled at level <#{log_level}>")
56
+ end
57
+
58
+ def create_calls
59
+ levels = [:info, :debug, :error, :warn]
60
+ levels.each do |level|
61
+ method_name =
62
+ define_singleton_method("log_#{level.to_s}_message") do |message|
63
+ puts message if @stdout
64
+ @log.send(level, message) unless !@enabled || @log.nil?
65
+ end
19
66
  end
20
67
  end
21
68
 
22
- # Logs a message
23
69
  def log_message(message)
24
- @log.info(message)
70
+ log_info_message message
71
+ end
72
+
73
+ def log_stat_message(message)
74
+ end
75
+
76
+ def get_log_path(product)
77
+ product.downcase! unless product.nil?
78
+ File.join(File.dirname(__FILE__), LOG_PATH % (product || DEFAULT_LOG))
79
+ end
80
+
81
+ def get_statistic_key(vendor)
82
+ if vendor.nil? || vendor.length < KEY_RANGE.min
83
+ log_stat_message("Vendor length is below minimum of <#{KEY_RANGE}>")
84
+ return nil
85
+ end
86
+
87
+ vendor.gsub!('-', '_')
88
+ vendor.slice! vendor.rindex('_') until vendor.count('_') <= 1
89
+
90
+ vendor.delete! "^A-Za-z0-9\_"
91
+
92
+ KEY_FORMAT % vendor[0...KEY_RANGE.max].downcase
93
+ end
94
+
95
+ def get_product(product, version)
96
+ return nil if ((product.nil? || product.empty?) ||
97
+ (version.nil? || version.empty?))
98
+
99
+ product.gsub!('-', '_')
100
+ product.slice! product.rindex('_') until product.count('_') <= 1
101
+
102
+ product.delete! "^A-Za-z0-9\_"
103
+ version.delete! "^A-Za-z0-9\.\-"
104
+
105
+ product = (PRODUCT_FORMAT % [product, version])[0...PRODUCT_RANGE.max]
106
+
107
+ product.slice! product.rindex(/[A-Z0-9]/i)+1..-1
108
+
109
+ if product.length < PRODUCT_RANGE.min
110
+ log_stat_message("Product length below minimum <#{PRODUCT_RANGE.min}>.")
111
+ return nil
112
+ end
113
+ product.downcase
114
+ end
115
+
116
+ def generate_payload(statistic_value='')
117
+ product_name, separator, version = @product.to_s.rpartition('_')
118
+ payload_value = {'version' => version}.to_json
119
+
120
+ payload = {'statistic-key' => @statistic_key.to_s,
121
+ 'statistic-value' => payload_value,
122
+ 'product' => product_name}
123
+ JSON.generate(payload)
25
124
  end
125
+
126
+ def send(nexpose_address, nexpose_port, session_id, payload)
127
+ header = {'Content-Type' => 'application/json',
128
+ 'nexposeCCSessionID' => session_id,
129
+ 'Cookie' => "nexposeCCSessionID=#{session_id}"}
130
+ req = Net::HTTP::Put.new(ENDPOINT, header)
131
+ req.body = payload
132
+ http_instance = Net::HTTP.new(nexpose_address, nexpose_port)
133
+ http_instance.use_ssl = true
134
+ http_instance.verify_mode = OpenSSL::SSL::VERIFY_NONE
135
+ response = http_instance.start { |http| http.request(req) }
136
+ log_stat_message "Received code #{response.code} from Nexpose console."
137
+ log_stat_message "Received message #{response.msg} from Nexpose console."
138
+ log_stat_message 'Finished sending statistics data to Nexpose.'
139
+
140
+ response.code
141
+ end
142
+
143
+ def on_connect(nexpose_address, nexpose_port, session_id, value)
144
+ log_stat_message 'Sending statistics data to Nexpose'
145
+
146
+ if @product.nil? || @statistic_key.nil?
147
+ log_stat_message('Invalid product name and/or statistics key.')
148
+ log_stat_message('Statistics collection not enabled.')
149
+ return
150
+ end
151
+
152
+ begin
153
+ payload = generate_payload value
154
+ send(nexpose_address, nexpose_port, session_id, payload)
155
+ rescue => e
156
+ #Let the program continue
157
+ end
158
+ end
159
+
160
+ #Used by net library for debugging
161
+ def <<(value)
162
+ log_debug_message(value)
163
+ end
164
+
26
165
  end
27
- end
166
+ end
@@ -1,3 +1,5 @@
1
1
  module Paloalto
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
+ VENDOR = "Palo Alto"
4
+ PRODUCT = "NGFW"
3
5
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexpose_paloalto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Damian Finol
8
8
  - JJ Cassidy
9
9
  autorequire:
10
- bindir: exe
10
+ bindir: bin
11
11
  cert_chain: []
12
- date: 2015-04-01 00:00:00.000000000 Z
12
+ date: 2017-05-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -45,14 +45,14 @@ dependencies:
45
45
  requirements:
46
46
  - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: '0.9'
48
+ version: '3.2'
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
- version: '0.9'
55
+ version: '3.2'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: curb
58
58
  requirement: !ruby/object:Gem::Requirement
@@ -84,8 +84,9 @@ dependencies:
84
84
  description: This Gem allows usage of Nexpose Dynamic Asset groups with Palo Alto
85
85
  TAGs.
86
86
  email:
87
- - integrations_support@rapid7.com
88
- executables: []
87
+ - support@rapid7.com
88
+ executables:
89
+ - nexpose_paloalto
89
90
  extensions: []
90
91
  extra_rdoc_files: []
91
92
  files:
@@ -94,13 +95,12 @@ files:
94
95
  - LICENSE.txt
95
96
  - README.md
96
97
  - Rakefile
97
- - lib/bin/nexpose_paloalto.rb
98
+ - bin/nexpose_paloalto
98
99
  - lib/paloalto.rb
99
100
  - lib/paloalto/nexpose_helper.rb
100
101
  - lib/paloalto/ngfw.rb
101
102
  - lib/paloalto/nx_logger.rb
102
103
  - lib/paloalto/version.rb
103
- - nexpose_paloalto.gemspec
104
104
  homepage: http://www.rapid7.com
105
105
  licenses:
106
106
  - MIT
@@ -121,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
121
  version: '0'
122
122
  requirements: []
123
123
  rubyforge_project:
124
- rubygems_version: 2.4.4
124
+ rubygems_version: 2.5.1
125
125
  signing_key:
126
126
  specification_version: 4
127
127
  summary: Nexpose Palo Alto Gem Integration
@@ -1,28 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'paloalto/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "nexpose_paloalto"
8
- spec.version = Paloalto::VERSION
9
- spec.authors = ['Damian Finol', 'JJ Cassidy']
10
- spec.email = ['integrations_support@rapid7.com']
11
-
12
- spec.summary = 'Nexpose Palo Alto Gem Integration'
13
- spec.description = 'This Gem allows usage of Nexpose Dynamic Asset groups with Palo Alto TAGs.'
14
- spec.homepage = "http://www.rapid7.com"
15
- spec.license = "MIT"
16
-
17
- spec.files = Dir['[A-Z]*'] + Dir['lib/**/*'] + Dir['bin/**']
18
- spec.bindir = "exe"
19
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
- spec.require_paths = ["lib"]
21
-
22
- spec.add_development_dependency "bundler", "~> 1.8"
23
- spec.add_development_dependency "rake", "~> 10.0"
24
- spec.add_runtime_dependency 'nexpose', "~> 0.9"
25
- spec.add_runtime_dependency 'curb', "~> 0.8.7"
26
- spec.add_runtime_dependency 'nokogiri', "~> 1.6"
27
- spec.required_ruby_version = '~> 2.0'
28
- end