nexpose_paloalto 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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