nexpose 0.6.5 → 0.7.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.
@@ -134,6 +134,19 @@ module Nexpose
134
134
  # Valid Operators: CONTAINS, NOT_CONTAINS
135
135
  SOFTWARE = 'SOFTWARE'
136
136
 
137
+ # Valid Operators: IS, IS_NOT, GREATER_THAN, LESS_THAN, IS_APPLIED, IS_NOT_APPLIED
138
+ # Valid Values: VERY_HIGH, HIGH, NORMAL, LOW, VERY_LOW
139
+ USER_ADDED_CRITICALITY_LEVEL = 'TAG_CRITICALITY'
140
+
141
+ # Valid Operators: IS, IS_NOT, STARTS_WITH, ENDS_WITH, IS_APPLIED, IS_NOT_APPLIED, CONTAINS, NOT_CONTAINS
142
+ USER_ADDED_CUSTOM_TAG = 'TAG'
143
+
144
+ # Valid Operators: IS, IS_NOT, STARTS_WITH, ENDS_WITH, IS_APPLIED, IS_NOT_APPLIED, CONTAINS, NOT_CONTAINS
145
+ USER_ADDED_TAG_LOCATION = 'TAG_LOCATION'
146
+
147
+ # Valid Operators: IS, IS_NOT, STARTS_WITH, ENDS_WITH, IS_APPLIED, IS_NOT_APPLIED, CONTAINS, NOT_CONTAINS
148
+ USER_ADDED_TAG_OWNER = 'TAG_OWNER'
149
+
137
150
  # Valid Operators: ARE
138
151
  # Valid Values: PRESENT, NOT_PRESENT
139
152
  VALIDATED_VULNERABILITIES = 'VULNERABILITY_VALIDATED_STATUS'
@@ -171,6 +184,8 @@ module Nexpose
171
184
  IS_NOT_EMPTY = 'IS_NOT_EMPTY'
172
185
  INCLUDE = 'INCLUDE'
173
186
  DO_NOT_INCLUDE = 'DO_NOT_INCLUDE'
187
+ IS_APPLIED = 'IS_APPLIED'
188
+ IS_NOT_APPLIED = 'IS_NOT_APPLIED'
174
189
  end
175
190
 
176
191
  # Specialized values used by certain search fields
@@ -263,7 +278,7 @@ module Nexpose
263
278
  def to_map
264
279
  { 'metadata' => { 'fieldName' => field },
265
280
  'operator' => operator,
266
- 'values' => value.kind_of?(Array) ? value : [value] }
281
+ 'values' => Array(value) }
267
282
  end
268
283
 
269
284
  def self.parse(json)
@@ -283,11 +298,7 @@ module Nexpose
283
298
  attr_accessor :criteria
284
299
 
285
300
  def initialize(criteria = [], match = 'AND')
286
- if criteria.kind_of?(Array)
287
- @criteria = criteria
288
- else
289
- @criteria = [criteria]
290
- end
301
+ @criteria = Array(criteria)
291
302
  @match = match.upcase
292
303
  end
293
304
 
data/lib/nexpose/group.rb CHANGED
@@ -28,9 +28,10 @@ module Nexpose
28
28
  if r.success
29
29
  r.res.elements.each('AssetGroupListingResponse/AssetGroupSummary') do |group|
30
30
  groups << AssetGroupSummary.new(group.attributes['id'].to_i,
31
- group.attributes['name'],
32
- group.attributes['description'],
33
- group.attributes['riskscore'].to_f)
31
+ group.attributes['name'],
32
+ group.attributes['description'],
33
+ group.attributes['riskscore'].to_f,
34
+ group.attributes['dynamic'].to_i == 1)
34
35
  end
35
36
  end
36
37
  groups
@@ -43,10 +44,14 @@ module Nexpose
43
44
  # Summary value object for asset group information.
44
45
  #
45
46
  class AssetGroupSummary
46
- attr_reader :id, :name, :description, :risk_score
47
+ attr_reader :id, :name, :description, :risk_score, :dynamic
47
48
 
48
- def initialize(id, name, desc, risk)
49
- @id, @name, @description, @risk_score = id, name, desc, risk
49
+ def initialize(id, name, desc, risk, dynamic)
50
+ @id, @name, @description, @risk_score, @dyanmic = id, name, desc, risk, dynamic
51
+ end
52
+
53
+ def dynamic?
54
+ dynamic
50
55
  end
51
56
 
52
57
  # Delete this asset group and all associated data.
@@ -63,7 +68,7 @@ module Nexpose
63
68
  class AssetGroup < AssetGroupSummary
64
69
  include Sanitize
65
70
 
66
- attr_accessor :name, :description, :id
71
+ attr_accessor :name, :description, :id , :tags
67
72
 
68
73
  # Array[Device] of devices associated with this asset group.
69
74
  attr_accessor :assets
@@ -73,6 +78,7 @@ module Nexpose
73
78
  def initialize(name, desc, id = -1, risk = 0.0)
74
79
  @name, @description, @id, @risk_score = name, desc, id, risk
75
80
  @assets = []
81
+ @tags = []
76
82
  end
77
83
 
78
84
  def save(connection)
@@ -98,6 +104,11 @@ module Nexpose
98
104
  xml << %(<device id="#{asset.id}"/>)
99
105
  end
100
106
  xml << '</Devices>'
107
+ xml << '<Tags>'
108
+ @tags.each do |tag|
109
+ xml << tag.as_xml.to_s
110
+ end
111
+ xml << '</Tags>'
101
112
  xml << '</AssetGroup>'
102
113
  end
103
114
 
@@ -133,7 +144,6 @@ module Nexpose
133
144
 
134
145
  def self.parse(xml)
135
146
  return nil unless xml
136
-
137
147
  group = REXML::XPath.first(xml, 'AssetGroupConfigResponse/AssetGroup')
138
148
  asset_group = new(group.attributes['name'],
139
149
  group.attributes['description'],
@@ -146,6 +156,9 @@ module Nexpose
146
156
  dev.attributes['riskfactor'].to_f,
147
157
  dev.attributes['riskscore'].to_f)
148
158
  end
159
+ group.elements.each('Tags/Tag') do |tag|
160
+ asset_group.tags << TagSummary.parse_xml(tag)
161
+ end
149
162
  asset_group
150
163
  end
151
164
  end
@@ -0,0 +1,219 @@
1
+ module Nexpose
2
+
3
+ class Connection
4
+ include XMLUtils
5
+
6
+ # Retrieve a list of all users the user is authorized to view or manage.
7
+ #
8
+ # @return [Array[MultiTenantUserSummary]] Array of MultiTenantUserSummary objects.
9
+ #
10
+ def list_silo_users
11
+ r = execute(make_xml('MultiTenantUserListingRequest'), '1.2')
12
+ arr = []
13
+ if r.success
14
+ r.res.elements.each('MultiTenantUserListingResponse/MultiTenantUserSummaries/MultiTenantUserSummary') do |user|
15
+ arr << MultiTenantUserSummary.parse(user)
16
+ end
17
+ end
18
+ arr
19
+ end
20
+
21
+ # Delete the specified silo user
22
+ #
23
+ # @return Whether or not the delete request succeeded.
24
+ #
25
+ def delete_silo_user(user_id)
26
+ r = execute(make_xml('MultiTenantUserDeleteRequest', {'user-id' => user_id}), '1.2')
27
+ r.success
28
+ end
29
+ end
30
+
31
+ class MultiTenantUserSummary
32
+ attr_reader :id
33
+ attr_reader :full_name
34
+ attr_reader :user_name
35
+ attr_reader :email
36
+ attr_reader :superuser
37
+ attr_reader :enabled
38
+ attr_reader :auth_module
39
+ attr_reader :auth_source
40
+ attr_reader :silo_count
41
+ attr_reader :locked
42
+
43
+ def initialize(&block)
44
+ instance_eval &block if block_given?
45
+ end
46
+
47
+ def self.parse(xml)
48
+ new do
49
+ @id = xml.attributes['id'].to_i
50
+ @full_name = xml.attributes['full-name']
51
+ @user_name = xml.attributes['user-name']
52
+ @email = xml.attributes['email']
53
+ @superuser = xml.attributes['superuser'].to_s.chomp.eql?('true')
54
+ @enabled = xml.attributes['enabled'].to_s.chomp.eql?('true')
55
+ @auth_module = xml.attributes['auth-module']
56
+ @auth_source = xml.attributes['auth-source']
57
+ @silo_count = xml.attributes['silo-count'].to_i
58
+ @locked = xml.attributes['locked'].to_s.chomp.eql?('true')
59
+ end
60
+ end
61
+ end
62
+
63
+ class MultiTenantUser
64
+ attr_accessor :id
65
+ attr_accessor :full_name
66
+ attr_accessor :user_name
67
+ attr_accessor :auth_source_id
68
+ attr_accessor :email
69
+ attr_accessor :password
70
+ attr_accessor :superuser
71
+ attr_accessor :enabled
72
+ attr_accessor :silo_access
73
+
74
+ def initialize(&block)
75
+ instance_eval &block if block_given?
76
+
77
+ @silo_access = Array(@silo_access)
78
+ end
79
+
80
+ def save(connection)
81
+ if (@id)
82
+ update(connection)
83
+ else
84
+ create(connection)
85
+ end
86
+ end
87
+
88
+ # Updates this silo user on a Nexpose console.
89
+ #
90
+ # @param [Connection] connection Connection to console where this silo user will be saved.
91
+ # @return [String] User ID assigned to this configuration, if successful.
92
+ #
93
+ def update(connection)
94
+ xml = connection.make_xml('MultiTenantUserUpdateRequest')
95
+ xml.add_element(as_xml)
96
+ r = connection.execute(xml, '1.2')
97
+ @id = r.attributes['user-id'] if r.success
98
+ end
99
+
100
+ # Saves this silo user to a Nexpose console.
101
+ #
102
+ # @param [Connection] connection Connection to console where this silo user will be saved.
103
+ # @return [String] User ID assigned to this configuration, if successful.
104
+ #
105
+ def create(connection)
106
+ xml = connection.make_xml('MultiTenantUserCreateRequest')
107
+ xml.add_element(as_xml)
108
+ r = connection.execute(xml, '1.2')
109
+ @id = r.attributes['user-id'] if r.success
110
+ end
111
+
112
+ def as_xml
113
+ xml = REXML::Element.new('MultiTenantUserConfig')
114
+ xml.add_attributes({'id' => @id,
115
+ 'full-name' => @full_name,
116
+ 'user-name' => @user_name,
117
+ 'authsrcid' => @auth_source_id,
118
+ 'email' => @email,
119
+ 'password' => @password,
120
+ 'superuser' => @superuser,
121
+ 'enabled' => @enabled})
122
+ siloaccesses = xml.add_element('SiloAccesses')
123
+ @silo_access.each { |silo_access| siloaccesses.add_element(silo_access.as_xml) }
124
+ xml
125
+ end
126
+
127
+ def delete(connection)
128
+ connection.delete_silo_user(@id)
129
+ end
130
+
131
+ def to_xml
132
+ as_xml.to_s
133
+ end
134
+
135
+ def self.parse(xml)
136
+ new do |user|
137
+ user.id = xml.attributes['id'].to_i
138
+ user.full_name = xml.attributes['full-name']
139
+ user.user_name = xml.attributes['user-name']
140
+ user.email = xml.attributes['email']
141
+ user.superuser = xml.attributes['superuser'].to_s.chomp.eql?('true')
142
+ user.enabled = xml.attributes['enabled'].to_s.chomp.eql?('true')
143
+ user.auth_source_id = xml.attributes['authsrcid'].to_i
144
+ user.silo_access = []
145
+ xml.elements.each('SiloAccesses/SiloAccess') { |access| user.silo_access << SiloAccess.parse(access) }
146
+ end
147
+ end
148
+
149
+ def self.load(connection, user_id)
150
+ r = connection.execute(connection.make_xml('MultiTenantUserConfigRequest', {'user-id' => user_id}), '1.2')
151
+
152
+ if r.success
153
+ r.res.elements.each('MultiTenantUserConfigResponse/MultiTenantUserConfig') do |config|
154
+ return MultiTenantUser.parse(config)
155
+ end
156
+ end
157
+ nil
158
+ end
159
+ end
160
+
161
+ class SiloAccess
162
+ attr_accessor :all_groups
163
+ attr_accessor :all_sites
164
+ attr_accessor :role_name
165
+ attr_accessor :silo_id
166
+ attr_accessor :default
167
+ attr_accessor :sites
168
+ attr_accessor :groups
169
+
170
+ def initialize(&block)
171
+ instance_eval &block if block_given?
172
+ @sites = Array(@sites)
173
+ @groups = Array(@groups)
174
+ end
175
+
176
+ def as_xml
177
+ xml = REXML::Element.new('SiloAccess')
178
+ xml.add_attributes({'all-groups' => @all_groups,
179
+ 'all-sites' => @all_sites,
180
+ 'role-name' => @role_name,
181
+ 'silo-id' => @silo_id,
182
+ 'default-silo' => @default})
183
+
184
+ unless @groups.empty?
185
+ groups = xml.add_element('AllowedGroups')
186
+ @groups.each do |group|
187
+ groups.add_element('AllowedGroup', {'id' => group})
188
+ end
189
+ end
190
+
191
+ unless @sites.empty?
192
+ sites = xml.add_element('AllowedSites')
193
+ @sites.each do |site|
194
+ sites.add_element('AllowedSite', {'id' => site})
195
+ end
196
+ end
197
+
198
+ xml
199
+ end
200
+
201
+ def to_xml
202
+ as_xml.to_s
203
+ end
204
+
205
+ def self.parse(xml)
206
+ new do |access|
207
+ access.all_groups = xml.attributes['all-groups'].to_s.chomp.eql?('true')
208
+ access.all_sites = xml.attributes['all-sites'].to_s.chomp.eql?('true')
209
+ access.role_name = xml.attributes['role-name']
210
+ access.silo_id = xml.attributes['silo-id']
211
+ access.default = xml.attributes['default-silo'].to_s.chomp.eql?('true')
212
+ access.sites = []
213
+ xml.elements.each('AllowedSites/AllowedSite') { |site| access.sites << site.attributes['id'].to_i }
214
+ access.groups = []
215
+ xml.elements.each('AllowedGroups/AllowedGroup') { |group| access.groups << group.attributes['id'].to_i }
216
+ end
217
+ end
218
+ end
219
+ end
@@ -27,7 +27,7 @@ module Nexpose
27
27
  # @param [String] template_id Unique identifier of the report template to remove.
28
28
  #
29
29
  def delete_report_template(template_id)
30
- AJAX.delete(self, "/data/report/templates/#{template_id}")
30
+ AJAX.delete(self, "/data/report/templates/#{URI.escape(template_id)}")
31
31
  end
32
32
  end
33
33
 
data/lib/nexpose/scan.rb CHANGED
@@ -208,6 +208,17 @@ module Nexpose
208
208
  false
209
209
  end
210
210
  end
211
+
212
+ # Delete a scan and all its data from a console.
213
+ # Warning, this method is destructive and not guaranteed to leave a site
214
+ # in a valid state. DBCC may need to be run to correct missing or empty
215
+ # assets.
216
+ #
217
+ # @param [Fixnum] scan_id Scan ID to remove data for.
218
+ #
219
+ def delete_scan(scan_id)
220
+ AJAX.delete(self, "/data/scan/#{scan_id}")
221
+ end
211
222
  end
212
223
 
213
224
  # Object that represents a summary of a scan.
data/lib/nexpose/silo.rb CHANGED
@@ -3,347 +3,351 @@ module Nexpose
3
3
  class Connection
4
4
  include XMLUtils
5
5
 
6
- ###################
7
- # SILO MANAGEMENT #
8
- ###################
9
-
10
- #########################
11
- # MULTI-TENANT USER OPS #
12
- #########################
13
-
14
- #-------------------------------------------------------------------------
15
- # Creates a multi-tenant user
6
+ # Retrieve a list of all silos the user is authorized to view or manage.
16
7
  #
17
- # user_config - A map of the user data.
8
+ # @return [Array[SiloSummary]] Array of SiloSummary objects.
18
9
  #
19
- # REQUIRED PARAMS
20
- # user-id, authsrcid, user-name, full-name, enabled, superuser
10
+ def list_silos
11
+ r = execute(make_xml('SiloListingRequest'), '1.2')
12
+ arr = []
13
+ if r.success
14
+ r.res.elements.each('SiloListingResponse/SiloSummaries/SiloSummary') do |silo|
15
+ arr << SiloSummary.parse(silo)
16
+ end
17
+ end
18
+ arr
19
+ end
20
+
21
+ alias_method :silos, :list_silos
22
+
23
+ # Delete the specified silo
21
24
  #
22
- # OPTIONAL PARAMS
23
- # email, password
25
+ # @return Whether or not the delete request succeeded.
24
26
  #
25
- # silo_configs - An array of maps of silo specific data
27
+ def delete_silo(silo_id)
28
+ r = execute(make_xml('SiloDeleteRequest', {'silo-id' => silo_id}), '1.2')
29
+ r.success
30
+ end
31
+ end
32
+
33
+ class Silo
34
+ # Required fields
35
+ attr_accessor :id
36
+ attr_accessor :profile_id
37
+ attr_accessor :name
38
+ attr_accessor :max_assets
39
+ attr_accessor :max_users
40
+ attr_accessor :max_hosted_assets
41
+
42
+ #Optional fields
43
+ attr_accessor :description
44
+ attr_accessor :merchant
45
+ attr_accessor :organization
46
+
47
+ def initialize(&block)
48
+ instance_eval &block if block_given?
49
+ end
50
+
51
+ # Copy an existing configuration from a Nexpose instance.
52
+ # Returned object will reset the silo ID and name
26
53
  #
27
- # REQUIRED PARAMS
28
- # silo-id, role-name, all-groups, all-sites, default-silo
54
+ # @param [Connection] connection Connection to the security console.
55
+ # @param [String] id Silo ID of an existing silo.
56
+ # @return [Silo] Silo configuration loaded from a Nexpose console.
29
57
  #
30
- # allowed_groups/allowed_sites - An array of ids
31
- #-------------------------------------------------------------------------
32
- def create_multi_tenant_user(user_config, silo_configs)
33
- xml = make_xml('MultiTenantUserCreateRequest')
34
- mtu_config_xml = make_xml('MultiTenantUserConfig', user_config, '', false)
35
-
36
- # Add the silo access
37
- silo_xml = make_xml('SiloAccesses', {}, '', false)
38
- silo_configs.each do |silo_config|
39
- silo_config_xml = make_xml('SiloAccess', {}, '', false)
40
- silo_config.keys.each do |k|
41
- if k == 'allowed_sites'
42
- allowed_sites_xml = make_xml('AllowedSites', {}, '', false)
43
- silo_config['allowed_sites'].each do |allowed_site|
44
- allowed_sites_xml.add_element(make_xml('AllowedSite', {'id' => allowed_site}, '', false))
45
- end
46
- silo_config_xml.add_element(allowed_sites_xml)
47
- elsif k == 'allowed_groups'
48
- allowed_groups_xml = make_xml('AllowedGroups', {}, '', false)
49
- silo_config['allowed_groups'].each do |allowed_group|
50
- allowed_groups_xml.add_element(make_xml('AllowedGroup', {'id' => allowed_group}, '', false))
51
- end
52
- silo_config_xml.add_element(allowed_groups_xml)
53
- else
54
- silo_config_xml.attributes[k] = silo_config[k]
55
- end
56
- end
57
- silo_xml.add_element(silo_config_xml)
58
- end
59
- mtu_config_xml.add_element(silo_xml)
60
- xml.add_element(mtu_config_xml)
61
- r = execute(xml, '1.2')
62
- r.success
58
+ def self.copy(connection, id)
59
+ silo = load(connection, id)
60
+ silo.id = nil
61
+ silo.name = nil
62
+ silo
63
63
  end
64
64
 
65
- #-------------------------------------------------------------------------
66
- # Lists all the multi-tenant users and their attributes.
67
- #-------------------------------------------------------------------------
68
- def list_mtu
69
- xml = make_xml('MultiTenantUserListingRequest')
70
- r = execute xml, '1.2'
65
+ # Load an existing configuration from a Nexpose instance.
66
+ #
67
+ # @param [Connection] connection Connection to console where site exists.
68
+ # @param [String] id Silo ID of an existing silo.
69
+ # @return [Silo] Silo configuration loaded from a Nexpose console.
70
+ #
71
+ def self.load(connection, id)
72
+ r = connection.execute(connection.make_xml('SiloConfigRequest', {'silo-id' => id}), '1.2')
71
73
 
72
74
  if r.success
73
- res = []
74
- r.res.elements.each("//MultiTenantUserSummary") do |mtu|
75
- res << {
76
- :id => mtu.attributes['id'],
77
- :full_name => mtu.attributes['full-name'],
78
- :user_name => mtu.attributes['user-name'],
79
- :email => mtu.attributes['email'],
80
- :super_user => mtu.attributes['superuser'],
81
- :enabled => mtu.attributes['enabled'],
82
- :auth_module => mtu.attributes['auth-module'],
83
- :silo_count => mtu.attributes['silo-count'],
84
- :locked => mtu.attributes['locked']
85
- }
75
+ r.res.elements.each('SiloConfigResponse/SiloConfig') do |config|
76
+ return Silo.parse(config)
86
77
  end
87
- res
88
- else
89
- false
90
78
  end
79
+ nil
91
80
  end
92
81
 
93
- #-------------------------------------------------------------------------
94
- # Delete a multi-tenant user
95
- #-------------------------------------------------------------------------
96
- def delete_mtu user_name, user_id
97
- using_user_name = (user_name and not user_name.empty?)
98
- xml = make_xml('MultiTenantUserDeleteRequest', (using_user_name ? {'user-name' => user_name} : {'user-id' => user_id}))
99
- r = execute xml, '1.2'
100
- r.success
82
+ def save(connection)
83
+ begin
84
+ update(connection)
85
+ rescue APIError => error
86
+ raise error unless (error.message =~ /A silo .* does not exist./)
87
+ create(connection)
88
+ end
101
89
  end
102
90
 
103
- ####################
104
- # SILO PROFILE OPS #
105
- ####################
106
-
107
- #-------------------------------------------------------------------------
108
- # Creates a silo profile
91
+ # Updates this silo on a Nexpose console.
109
92
  #
110
- # silo_config - A map of the silo data.
93
+ # @param [Connection] connection Connection to console where this silo will be saved.
94
+ # @return [String] Silo ID assigned to this configuration, if successful.
111
95
  #
112
- # REQUIRED PARAMS
113
- # id, name, all‐licensed-modules, all‐global-engines, all-global-report-templates, all‐global-scan‐templates
114
- #
115
- # OPTIONAL PARAMS
116
- # description
117
- #
118
- # permissions - A map of an array of maps of silo specific data
96
+ def update(connection)
97
+ xml = connection.make_xml('SiloUpdateRequest')
98
+ xml.add_element(as_xml)
99
+ r = connection.execute(xml, '1.2')
100
+ @id = r.attributes['id'] if r.success
101
+ end
102
+
103
+ # Saves a new silo to a Nexpose console.
119
104
  #
120
- # REQUIRED PARAMS
121
- # silo-id, role-name, all-groups, all-sites, default-silo
105
+ # @param [Connection] connection Connection to console where this silo will be saved.
106
+ # @return [String] Silo ID assigned to this configuration, if successful.
122
107
  #
123
- # allowed_groups/allowed_sites - An array of ids
124
- #-------------------------------------------------------------------------
125
- def create_silo_profile silo_profile_config, permissions
126
- xml = make_xml 'SiloProfileCreateRequest'
127
- spc_xml = make_xml('SiloProfileConfig', silo_profile_config, '', false)
128
-
129
- # Add the permissions
130
- if permissions['global_report_templates']
131
- grt_xml = make_xml('GlobalReportTemplates', {}, '', false)
132
- permissions['global_report_templates'].each do |name|
133
- grt_xml.add_element make_xml('GlobalReportTemplate', {'name' => name}, '', false)
134
- end
135
- spc_xml.add_element grt_xml
136
- end
108
+ def create(connection)
109
+ xml = connection.make_xml('SiloCreateRequest')
110
+ xml.add_element(as_xml)
111
+ r = connection.execute(xml, '1.2')
112
+ @id = r.attributes['id'] if r.success
113
+ end
137
114
 
138
- if permissions['global_scan_engines']
139
- gse_xml = make_xml('GlobalScanEngines', {}, '', false)
140
- permissions['global_scan_engines'].each do |name|
141
- gse_xml.add_element make_xml('GlobalScanEngine', {'name' => name}, '', false)
142
- end
143
- spc_xml.add_element gse_xml
144
- end
115
+ def delete(connection)
116
+ connection.delete_silo(@id)
117
+ end
145
118
 
146
- if permissions['global_scan_templates']
147
- gst_xml = make_xml('GlobalScanTemplates', {}, '', false)
148
- permissions['global_scan_templates'].each do |name|
149
- gst_xml.add_element make_xml('GlobalScanTemplate', {'name' => name}, '', false)
150
- end
151
- spc_xml.add_element gst_xml
152
- end
119
+ def as_xml
120
+ xml = REXML::Element.new('SiloConfig')
121
+ xml.add_attributes({'description' => @description, 'name' => @name, 'id' => @id, 'silo-profile-id' => @profile_id, 'max-assets' => @max_assets, 'max-users' => @max_users, 'max-hosted-assets' => @max_hosted_assets})
122
+ xml.add(@merchant.as_xml) if @merchant
123
+ xml.add(@organization.as_xml) if @organization
124
+ xml
125
+ end
153
126
 
154
- if permissions['licensed_modules']
155
- lm_xml = make_xml('LicensedModules', {}, '', false)
156
- permissions['licensed_modules'].each do |name|
157
- lm_xml.add_element make_xml('LicensedModule', {'name' => name}, '', false)
158
- end
159
- spc_xml.add_element lm_xml
160
- end
127
+ def to_xml
128
+ as_xml.to_s
129
+ end
161
130
 
162
- if permissions['restricted_report_formats']
163
- rrf_xml = make_xml('RestrictedReportFormats', {}, '', false)
164
- permissions['restricted_report_formats'].each do |name|
165
- rrf_xml.add_element make_xml('RestrictedReportFormat', {'name' => name}, '', false)
131
+ def self.parse(xml)
132
+ new do |silo|
133
+ silo.id = xml.attributes['id']
134
+ silo.profile_id = xml.attributes['silo-profile-id']
135
+ silo.name = xml.attributes['name']
136
+ silo.max_assets = xml.attributes['max-assets'].to_i
137
+ silo.max_users = xml.attributes['max-users'].to_i
138
+ silo.max_hosted_assets = xml.attributes['max-hosted-assets'].to_i
139
+ silo.description = xml.attributes['description']
140
+
141
+ xml.elements.each('Merchant') do |merchant|
142
+ silo.merchant = Merchant.parse(merchant)
166
143
  end
167
- spc_xml.add_element rrf_xml
168
- end
169
144
 
170
- if permissions['restricted_report_sections']
171
- rrs_xml = make_xml('RestrictedReportSections', {}, '', false)
172
- permissions['restricted_report_sections'].each do |name|
173
- rrs_xml.add_element make_xml('RestrictedReportSection', {'name' => name}, '', false)
145
+ xml.elements.each('Organization') do |organization|
146
+ silo.organization = Organization.parse(organization)
174
147
  end
175
- spc_xml.add_element rrs_xml
176
148
  end
177
-
178
- xml.add_element spc_xml
179
- r = execute xml, '1.2'
180
- r.success
181
149
  end
182
150
 
183
- #-------------------------------------------------------------------------
184
- # Lists all the silo profiles and their attributes.
185
- #-------------------------------------------------------------------------
186
- def list_silo_profiles
187
- xml = make_xml('SiloProfileListingRequest')
188
- r = execute xml, '1.2'
151
+ class Address
152
+ attr_accessor :line1
153
+ attr_accessor :line2
154
+ attr_accessor :city
155
+ attr_accessor :state
156
+ attr_accessor :zip
157
+ attr_accessor :country
189
158
 
190
- if r.success
191
- res = []
192
- r.res.elements.each("//SiloProfileSummary") do |silo_profile|
193
- res << {
194
- :id => silo_profile.attributes['id'],
195
- :name => silo_profile.attributes['name'],
196
- :description => silo_profile.attributes['description'],
197
- :global_report_template_count => silo_profile.attributes['global-report-template-count'],
198
- :global_scan_engine_count => silo_profile.attributes['global-scan-engine-count'],
199
- :global_scan_template_count => silo_profile.attributes['global-scan-template-count'],
200
- :licensed_module_count => silo_profile.attributes['licensed-module-count'],
201
- :restricted_report_section_count => silo_profile.attributes['restricted-report-section-count'],
202
- :all_licensed_modules => silo_profile.attributes['all-licensed-modules'],
203
- :all_global_engines => silo_profile.attributes['all-global-engines'],
204
- :all_global_report_templates => silo_profile.attributes['all-global-report-templates'],
205
- :all_global_scan_templates => silo_profile.attributes['all-global-scan-templates']
206
- }
159
+
160
+ def initialize(&block)
161
+ instance_eval &block if block_given?
162
+ end
163
+
164
+ def self.parse(xml)
165
+ new do |address|
166
+ address.line1 = xml.attributes['line1']
167
+ address.line2 = xml.attributes['line2']
168
+ address.city = xml.attributes['city']
169
+ address.state = xml.attributes['state']
170
+ address.zip = xml.attributes['zip']
171
+ address.country = xml.attributes['country']
207
172
  end
208
- res
209
- else
210
- false
211
173
  end
212
- end
213
174
 
214
- #-------------------------------------------------------------------------
215
- # Delete a silo profile
216
- #-------------------------------------------------------------------------
217
- def delete_silo_profile name, id
218
- using_name = (name and not name.empty?)
219
- xml = make_xml('SiloProfileDeleteRequest', (using_name ? {'name' => name} : {'silo-profile-id' => id}))
220
- r = execute xml, '1.2'
221
- r.success
175
+ def as_xml
176
+ xml = REXML::Element.new('Address')
177
+ xml.add_attributes({'city' => @city, 'country' => @country, 'line1' => @line1, 'line2' => @line2, 'state' => @state, 'zip' => @zip})
178
+ xml
179
+ end
222
180
  end
223
181
 
224
- ####################
225
- # SILO OPS #
226
- ####################
182
+ class Organization
183
+ attr_accessor :company
184
+ attr_accessor :first_name
185
+ attr_accessor :last_name
186
+ attr_accessor :phone
187
+ attr_accessor :address
188
+ attr_accessor :email
189
+ attr_accessor :title
190
+ attr_accessor :url
191
+
192
+ def initialize(&block)
193
+ instance_eval &block if block_given?
194
+ end
227
195
 
228
- #-------------------------------------------------------------------------
229
- # Creates a silo
230
- #
231
- # silo_config - A map of the silo creation data.
232
- #
233
- # REQUIRED PARAMS
234
- # id, name, silo-profile-id, max-assets, max-hosted-assets, max-users
235
- #
236
- # OPTIONAL PARAMS
237
- # description
238
- #-------------------------------------------------------------------------
239
- def create_silo silo_config
240
- xml = make_xml 'SiloCreateRequest'
241
- silo_config_xml = make_xml 'SiloConfig', {}, '', false
242
-
243
- # Add the attributes
244
- silo_config.keys.each do |key|
245
- if not 'merchant'.eql? key and not 'organization'.eql? key
246
- silo_config_xml.attributes[key] = silo_config[key]
247
- end
196
+ def as_xml
197
+ xml = REXML::Element.new('Organization')
198
+ xml.add_attributes({'company' => @company, 'email-address' => @email, 'first-name' => @first_name, 'last-name' => @last_name, 'phone-number' => @phone, 'title' => @title, 'url' => @url})
199
+ xml.add(@address.as_xml)
200
+ xml
248
201
  end
249
202
 
250
- # Add Organization info
251
- if silo_config['organization']
252
- org_xml = make_xml 'Organization', {}, '', false
253
- silo_config['organization'].keys.each do |key|
254
- if not 'address'.eql? key
255
- org_xml.attributes[key] = silo_config['organization'][key]
203
+ def self.parse(xml)
204
+ new do |organization|
205
+ organization.company = xml.attributes['company']
206
+ organization.first_name = xml.attributes['first-name']
207
+ organization.last_name = xml.attributes['last-name']
208
+ organization.phone = xml.attributes['phone-number']
209
+ xml.elements.each('Address') do |address|
210
+ organization.address = Address.parse(address)
256
211
  end
212
+ organization.email = xml.attributes['email']
213
+ organization.title = xml.attributes['title']
214
+ organization.url = xml.attributes['url']
257
215
  end
216
+ end
217
+ end
258
218
 
259
- address_xml = make_xml 'Address', silo_config['organization']['address'], '', false
260
- org_xml.add_element address_xml
261
- silo_config_xml.add_element org_xml
219
+ class Merchant < Organization
220
+ attr_accessor :acquirer_relationship
221
+ attr_accessor :agent_relationship
222
+ attr_accessor :ecommerce
223
+ attr_accessor :grocery
224
+ attr_accessor :mail_order
225
+ attr_accessor :payment_application
226
+ attr_accessor :payment_version
227
+ attr_accessor :petroleum
228
+ attr_accessor :retail
229
+ attr_accessor :telecommunication
230
+ attr_accessor :travel
231
+ attr_accessor :dbas
232
+ attr_accessor :industries
233
+ attr_accessor :qsa
234
+
235
+ def initialize(&block)
236
+ instance_eval &block if block_given?
237
+ @dbas = Array(@dbas)
238
+ @industries = Array(@industries)
239
+ @qsa = Array(@qsa)
262
240
  end
263
241
 
264
- # Add Merchant info
265
- if silo_config['merchant']
266
- merchant_xml = make_xml 'Merchant', {}, '', false
242
+ def self.parse(xml)
243
+ new do |merchant|
244
+ merchant.acquirer_relationship = xml.attributes['acquirer-relationship'].to_s.chomp.eql?('true')
245
+ merchant.agent_relationship = xml.attributes['agent-relationship'].to_s.chomp.eql?('true')
246
+ merchant.ecommerce = xml.attributes['ecommerce'].to_s.chomp.eql?('true')
247
+ merchant.grocery = xml.attributes['grocery'].to_s.chomp.eql?('true')
248
+ merchant.mail_order = xml.attributes['mail-order'].to_s.chomp.eql?('true')
249
+ merchant.payment_application = xml.attributes['payment-application']
250
+ merchant.payment_version = xml.attributes['payment-version']
251
+ merchant.petroleum = xml.attributes['petroleum'].to_s.chomp.eql?('true')
252
+ merchant.retail = xml.attributes['retail'].to_s.chomp.eql?('true')
253
+ merchant.telecommunication = xml.attributes['telecommunication'].to_s.chomp.eql?('true')
254
+ merchant.travel = xml.attributes['travel'].to_s.chomp.eql?('true')
255
+ merchant.company = xml.attributes['company']
256
+ merchant.first_name = xml.attributes['first-name']
257
+ merchant.last_name = xml.attributes['last-name']
258
+ merchant.phone = xml.attributes['phone-number']
259
+ merchant.email = xml.attributes['email']
260
+ merchant.title = xml.attributes['title']
261
+ merchant.url = xml.attributes['url']
262
+
263
+ xml.elements.each('Address') do |address|
264
+ merchant.address = Address.parse(address)
265
+ end
267
266
 
268
- silo_config['merchant'].keys.each do |key|
269
- if not 'dba'.eql? key and not 'other_industries'.eql? key and not 'qsa'.eql? key and not 'address'.eql? key
270
- merchant_xml.attributes[key] = silo_config['merchant'][key]
267
+ merchant.dbas = []
268
+ xml.elements.each('DBAs/DBA') do |dba|
269
+ merchant.dbas << dba.attributes['name']
271
270
  end
272
- end
273
271
 
274
- # Add the merchant address
275
- merchant_address_xml = make_xml 'Address', silo_config['merchant']['address'], '', false
276
- merchant_xml.add_element merchant_address_xml
272
+ merchant.industries = []
273
+ xml.elements.each('OtherIndustries/Industry') do |industry|
274
+ merchant.industries << industry.attributes['name']
275
+ end
277
276
 
278
- #Now add the complex data types
279
- if silo_config['merchant']['dba']
280
- dba_xml = make_xml 'DBAs', {}, '', false
281
- silo_config['merchant']['dba'].each do |name|
282
- dba_xml.add_element make_xml('DBA', {'name' => name}, '', false)
277
+ merchant.qsa = []
278
+ xml.elements.each('QSA') do |organization|
279
+ merchant.qsa << Organization.parse(organization)
283
280
  end
284
- merchant_xml.add_element dba_xml
285
281
  end
282
+ end
283
+
284
+ def as_xml
285
+ xml = super
286
+ xml.name = 'Merchant'
287
+ xml.add_attributes({'acquirer-relationship' => @acquirer_relationship, 'agent-relationship' => @agent_relationship, 'ecommerce' => @ecommerce, 'grocery' => @grocery, 'mail-order' => @mail_order})
288
+ xml.add_attributes({'payment-application' => @payment_application, 'payment-version' => @payment_version, 'petroleum' => @petroleum, 'retail' => @retail, 'telecommunication' => @telecommunication, 'travel' => @travel})
286
289
 
287
- if silo_config['merchant']['other_industries']
288
- ois_xml = make_xml 'OtherIndustries', {}, '', false
289
- silo_config['merchant']['other_industries'].each do |name|
290
- ois_xml.add_element make_xml('Industry', {'name' => name}, '', false)
290
+ unless dbas.empty?
291
+ dbas = REXML::Element.new('DBAs')
292
+ @dbas.each do |dba|
293
+ dbas.add_element('DBA', {'name' => dba})
291
294
  end
292
- merchant_xml.add_element ois_xml
293
295
  end
294
296
 
295
- if silo_config['merchant']['qsa']
296
- qsa_xml = make_xml 'QSA', {}, '', false
297
- silo_config['merchant']['qsa'].keys.each do |key|
298
- if not 'address'.eql? key
299
- qsa_xml.attributes[key] = silo_config['merchant']['qsa'][key]
300
- end
297
+ unless @industries.empty?
298
+ industries = REXML::Element.new('OtherIndustries')
299
+ @industries.each do |industry|
300
+ industries.add_element('Industry', {'name' => industry})
301
301
  end
302
+ end
302
303
 
303
- # Add the address for this QSA
304
- address_xml = make_xml 'Address', silo_config['merchant']['qsa']['address'], '', false
304
+ xml.add(@qsa.as_xml) unless @qsa.empty?
305
305
 
306
- qsa_xml.add_element address_xml
307
- merchant_xml.add_element qsa_xml
308
- end
309
- silo_config_xml.add_element merchant_xml
306
+ xml
310
307
  end
311
-
312
- xml.add_element silo_config_xml
313
- r = execute xml, '1.2'
314
- r.success
315
308
  end
309
+ end
316
310
 
317
- #-------------------------------------------------------------------------
318
- # Lists all the silos and their attributes.
319
- #-------------------------------------------------------------------------
320
- def list_silos
321
- xml = make_xml('SiloListingRequest')
322
- r = execute xml, '1.2'
311
+ # Object that represents the summary of a Nexpose Site.
312
+ #
313
+ class SiloSummary
314
+ # The silo ID.
315
+ attr_reader :id
316
+ # The silo name.
317
+ attr_reader :name
318
+ # A description of the silo.
319
+ attr_reader :description
320
+ # The ID of the silo profile being used for this silo.
321
+ attr_reader :profile_id
322
+ # The asset count for this silo
323
+ attr_reader :assets
324
+ # The asset count limit for this silo.
325
+ attr_reader :max_assets
326
+ # The hosted asset count limit for this silo.
327
+ attr_reader :max_hosted_assets
328
+ # The user count for this silo
329
+ attr_reader :users
330
+ # The user count limit for this silo.
331
+ attr_reader :max_users
332
+
333
+ def initialize(&block)
334
+ instance_eval &block if block_given?
335
+ end
323
336
 
324
- if r.success
325
- res = []
326
- r.res.elements.each("//SiloSummary") do |silo_profile|
327
- res << {
328
- :id => silo_profile.attributes['id'],
329
- :name => silo_profile.attributes['name'],
330
- :description => silo_profile.attributes['description']
331
- }
337
+ def self.parse(xml)
338
+ new do
339
+ @id = xml.attributes['id']
340
+ @name = xml.attributes['name']
341
+ @description = xml.attributes['description']
342
+ @profile_id = xml.attributes['silo-profile-id']
343
+ xml.elements.each('LicenseSummary') do |license|
344
+ @assets = license.attributes['assets']
345
+ @max_assets = license.attributes['max-assets']
346
+ @max_hosted_assets = license.attributes['max-hosted-assets']
347
+ @users = license.attributes['users']
348
+ @max_users = license.attributes['max-users']
332
349
  end
333
- res
334
- else
335
- false
336
350
  end
337
351
  end
338
-
339
- #-------------------------------------------------------------------------
340
- # Delete a silo
341
- #-------------------------------------------------------------------------
342
- def delete_silo name, id
343
- using_name = (name and not name.empty?)
344
- xml = make_xml('SiloDeleteRequest', (using_name ? {'silo-name' => name} : {'silo-id' => id}))
345
- r = execute xml, '1.2'
346
- r.success
347
- end
348
352
  end
349
353
  end