nexpose 7.0.0 → 7.0.1
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 +4 -4
- data/CHANGELOG.md +2 -3
- data/Gemfile.lock +1 -1
- data/lib/nexpose/ajax.rb +12 -16
- data/lib/nexpose/alert.rb +20 -21
- data/lib/nexpose/api.rb +3 -3
- data/lib/nexpose/asset.rb +23 -23
- data/lib/nexpose/blackout.rb +6 -14
- data/lib/nexpose/common.rb +87 -92
- data/lib/nexpose/connection.rb +8 -10
- data/lib/nexpose/console.rb +9 -9
- data/lib/nexpose/dag.rb +2 -2
- data/lib/nexpose/data_table.rb +8 -12
- data/lib/nexpose/device.rb +35 -34
- data/lib/nexpose/discovery.rb +69 -69
- data/lib/nexpose/discovery/filter.rb +7 -8
- data/lib/nexpose/engine.rb +22 -21
- data/lib/nexpose/error.rb +7 -5
- data/lib/nexpose/external.rb +21 -16
- data/lib/nexpose/filter.rb +51 -52
- data/lib/nexpose/global_blackout.rb +6 -7
- data/lib/nexpose/global_settings.rb +2 -3
- data/lib/nexpose/group.rb +25 -19
- data/lib/nexpose/json_serializer.rb +4 -14
- data/lib/nexpose/maint.rb +8 -9
- data/lib/nexpose/manage.rb +2 -2
- data/lib/nexpose/multi_tenant_user.rb +42 -42
- data/lib/nexpose/password_policy.rb +14 -14
- data/lib/nexpose/pool.rb +6 -5
- data/lib/nexpose/report.rb +30 -34
- data/lib/nexpose/report_template.rb +17 -18
- data/lib/nexpose/role.rb +64 -55
- data/lib/nexpose/scan.rb +77 -60
- data/lib/nexpose/scan_template.rb +17 -17
- data/lib/nexpose/scheduled_backup.rb +8 -8
- data/lib/nexpose/scheduled_maintenance.rb +9 -9
- data/lib/nexpose/shared_credential.rb +30 -33
- data/lib/nexpose/shared_secret.rb +5 -5
- data/lib/nexpose/silo.rb +68 -66
- data/lib/nexpose/silo_profile.rb +47 -50
- data/lib/nexpose/site.rb +101 -123
- data/lib/nexpose/site_credentials.rb +15 -17
- data/lib/nexpose/tag.rb +73 -80
- data/lib/nexpose/ticket.rb +45 -42
- data/lib/nexpose/user.rb +45 -45
- data/lib/nexpose/util.rb +1 -1
- data/lib/nexpose/version.rb +1 -1
- data/lib/nexpose/vuln.rb +45 -43
- data/lib/nexpose/vuln_def.rb +7 -7
- data/lib/nexpose/vuln_exception.rb +35 -36
- data/lib/nexpose/wait.rb +32 -28
- data/lib/nexpose/web_credentials.rb +34 -36
- metadata +2 -2
data/lib/nexpose/pool.rb
CHANGED
@@ -21,7 +21,7 @@ module Nexpose
|
|
21
21
|
arr
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
alias engine_pools list_engine_pools
|
25
25
|
end
|
26
26
|
|
27
27
|
# A summary of an engine pool.
|
@@ -36,8 +36,8 @@ module Nexpose
|
|
36
36
|
attr_reader :scope
|
37
37
|
|
38
38
|
def initialize(id, name, scope = 'silo')
|
39
|
-
@id
|
40
|
-
@name
|
39
|
+
@id = id.to_i
|
40
|
+
@name = name
|
41
41
|
@scope = scope
|
42
42
|
end
|
43
43
|
|
@@ -74,7 +74,9 @@ module Nexpose
|
|
74
74
|
attr_accessor :engines
|
75
75
|
|
76
76
|
def initialize(name, scope = 'silo', id = -1)
|
77
|
-
@name
|
77
|
+
@name = name
|
78
|
+
@scope = scope
|
79
|
+
@id = id.to_i
|
78
80
|
@engines = []
|
79
81
|
end
|
80
82
|
|
@@ -100,7 +102,6 @@ module Nexpose
|
|
100
102
|
xml = %(<EnginePoolDetailsRequest session-id="#{connection.session_id}">)
|
101
103
|
xml << %(<EnginePool name="#{name}" scope="#{scope}"/>)
|
102
104
|
xml << '</EnginePoolDetailsRequest>'
|
103
|
-
|
104
105
|
r = connection.execute(xml, '1.2')
|
105
106
|
if r.success
|
106
107
|
r.res.elements.each('EnginePoolDetailsResponse/EnginePool') do |pool|
|
data/lib/nexpose/report.rb
CHANGED
@@ -19,7 +19,7 @@ module Nexpose
|
|
19
19
|
reports
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
alias reports list_reports
|
23
23
|
|
24
24
|
# Generate a new report using the specified report definition.
|
25
25
|
def generate_report(report_id, wait = false)
|
@@ -38,7 +38,7 @@ module Nexpose
|
|
38
38
|
return summary unless summary.status == 'Started'
|
39
39
|
sleep 5
|
40
40
|
so_far += 5
|
41
|
-
if so_far % 60
|
41
|
+
if (so_far % 60).zero?
|
42
42
|
puts "Still waiting. Current status: #{summary.status}"
|
43
43
|
end
|
44
44
|
end
|
@@ -101,13 +101,13 @@ module Nexpose
|
|
101
101
|
attr_reader :scope
|
102
102
|
|
103
103
|
def initialize(config_id, name, template_id, status, generated_on, uri, scope)
|
104
|
-
@config_id
|
105
|
-
@name
|
106
|
-
@template_id
|
107
|
-
@status
|
104
|
+
@config_id = config_id.to_i
|
105
|
+
@name = name
|
106
|
+
@template_id = template_id
|
107
|
+
@status = status
|
108
108
|
@generated_on = generated_on
|
109
|
-
@uri
|
110
|
-
@scope
|
109
|
+
@uri = uri
|
110
|
+
@scope = scope
|
111
111
|
end
|
112
112
|
|
113
113
|
def self.parse(xml)
|
@@ -138,11 +138,11 @@ module Nexpose
|
|
138
138
|
attr_reader :uri
|
139
139
|
|
140
140
|
def initialize(id, config_id, status, generated_on, uri)
|
141
|
-
@id
|
142
|
-
@config_id
|
143
|
-
@status
|
141
|
+
@id = id
|
142
|
+
@config_id = config_id.to_i
|
143
|
+
@status = status
|
144
144
|
@generated_on = generated_on
|
145
|
-
@uri
|
145
|
+
@uri = uri
|
146
146
|
end
|
147
147
|
|
148
148
|
# Delete this report.
|
@@ -194,11 +194,11 @@ module Nexpose
|
|
194
194
|
|
195
195
|
def initialize(template_id, format, site_id = nil, owner = nil, time_zone = nil)
|
196
196
|
@template_id = template_id
|
197
|
-
@format
|
198
|
-
@owner
|
199
|
-
@time_zone
|
197
|
+
@format = format
|
198
|
+
@owner = owner
|
199
|
+
@time_zone = time_zone
|
200
200
|
|
201
|
-
@filters
|
201
|
+
@filters = []
|
202
202
|
@filters << Filter.new('site', site_id) if site_id
|
203
203
|
end
|
204
204
|
|
@@ -289,15 +289,14 @@ module Nexpose
|
|
289
289
|
|
290
290
|
# Construct a basic ReportConfig object.
|
291
291
|
def initialize(name, template_id, format, id = -1, owner = nil, time_zone = nil)
|
292
|
-
@name
|
292
|
+
@name = name
|
293
293
|
@template_id = template_id
|
294
|
-
@format
|
295
|
-
@id
|
296
|
-
@owner
|
297
|
-
@time_zone
|
298
|
-
|
299
|
-
@
|
300
|
-
@users = []
|
294
|
+
@format = format
|
295
|
+
@id = id
|
296
|
+
@owner = owner
|
297
|
+
@time_zone = time_zone
|
298
|
+
@filters = []
|
299
|
+
@users = []
|
301
300
|
end
|
302
301
|
|
303
302
|
# Retrieve the configuration for an existing report definition.
|
@@ -306,7 +305,7 @@ module Nexpose
|
|
306
305
|
ReportConfig.parse(connection.execute(xml))
|
307
306
|
end
|
308
307
|
|
309
|
-
|
308
|
+
alias get load
|
310
309
|
|
311
310
|
# Build and save a report configuration against the specified site using
|
312
311
|
# the supplied type and format.
|
@@ -436,11 +435,8 @@ module Nexpose
|
|
436
435
|
%(<filter id="#{replace_entities(@id)}" type="#{@type}" />)
|
437
436
|
end
|
438
437
|
|
439
|
-
def ==(
|
440
|
-
|
441
|
-
(object.instance_of?(self.class) &&
|
442
|
-
object.type == @type &&
|
443
|
-
object.id == @id)
|
438
|
+
def ==(other)
|
439
|
+
other.equal?(self) || (other.instance_of?(self.class) && other.type == @type && other.id == @id)
|
444
440
|
end
|
445
441
|
|
446
442
|
def self.parse(xml)
|
@@ -466,8 +462,8 @@ module Nexpose
|
|
466
462
|
|
467
463
|
def initialize(after_scan, scheduled, schedule = nil)
|
468
464
|
@after_scan = after_scan
|
469
|
-
@scheduled
|
470
|
-
@schedule
|
465
|
+
@scheduled = scheduled
|
466
|
+
@schedule = schedule
|
471
467
|
end
|
472
468
|
|
473
469
|
def to_xml
|
@@ -610,9 +606,9 @@ module Nexpose
|
|
610
606
|
xml.elements.each('//credentials') do |creds|
|
611
607
|
credential = ExportCredential.new(creds.text)
|
612
608
|
# The following attributes may not exist.
|
613
|
-
credential.user_id
|
609
|
+
credential.user_id = creds.attributes['userid']
|
614
610
|
credential.password = creds.attributes['password']
|
615
|
-
credential.realm
|
611
|
+
credential.realm = creds.attributes['realm']
|
616
612
|
return credential
|
617
613
|
end
|
618
614
|
nil
|
@@ -19,7 +19,7 @@ module Nexpose
|
|
19
19
|
templates
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
alias report_templates list_report_templates
|
23
23
|
|
24
24
|
# Deletes an existing, custom report template.
|
25
25
|
# Cannot delete built-in templates.
|
@@ -53,11 +53,11 @@ module Nexpose
|
|
53
53
|
attr_reader :description
|
54
54
|
|
55
55
|
def initialize(id, name, type, scope, built_in, description)
|
56
|
-
@id
|
57
|
-
@name
|
58
|
-
@type
|
59
|
-
@scope
|
60
|
-
@built_in
|
56
|
+
@id = id
|
57
|
+
@name = name
|
58
|
+
@type = type
|
59
|
+
@scope = scope
|
60
|
+
@built_in = built_in
|
61
61
|
@description = description
|
62
62
|
end
|
63
63
|
|
@@ -109,19 +109,18 @@ module Nexpose
|
|
109
109
|
attr_accessor :attributes
|
110
110
|
# Display asset names with IPs.
|
111
111
|
attr_accessor :show_asset_names
|
112
|
-
alias
|
113
|
-
alias
|
112
|
+
alias show_device_names show_asset_names
|
113
|
+
alias show_device_names= show_asset_names=
|
114
114
|
|
115
115
|
def initialize(name, type = 'document', id = -1, scope = 'silo', built_in = false)
|
116
|
-
@name
|
117
|
-
@type
|
118
|
-
@id
|
119
|
-
@scope
|
120
|
-
@built_in
|
121
|
-
|
122
|
-
@
|
123
|
-
@
|
124
|
-
@attributes = []
|
116
|
+
@name = name
|
117
|
+
@type = type
|
118
|
+
@id = id
|
119
|
+
@scope = scope
|
120
|
+
@built_in = built_in
|
121
|
+
@sections = []
|
122
|
+
@properties = {}
|
123
|
+
@attributes = []
|
125
124
|
@show_asset_names = false
|
126
125
|
end
|
127
126
|
|
@@ -219,7 +218,7 @@ module Nexpose
|
|
219
218
|
attr_accessor :properties
|
220
219
|
|
221
220
|
def initialize(name)
|
222
|
-
@name
|
221
|
+
@name = name
|
223
222
|
@properties = {}
|
224
223
|
end
|
225
224
|
|
data/lib/nexpose/role.rb
CHANGED
@@ -4,44 +4,44 @@ module Nexpose
|
|
4
4
|
module Privilege
|
5
5
|
|
6
6
|
module Global
|
7
|
-
CREATE_REPORTS
|
8
|
-
CONFIGURE_GLOBAL_SETTINGS
|
9
|
-
MANAGE_SITES
|
10
|
-
MANAGE_ASSET_GROUPS
|
7
|
+
CREATE_REPORTS = 'CreateReports'
|
8
|
+
CONFIGURE_GLOBAL_SETTINGS = 'ConfigureGlobalSettings'
|
9
|
+
MANAGE_SITES = 'ManageSites'
|
10
|
+
MANAGE_ASSET_GROUPS = 'ManageAssetGroups'
|
11
11
|
MANAGE_DYNAMIC_ASSET_GROUPS = 'ManageDynamicAssetGroups'
|
12
|
-
MANAGE_SCAN_TEMPLATES
|
13
|
-
MANAGE_REPORT_TEMPLATES
|
12
|
+
MANAGE_SCAN_TEMPLATES = 'ManageScanTemplates'
|
13
|
+
MANAGE_REPORT_TEMPLATES = 'ManageReportTemplates'
|
14
14
|
GENERATE_RESTRICTED_REPORTS = 'GenerateRestrictedReports'
|
15
|
-
MANAGE_SCAN_ENGINES
|
16
|
-
SUBMIT_VULN_EXCEPTIONS
|
17
|
-
APPROVE_VULN_EXCEPTIONS
|
18
|
-
DELETE_VULN_EXCEPTIONS
|
19
|
-
CREATE_TICKETS
|
20
|
-
CLOSE_TICKETS
|
21
|
-
TICKET_ASSIGNEE
|
22
|
-
ADD_USERS_TO_SITE
|
23
|
-
ADD_USERS_TO_GROUP
|
24
|
-
ADD_USERS_TO_REPORT
|
25
|
-
MANAGE_POLICIES
|
26
|
-
MANAGE_TAGS
|
15
|
+
MANAGE_SCAN_ENGINES = 'ManageScanEngines'
|
16
|
+
SUBMIT_VULN_EXCEPTIONS = 'SubmitVulnExceptions'
|
17
|
+
APPROVE_VULN_EXCEPTIONS = 'ApproveVulnExceptions'
|
18
|
+
DELETE_VULN_EXCEPTIONS = 'DeleteVulnExceptions'
|
19
|
+
CREATE_TICKETS = 'CreateTickets'
|
20
|
+
CLOSE_TICKETS = 'CloseTickets'
|
21
|
+
TICKET_ASSIGNEE = 'TicketAssignee'
|
22
|
+
ADD_USERS_TO_SITE = 'AddUsersToSite'
|
23
|
+
ADD_USERS_TO_GROUP = 'AddUsersToGroup'
|
24
|
+
ADD_USERS_TO_REPORT = 'AddUsersToReport'
|
25
|
+
MANAGE_POLICIES = 'ManagePolicies'
|
26
|
+
MANAGE_TAGS = 'ManageTags'
|
27
27
|
end
|
28
28
|
|
29
29
|
module Site
|
30
|
-
VIEW_ASSET_DATA
|
31
|
-
CONFIGURE_ALERTS
|
32
|
-
CONFIGURE_CREDENTIALS
|
33
|
-
CONFIGURE_ENGINES
|
30
|
+
VIEW_ASSET_DATA = 'ViewAssetData' # NOTE Duplicated between Site and AssetGroup
|
31
|
+
CONFIGURE_ALERTS = 'ConfigureAlerts'
|
32
|
+
CONFIGURE_CREDENTIALS = 'ConfigureCredentials'
|
33
|
+
CONFIGURE_ENGINES = 'ConfigureEngines'
|
34
34
|
CONFIGURE_SCAN_TEMPLATES = 'ConfigureScanTemplates'
|
35
35
|
CONFIGURE_SCHEDULE_SCANS = 'ConfigureScheduleScans'
|
36
|
-
CONFIGURE_SITE_SETTINGS
|
37
|
-
CONFIGURE_TARGETS
|
38
|
-
MANUAL_SCANS
|
39
|
-
PURGE_DATA
|
36
|
+
CONFIGURE_SITE_SETTINGS = 'ConfigureSiteSettings'
|
37
|
+
CONFIGURE_TARGETS = 'ConfigureTargets'
|
38
|
+
MANUAL_SCANS = 'ManualScans'
|
39
|
+
PURGE_DATA = 'PurgeData'
|
40
40
|
end
|
41
41
|
|
42
42
|
module AssetGroup
|
43
43
|
CONFIGURE_ASSETS = 'ConfigureAssets'
|
44
|
-
VIEW_ASSET_DATA
|
44
|
+
VIEW_ASSET_DATA = 'ViewAssetData' # NOTE Duplicated between Site and AssetGroup
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -51,27 +51,27 @@ module Nexpose
|
|
51
51
|
# Returns a summary list of all roles.
|
52
52
|
#
|
53
53
|
def role_listing
|
54
|
-
xml
|
55
|
-
r
|
54
|
+
xml = make_xml('RoleListingRequest')
|
55
|
+
r = execute(xml, '1.2')
|
56
56
|
roles = []
|
57
57
|
if r.success
|
58
58
|
r.res.elements.each('RoleListingResponse/RoleSummary') do |summary|
|
59
|
-
roles << RoleSummary
|
59
|
+
roles << RoleSummary.parse(summary)
|
60
60
|
end
|
61
61
|
end
|
62
62
|
roles
|
63
63
|
end
|
64
64
|
|
65
|
-
|
65
|
+
alias roles role_listing
|
66
66
|
|
67
67
|
def role_delete(role, scope = Scope::SILO)
|
68
68
|
xml = make_xml('RoleDeleteRequest')
|
69
|
-
xml.add_element('Role', {'name' => role, 'scope' => scope})
|
69
|
+
xml.add_element('Role', { 'name' => role, 'scope' => scope })
|
70
70
|
response = execute(xml, '1.2')
|
71
71
|
response.success
|
72
72
|
end
|
73
73
|
|
74
|
-
|
74
|
+
alias delete_role role_delete
|
75
75
|
end
|
76
76
|
|
77
77
|
# Role summary object encapsulating information about a role.
|
@@ -98,7 +98,12 @@ module Nexpose
|
|
98
98
|
attr_accessor :scope
|
99
99
|
|
100
100
|
def initialize(name, full_name, id, description, enabled = true, scope = Scope::SILO)
|
101
|
-
@name
|
101
|
+
@name = name
|
102
|
+
@full_name = full_name
|
103
|
+
@id = id.to_i
|
104
|
+
@description = description
|
105
|
+
@enabled = enabled
|
106
|
+
@scope = scope
|
102
107
|
end
|
103
108
|
|
104
109
|
def self.parse(xml)
|
@@ -116,12 +121,12 @@ module Nexpose
|
|
116
121
|
|
117
122
|
# Constants, mapping UI terms to role names expected by API.
|
118
123
|
|
119
|
-
GLOBAL_ADMINISTRATOR
|
120
|
-
ASSET_OWNER
|
124
|
+
GLOBAL_ADMINISTRATOR = 'global-admin'
|
125
|
+
ASSET_OWNER = 'system-admin'
|
121
126
|
CONTROLS_INSIGHT_ONLY = 'controls-insight-only'
|
122
|
-
SECURITY_MANAGER
|
123
|
-
SITE_OWNER
|
124
|
-
USER
|
127
|
+
SECURITY_MANAGER = 'security-manager'
|
128
|
+
SITE_OWNER = 'site-admin'
|
129
|
+
USER = 'user'
|
125
130
|
|
126
131
|
# Array of all privileges which are enabled for this role.
|
127
132
|
# Note: Although the underlying XML has different requirements, this only checks for presence.
|
@@ -133,7 +138,11 @@ module Nexpose
|
|
133
138
|
attr_accessor :existing
|
134
139
|
|
135
140
|
def initialize(name, full_name, id = -1, enabled = true, scope = Scope::SILO)
|
136
|
-
@name
|
141
|
+
@name = name
|
142
|
+
@full_name = full_name
|
143
|
+
@id = id.to_i
|
144
|
+
@enabled = enabled
|
145
|
+
@scope = scope
|
137
146
|
@privileges = []
|
138
147
|
end
|
139
148
|
|
@@ -147,7 +156,7 @@ module Nexpose
|
|
147
156
|
#
|
148
157
|
def self.load(nsc, name, scope = Scope::SILO)
|
149
158
|
xml = nsc.make_xml('RoleDetailsRequest')
|
150
|
-
xml.add_element('Role', {'name' => name, 'scope' => scope})
|
159
|
+
xml.add_element('Role', { 'name' => name, 'scope' => scope })
|
151
160
|
response = APIRequest.execute(nsc.url, xml, '1.2')
|
152
161
|
|
153
162
|
if response.success
|
@@ -156,7 +165,7 @@ module Nexpose
|
|
156
165
|
end
|
157
166
|
end
|
158
167
|
|
159
|
-
|
168
|
+
alias get load
|
160
169
|
|
161
170
|
# Create or save a Role to the Nexpose console.
|
162
171
|
#
|
@@ -170,9 +179,9 @@ module Nexpose
|
|
170
179
|
end
|
171
180
|
xml.add_element(as_xml)
|
172
181
|
|
173
|
-
response
|
174
|
-
xml
|
175
|
-
@id
|
182
|
+
response = APIRequest.execute(nsc.url, xml, '1.2')
|
183
|
+
xml = REXML::XPath.first(response.res, 'RoleCreateResponse')
|
184
|
+
@id = xml.attributes['id'].to_i unless @existing
|
176
185
|
@existing = true
|
177
186
|
response.success
|
178
187
|
end
|
@@ -186,9 +195,9 @@ module Nexpose
|
|
186
195
|
# @return [Role] requested role.
|
187
196
|
#
|
188
197
|
def self.copy(nsc, name, scope = Scope::SILO)
|
189
|
-
role
|
190
|
-
role.name
|
191
|
-
role.id
|
198
|
+
role = load(nsc, name, scope)
|
199
|
+
role.name = role.full_name = nil
|
200
|
+
role.id = -1
|
192
201
|
role.existing = false
|
193
202
|
role
|
194
203
|
end
|
@@ -230,29 +239,29 @@ module Nexpose
|
|
230
239
|
|
231
240
|
def as_xml
|
232
241
|
xml = REXML::Element.new('Role')
|
233
|
-
xml.add_attributes({'name' => @name, 'full-name' => @full_name, 'enabled' => enabled
|
242
|
+
xml.add_attributes({ 'name' => @name, 'full-name' => @full_name, 'enabled' => enabled, 'scope' => @scope })
|
234
243
|
xml.add_attribute('id', @id) if @id > 0
|
235
244
|
xml.add_element('Description').text = @description
|
236
245
|
|
237
246
|
site_privileges = xml.add_element('SitePrivileges')
|
238
|
-
Privilege::Site
|
247
|
+
Privilege::Site.constants.each do |field|
|
239
248
|
as_s = Privilege::Site.const_get(field)
|
240
249
|
enabled = privileges.member? as_s
|
241
|
-
site_privileges.add_element(
|
250
|
+
site_privileges.add_element(as_s, { 'enabled' => enabled })
|
242
251
|
end
|
243
252
|
|
244
253
|
asset_group_privileges = xml.add_element('AssetGroupPrivileges')
|
245
|
-
Privilege::AssetGroup
|
254
|
+
Privilege::AssetGroup.constants.each do |field|
|
246
255
|
as_s = Privilege::AssetGroup.const_get(field)
|
247
256
|
enabled = privileges.member? as_s
|
248
|
-
asset_group_privileges.add_element(
|
257
|
+
asset_group_privileges.add_element(as_s, { 'enabled' => enabled })
|
249
258
|
end
|
250
259
|
|
251
260
|
global_privileges = xml.add_element('GlobalPrivileges')
|
252
|
-
Privilege::Global
|
261
|
+
Privilege::Global.constants.each do |field|
|
253
262
|
as_s = Privilege::Global.const_get(field)
|
254
263
|
enabled = privileges.member? as_s
|
255
|
-
global_privileges.add_element(
|
264
|
+
global_privileges.add_element(as_s, { 'enabled' => enabled })
|
256
265
|
end
|
257
266
|
|
258
267
|
xml
|