nexpose 0.9.8 → 1.0.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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/nexpose.rb +8 -4
- data/lib/nexpose/ajax.rb +29 -4
- data/lib/nexpose/alert.rb +160 -177
- data/lib/nexpose/api.rb +18 -0
- data/lib/nexpose/common.rb +144 -10
- data/lib/nexpose/credential.rb +185 -1
- data/lib/nexpose/discovery.rb +141 -16
- data/lib/nexpose/discovery/filter.rb +26 -3
- data/lib/nexpose/engine.rb +16 -0
- data/lib/nexpose/json_serializer.rb +92 -0
- data/lib/nexpose/scan.rb +131 -23
- data/lib/nexpose/scan_template.rb +1 -1
- data/lib/nexpose/shared_secret.rb +31 -0
- data/lib/nexpose/site.rb +339 -317
- data/lib/nexpose/site_credentials.rb +178 -0
- data/lib/nexpose/tag.rb +42 -1
- data/lib/nexpose/util.rb +11 -16
- data/lib/nexpose/version.rb +1 -1
- data/lib/nexpose/wait.rb +103 -0
- data/lib/nexpose/web_credentials.rb +252 -0
- metadata +18 -8
- data/lib/nexpose/site_credential.rb +0 -323
@@ -0,0 +1,178 @@
|
|
1
|
+
module Nexpose
|
2
|
+
|
3
|
+
# Object that represents administrative credentials to be used
|
4
|
+
# during a scan. When retrieved from an existing site configuration
|
5
|
+
# the credentials will be returned as a security blob and can only
|
6
|
+
# be passed back as is during a Site Save operation. This object
|
7
|
+
# can only be used to create a new set of credentials.
|
8
|
+
#
|
9
|
+
class SiteCredentials < Credential
|
10
|
+
|
11
|
+
# Unique identifier of the credential on the Nexpose console.
|
12
|
+
attr_accessor :id
|
13
|
+
# The service for these credentials.
|
14
|
+
attr_accessor :service
|
15
|
+
# The host for these credentials.
|
16
|
+
attr_accessor :host_restriction
|
17
|
+
# The port on which to use these credentials.
|
18
|
+
attr_accessor :port_restriction
|
19
|
+
# The password
|
20
|
+
attr_accessor :password
|
21
|
+
# The name
|
22
|
+
attr_accessor :name
|
23
|
+
# is this credential enable on site or not.
|
24
|
+
attr_accessor :enabled
|
25
|
+
# the description of credential
|
26
|
+
attr_accessor :description
|
27
|
+
# domain of the service
|
28
|
+
attr_accessor :domain
|
29
|
+
# database of the service
|
30
|
+
attr_accessor :database
|
31
|
+
# The type of privilege escalation to use (sudo/su)
|
32
|
+
# Permission elevation type. See Nexpose::Credential::ElevationType.
|
33
|
+
attr_accessor :permission_elevation_type
|
34
|
+
# The userid to use when escalating privileges (optional)
|
35
|
+
attr_accessor :permission_elevation_user
|
36
|
+
# The password to use when escalating privileges (optional)
|
37
|
+
attr_accessor :permission_elevation_password
|
38
|
+
# The authentication type to use with SNMP v3 credentials
|
39
|
+
attr_accessor :authentication_type
|
40
|
+
# The privacy/encryption type to use with SNMP v3 credentials
|
41
|
+
attr_accessor :privacy_type
|
42
|
+
# The privacy/encryption pass phrase to use with SNMP v3 credentials
|
43
|
+
attr_accessor :privacy_password
|
44
|
+
# the user name to be used in service
|
45
|
+
attr_accessor :user_name
|
46
|
+
# the notes password
|
47
|
+
attr_accessor :notes_id_password
|
48
|
+
# use windows auth
|
49
|
+
attr_accessor :use_windows_auth
|
50
|
+
# sid for oracle
|
51
|
+
attr_accessor :sid
|
52
|
+
#for ssh public key require pem format private key
|
53
|
+
attr_accessor :pem_format_private_key
|
54
|
+
# for snmp v1/v2
|
55
|
+
attr_accessor :community_name
|
56
|
+
# scope of credential
|
57
|
+
attr_accessor :scope
|
58
|
+
|
59
|
+
#Create a credential object using name, id, description, host and port
|
60
|
+
def self.for_service(name, id = -1, desc = nil, host = nil, port = nil, service = Credential::Service::CIFS)
|
61
|
+
cred = new
|
62
|
+
cred.name = name
|
63
|
+
cred.id = id.to_i
|
64
|
+
cred.enabled = true
|
65
|
+
cred.description = desc
|
66
|
+
cred.host_restriction = host
|
67
|
+
cred.port_restriction = port
|
68
|
+
cred.service = service
|
69
|
+
cred.scope = Credential::Scope::SITE_SPECIFIC
|
70
|
+
cred
|
71
|
+
end
|
72
|
+
|
73
|
+
# Load an credential from the provided console.
|
74
|
+
#
|
75
|
+
# @param [Connection] nsc Active connection to a Nexpose console.
|
76
|
+
# @param [String] id Unique identifier of an site.
|
77
|
+
# @param [String] id Unique identifier of an credential.
|
78
|
+
# @return [SiteCredential] The requested credential of site, if found.
|
79
|
+
#
|
80
|
+
def self.load(nsc, site_id, credential_id)
|
81
|
+
uri = "/api/2.1/sites/#{site_id}/credentials/#{credential_id}"
|
82
|
+
resp = AJAX.get(nsc, uri, AJAX::CONTENT_TYPE::JSON)
|
83
|
+
hash = JSON.parse(resp, symbolize_names: true)
|
84
|
+
new.object_from_hash(nsc, hash)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Copy an existing configuration from a Nexpose instance.
|
88
|
+
# Returned object will reset the credential ID and append "Copy" to the existing
|
89
|
+
# name.
|
90
|
+
#
|
91
|
+
# @param [Connection] connection Connection to the security console.
|
92
|
+
# @param [String] id Unique identifier of an site.
|
93
|
+
# @param [String] id Unique identifier of an credential.
|
94
|
+
# @return [SiteCredentials] Site credential loaded from a Nexpose console.
|
95
|
+
#
|
96
|
+
def self.copy(connection, site_id, credential_id)
|
97
|
+
siteCredential = self.load(connection, site_id, credential_id)
|
98
|
+
siteCredential.id = -1
|
99
|
+
siteCredential.name = "#{siteCredential.name} Copy"
|
100
|
+
siteCredential
|
101
|
+
end
|
102
|
+
|
103
|
+
# Copy an existing configuration from a site credential.
|
104
|
+
# Returned object will reset the credential ID and append "Copy" to the existing
|
105
|
+
# name.
|
106
|
+
#
|
107
|
+
# @param [siteCredential] site credential to be copied.
|
108
|
+
# @return [SiteCredentials] modified.
|
109
|
+
#
|
110
|
+
def self.copy(siteCredential)
|
111
|
+
siteCredential.id = -1
|
112
|
+
siteCredential.name = "#{siteCredential.name} Copy"
|
113
|
+
siteCredential
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_json
|
117
|
+
JSON.generate(to_h)
|
118
|
+
end
|
119
|
+
|
120
|
+
def to_h
|
121
|
+
{ id: id,
|
122
|
+
service: service,
|
123
|
+
host_restriction: host_restriction,
|
124
|
+
port_restriction: port_restriction,
|
125
|
+
password: password,
|
126
|
+
name: name,
|
127
|
+
enabled: enabled,
|
128
|
+
description: description,
|
129
|
+
domain: domain,
|
130
|
+
database: database,
|
131
|
+
permission_elevation_type: permission_elevation_type,
|
132
|
+
permission_elevation_user: permission_elevation_user,
|
133
|
+
permission_elevation_password: permission_elevation_password,
|
134
|
+
authentication_type: authentication_type,
|
135
|
+
privacy_type: privacy_type,
|
136
|
+
privacy_password: privacy_password,
|
137
|
+
user_name: user_name,
|
138
|
+
notes_id_password: notes_id_password,
|
139
|
+
use_windows_auth: use_windows_auth,
|
140
|
+
sid: sid,
|
141
|
+
pem_format_private_key: pem_format_private_key,
|
142
|
+
community_name: community_name,
|
143
|
+
scope: scope
|
144
|
+
}
|
145
|
+
end
|
146
|
+
|
147
|
+
def ==(other)
|
148
|
+
eql?(other)
|
149
|
+
end
|
150
|
+
|
151
|
+
def eql?(other)
|
152
|
+
id.eql?(other.id) &&
|
153
|
+
service.eql?(other.service) &&
|
154
|
+
host_restriction.eql?(other.host_restriction) &&
|
155
|
+
port_restriction.eql?(other.port_restriction) &&
|
156
|
+
password.eql?(other.password) &&
|
157
|
+
name.eql?(other.name) &&
|
158
|
+
enabled.eql?(other.enabled) &&
|
159
|
+
description.eql?(other.description) &&
|
160
|
+
domain.eql?(other.domain) &&
|
161
|
+
database.eql?(other.database) &&
|
162
|
+
permission_elevation_type.eql?(other.permission_elevation_type) &&
|
163
|
+
permission_elevation_user.eql?(other.permission_elevation_user) &&
|
164
|
+
permission_elevation_password.eql?(other.permission_elevation_password) &&
|
165
|
+
authentication_type.eql?(other.authentication_type) &&
|
166
|
+
privacy_type.eql?(other.privacy_type) &&
|
167
|
+
privacy_password.eql?(other.privacy_password) &&
|
168
|
+
user_name.eql?(other.user_name) &&
|
169
|
+
notes_id_password.eql?(other.notes_id_password) &&
|
170
|
+
use_windows_auth.eql?(other.use_windows_auth) &&
|
171
|
+
sid.eql?(other.sid) &&
|
172
|
+
pem_format_private_key.eql?(other.pem_format_private_key) &&
|
173
|
+
community_name.eql?(other.community_name) &&
|
174
|
+
scope.eql?(other.scope)
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
end
|
data/lib/nexpose/tag.rb
CHANGED
@@ -218,7 +218,48 @@ module Nexpose
|
|
218
218
|
end
|
219
219
|
|
220
220
|
@color = hex
|
221
|
-
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Create list of tag objects from hash
|
224
|
+
def self.load_tags(tags)
|
225
|
+
unless tags.nil?
|
226
|
+
tags = tags.map do |hash|
|
227
|
+
self.create(hash)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
tags
|
231
|
+
end
|
232
|
+
|
233
|
+
# Create tag object from hash
|
234
|
+
def self.create(hash)
|
235
|
+
attributes = hash[:attributes]
|
236
|
+
color = attributes.find { |attr| attr[:tag_attribute_name] == 'COLOR' }
|
237
|
+
color = color[:tag_attribute_value] if color
|
238
|
+
source = attributes.find { |attr| attr[:tag_attribute_name] == 'SOURCE' }
|
239
|
+
source = source[:tag_attribute_value] if source
|
240
|
+
tag = Tag.new(hash[:tag_name], hash[:tag_type], hash[:tag_id])
|
241
|
+
tag.color = color
|
242
|
+
tag.source = source
|
243
|
+
tag
|
244
|
+
end
|
245
|
+
|
246
|
+
def to_h
|
247
|
+
{
|
248
|
+
tag_id: id,
|
249
|
+
tag_name: name,
|
250
|
+
tag_type: type,
|
251
|
+
attributes:[
|
252
|
+
{
|
253
|
+
tag_attribute_name: "COLOR",
|
254
|
+
tag_attribute_value: color
|
255
|
+
},
|
256
|
+
{
|
257
|
+
tag_attribute_name: "SOURCE",
|
258
|
+
tag_attribute_value: source
|
259
|
+
}
|
260
|
+
]
|
261
|
+
}
|
262
|
+
end
|
222
263
|
|
223
264
|
# Creates and saves a tag to Nexpose console
|
224
265
|
#
|
data/lib/nexpose/util.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Nexpose
|
2
|
-
|
3
2
|
module Sanitize
|
4
3
|
def replace_entities(str)
|
5
4
|
str.to_s.gsub(/&/, '&').gsub(/'/, ''').gsub(/"/, '"').gsub(/</, '<').gsub(/>/, '>')
|
@@ -7,21 +6,18 @@ module Nexpose
|
|
7
6
|
end
|
8
7
|
|
9
8
|
module XMLUtils
|
10
|
-
|
11
9
|
def parse_xml(xml)
|
12
10
|
::REXML::Document.new(xml.to_s)
|
13
11
|
end
|
14
12
|
|
15
13
|
def make_xml(name, opts = {}, data = '', append_session_id = true)
|
16
14
|
xml = REXML::Element.new(name)
|
17
|
-
if @session_id
|
15
|
+
if @session_id && append_session_id
|
18
16
|
xml.attributes['session-id'] = @session_id
|
19
17
|
end
|
20
18
|
|
21
19
|
opts.keys.each do |k|
|
22
|
-
|
23
|
-
xml.attributes[k] = "#{opts[k]}"
|
24
|
-
end
|
20
|
+
xml.attributes[k] = "#{opts[k]}" unless opts[k].nil?
|
25
21
|
end
|
26
22
|
|
27
23
|
xml.text = data
|
@@ -54,16 +50,15 @@ module Nexpose
|
|
54
50
|
# @return [IPRange|HostName] Valid class, if it can be converted.
|
55
51
|
#
|
56
52
|
def convert(asset)
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
53
|
+
ips = asset.split(' - ')
|
54
|
+
IPAddr.new(ips[0])
|
55
|
+
IPAddr.new(ips[1]) if ips[1]
|
56
|
+
IPRange.new(ips[0], ips[1])
|
57
|
+
rescue ArgumentError => e
|
58
|
+
if e.message == 'invalid address'
|
59
|
+
HostName.new(asset)
|
60
|
+
else
|
61
|
+
raise "Unable to parse asset: '#{asset}'. #{e.message}"
|
67
62
|
end
|
68
63
|
end
|
69
64
|
|
data/lib/nexpose/version.rb
CHANGED
data/lib/nexpose/wait.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
module Nexpose
|
2
|
+
class Wait
|
3
|
+
attr_reader :error_message, :ready, :retry_count, :timeout, :polling_interval
|
4
|
+
|
5
|
+
def initialize(retry_count: nil, timeout: nil, polling_interval: nil)
|
6
|
+
@error_message = 'Default General Failure in Nexpose::Wait'
|
7
|
+
@ready = false
|
8
|
+
@retry_count = retry_count.to_i
|
9
|
+
@timeout = timeout
|
10
|
+
@polling_interval = polling_interval
|
11
|
+
end
|
12
|
+
|
13
|
+
def ready?
|
14
|
+
@ready
|
15
|
+
end
|
16
|
+
|
17
|
+
def for_report(nexpose_connection:, report_id:)
|
18
|
+
poller = Nexpose::Poller.new(timeout: @timeout, polling_interval: @polling_interval)
|
19
|
+
poller.wait(report_status_proc(nexpose_connection: nexpose_connection, report_id: report_id))
|
20
|
+
@ready = true
|
21
|
+
rescue TimeoutError
|
22
|
+
retry if timeout_retry?
|
23
|
+
@error_message = "Timeout Waiting for Report to Generate - Report Config ID: #{report_id}"
|
24
|
+
rescue NoMethodError => error
|
25
|
+
@error_message = "Error Report Config ID: #{report_id} :: Report Probably Does Not Exist :: #{error}"
|
26
|
+
rescue => error
|
27
|
+
@error_message = "Error Report Config ID: #{report_id} :: #{error}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def for_integration(nexpose_connection:, scan_id:, status: 'finished')
|
31
|
+
poller = Nexpose::Poller.new(timeout: @timeout, polling_interval: @polling_interval)
|
32
|
+
poller.wait(integration_status_proc(nexpose_connection: nexpose_connection, scan_id: scan_id, status: status))
|
33
|
+
@ready = true
|
34
|
+
rescue TimeoutError
|
35
|
+
retry if timeout_retry?
|
36
|
+
@error_message = "Timeout Waiting for Integration Status of '#{status}' - Scan ID: #{scan_id}"
|
37
|
+
rescue Nexpose::APIError => error
|
38
|
+
@error_message = "API Error Waiting for Integration Scan ID: #{scan_id} :: #{error.req.error}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def for_judgment(proc:, desc:)
|
42
|
+
poller = Nexpose::Poller.new(timeout: @timeout, polling_interval: @polling_interval)
|
43
|
+
poller.wait(proc)
|
44
|
+
@ready = true
|
45
|
+
rescue TimeoutError
|
46
|
+
retry if timeout_retry?
|
47
|
+
@error_message = "Timeout Waiting for Judgment to Judge. #{desc}"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def report_status_proc(nexpose_connection:, report_id:)
|
53
|
+
Proc.new { nexpose_connection.last_report(report_id).status == 'Generated' }
|
54
|
+
end
|
55
|
+
|
56
|
+
def integration_status_proc(nexpose_connection:, scan_id:, status:)
|
57
|
+
Proc.new { nexpose_connection.scan_status(scan_id).downcase == status.downcase }
|
58
|
+
end
|
59
|
+
|
60
|
+
def timeout_retry?
|
61
|
+
if @retry_count > 0
|
62
|
+
@retry_count -= 1
|
63
|
+
true
|
64
|
+
else
|
65
|
+
false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class Poller
|
71
|
+
## Stand alone object to handle waiting logic.
|
72
|
+
attr_reader :timeout, :polling_interval, :poll_begin
|
73
|
+
|
74
|
+
def initialize(timeout: nil, polling_interval: nil)
|
75
|
+
global_timeout = set_global_timeout
|
76
|
+
@timeout = timeout.nil? ? global_timeout : timeout
|
77
|
+
|
78
|
+
global_polling = set_polling_interval
|
79
|
+
@polling_interval = polling_interval.nil? ? global_polling : polling_interval
|
80
|
+
end
|
81
|
+
|
82
|
+
def wait(condition)
|
83
|
+
@poll_begin = Time.now
|
84
|
+
loop do
|
85
|
+
break if condition.call
|
86
|
+
raise TimeoutError if @poll_begin + @timeout < Time.now
|
87
|
+
sleep @polling_interval
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def set_global_timeout
|
94
|
+
default_timeout = 120
|
95
|
+
ENV['GLOBAL_TIMEOUT'].nil? ? default_timeout : ENV['GLOBAL_TIMEOUT']
|
96
|
+
end
|
97
|
+
|
98
|
+
def set_polling_interval
|
99
|
+
default_polling = 1
|
100
|
+
ENV['GLOBAL_POLLING_INTERVAL'].nil? ? default_polling : ENV['GLOBAL_POLLING_INTERVAL']
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,252 @@
|
|
1
|
+
module Nexpose
|
2
|
+
|
3
|
+
# Object that represents web credential defined in site configuration.
|
4
|
+
module WebCredentials
|
5
|
+
|
6
|
+
module WebAppAuthType
|
7
|
+
HTML_FORM = 'htmlform' # Represent HTML form credentials.
|
8
|
+
HTTP_HEADER = 'httpheaders' # Represent HTTP header credentials.
|
9
|
+
end
|
10
|
+
|
11
|
+
# Object that represents Header name-value pairs, associated with Web Session Authentication.
|
12
|
+
#
|
13
|
+
class Header
|
14
|
+
|
15
|
+
# Name, one per Header
|
16
|
+
attr_reader :name
|
17
|
+
# Value, one per Header
|
18
|
+
attr_reader :value
|
19
|
+
|
20
|
+
# Construct with name value pair
|
21
|
+
def initialize(name, value)
|
22
|
+
@name = name
|
23
|
+
@value = value
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_json
|
27
|
+
JSON.generate(to_h)
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_h
|
31
|
+
header = Hash.new
|
32
|
+
header[@name] = @value
|
33
|
+
header
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Object that represents Headers, associated with Web Session Authentication.
|
38
|
+
#
|
39
|
+
class Headers < APIObject
|
40
|
+
|
41
|
+
# A regular expression used to match against the response to identify authentication failures.
|
42
|
+
attr_reader :soft403Pattern
|
43
|
+
# Base URL of the application for which the form authentication applies.
|
44
|
+
attr_reader :baseURL
|
45
|
+
# When using HTTP headers, this represents the set of headers to pass with the authentication request.
|
46
|
+
attr_reader :headers
|
47
|
+
# name of the html header
|
48
|
+
attr_reader :name
|
49
|
+
# is this enable for the site configuration
|
50
|
+
attr_accessor :enabled
|
51
|
+
#service type of header
|
52
|
+
attr_reader :service
|
53
|
+
# id of the header
|
54
|
+
attr_reader :id
|
55
|
+
|
56
|
+
|
57
|
+
def initialize(name, baseURL, soft403Pattern, id = -1, enabled = true)
|
58
|
+
@headers = {}
|
59
|
+
@name = name
|
60
|
+
@baseURL = baseURL
|
61
|
+
@soft403Pattern = soft403Pattern
|
62
|
+
@service = WebAppAuthType::HTTP_HEADER
|
63
|
+
@enabled = enabled
|
64
|
+
@id = id
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_header(header)
|
68
|
+
@headers = @headers.merge(header.to_h)
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_json
|
72
|
+
JSON.generate(to_h)
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_h
|
76
|
+
{ id: id,
|
77
|
+
service: service,
|
78
|
+
enabled: enabled,
|
79
|
+
name: name,
|
80
|
+
headers: headers,
|
81
|
+
baseURL: baseURL,
|
82
|
+
soft403Pattern: soft403Pattern
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
def ==(other)
|
87
|
+
eql?(other)
|
88
|
+
end
|
89
|
+
|
90
|
+
def eql?(other)
|
91
|
+
id.eql?(other.id) &&
|
92
|
+
service.eql?(other.service) &&
|
93
|
+
enabled.eql?(other.enabled) &&
|
94
|
+
name.eql?(other.name) &&
|
95
|
+
headers.eql?(other.headers) &&
|
96
|
+
baseURL.eql?(other.baseURL) &&
|
97
|
+
soft403Pattern.eql?(other.soft403Pattern)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# When using HTML form, this represents the login form information.
|
102
|
+
#
|
103
|
+
class Field
|
104
|
+
# The name of the HTML field (form parameter).
|
105
|
+
attr_reader :name
|
106
|
+
# The value of the HTML field (form parameter).
|
107
|
+
attr_reader :value
|
108
|
+
# The type of the HTML field (form parameter).
|
109
|
+
attr_reader :type
|
110
|
+
# Is the HTML field (form parameter) dynamically generated? If so,
|
111
|
+
# the login page is requested and the value of the field is extracted
|
112
|
+
# from the response.
|
113
|
+
attr_reader :dynamic
|
114
|
+
# If the HTML field (form parameter) is a radio button, checkbox or select
|
115
|
+
# field, this flag determines if the field should be checked (selected).
|
116
|
+
attr_reader :checked
|
117
|
+
|
118
|
+
def initialize(name, value, type, dynamic, checked)
|
119
|
+
@name = name
|
120
|
+
@value = value
|
121
|
+
@type = type
|
122
|
+
@dynamic = dynamic
|
123
|
+
@checked = checked
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_json
|
127
|
+
JSON.generate(to_h)
|
128
|
+
end
|
129
|
+
|
130
|
+
def to_h
|
131
|
+
{
|
132
|
+
value: value,
|
133
|
+
type: type,
|
134
|
+
name: name,
|
135
|
+
dynamic: dynamic,
|
136
|
+
checked: checked
|
137
|
+
}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# When using HTML form, this represents the login form information.
|
142
|
+
#
|
143
|
+
class HTMLForm
|
144
|
+
|
145
|
+
# The name of the form being submitted.
|
146
|
+
attr_reader :name
|
147
|
+
# The HTTP action (URL) through which to submit the login form.
|
148
|
+
attr_reader :action
|
149
|
+
# The HTTP request method with which to submit the form.
|
150
|
+
attr_reader :method
|
151
|
+
# The HTTP encoding type with which to submit the form.
|
152
|
+
attr_reader :encType
|
153
|
+
# The fields in the HTML Form
|
154
|
+
attr_reader :fields
|
155
|
+
|
156
|
+
def initialize(name, action, method, encType)
|
157
|
+
@name = name
|
158
|
+
@action = action
|
159
|
+
@method = method
|
160
|
+
@encType = encType
|
161
|
+
@fields = []
|
162
|
+
end
|
163
|
+
|
164
|
+
def add_field(field)
|
165
|
+
@fields << field.to_h
|
166
|
+
end
|
167
|
+
|
168
|
+
def to_json
|
169
|
+
JSON.generate(to_h)
|
170
|
+
end
|
171
|
+
|
172
|
+
def to_h
|
173
|
+
{ name: name,
|
174
|
+
action: action,
|
175
|
+
method: method,
|
176
|
+
encType: encType,
|
177
|
+
fields: fields,
|
178
|
+
parentPage: action
|
179
|
+
}
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# When using HTML form, this represents the login form information.
|
184
|
+
#
|
185
|
+
class HTMLForms < APIObject
|
186
|
+
|
187
|
+
# A regular expression used to match against the response to identify authentication failures.
|
188
|
+
attr_reader :soft403Pattern
|
189
|
+
# Base URL of the application for which the form authentication applies.
|
190
|
+
attr_reader :baseURL
|
191
|
+
# The URL of the login page containing the login form.
|
192
|
+
attr_reader :loginURL
|
193
|
+
# name of the html header
|
194
|
+
attr_reader :name
|
195
|
+
# is this enable for the site configuration
|
196
|
+
attr_accessor :enabled
|
197
|
+
#service type of header
|
198
|
+
attr_reader :service
|
199
|
+
# id of the header
|
200
|
+
attr_reader :id
|
201
|
+
# The forms to authenticate with
|
202
|
+
attr_reader :form
|
203
|
+
|
204
|
+
def initialize(name, baseURL, loginURL, soft403Pattern, id = -1, enabled = true)
|
205
|
+
@name = name
|
206
|
+
@baseURL = baseURL
|
207
|
+
@loginURL = loginURL
|
208
|
+
@soft403Pattern = soft403Pattern
|
209
|
+
@service = WebAppAuthType::HTML_FORM
|
210
|
+
@enabled = enabled
|
211
|
+
@id = id
|
212
|
+
end
|
213
|
+
|
214
|
+
def add_html_form(html_form)
|
215
|
+
@form = html_form
|
216
|
+
end
|
217
|
+
|
218
|
+
def to_json
|
219
|
+
JSON.generate(to_h)
|
220
|
+
end
|
221
|
+
|
222
|
+
def to_h
|
223
|
+
{ id: id,
|
224
|
+
service: service,
|
225
|
+
enabled: enabled,
|
226
|
+
name: name,
|
227
|
+
form: form.to_h,
|
228
|
+
baseURL: baseURL,
|
229
|
+
loginURL: loginURL,
|
230
|
+
soft403Pattern: soft403Pattern
|
231
|
+
}
|
232
|
+
end
|
233
|
+
|
234
|
+
def ==(other)
|
235
|
+
eql?(other)
|
236
|
+
end
|
237
|
+
|
238
|
+
def eql?(other)
|
239
|
+
id.eql?(other.id) &&
|
240
|
+
service.eql?(other.service) &&
|
241
|
+
enabled.eql?(other.enabled) &&
|
242
|
+
name.eql?(other.name) &&
|
243
|
+
form.eql?(other.form) &&
|
244
|
+
baseURL.eql?(other.baseURL) &&
|
245
|
+
loginURL.eql?(other.loginURL) &&
|
246
|
+
soft403Pattern.eql?(other.soft403Pattern)
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|