nexpose_ticketing 1.4.2 → 1.5.0

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: bd6e9d8bd62c54470ca4f54e04771f6a12ccdd8c
4
- data.tar.gz: 43dd34880ed11034f401ea0e848a88824446324f
3
+ metadata.gz: d1458f962f3e9bd3d18d9d2286438b3525d41811
4
+ data.tar.gz: 8eb1e53fe25c1562148ca9c83d04d79771cf68df
5
5
  SHA512:
6
- metadata.gz: 9888c112b4b8f6fbefaa14a57631dd81beb24b343c17789f0e03a3f4bbd8881bec1b7e11967c0bc3fb0b3c5573c1e760d9cab06b75525c340123b5ee7d06f5a7
7
- data.tar.gz: b87cf187e0344b22c4a9dc30db87a0befcff1323e4aad8aa4558a27de9191d70ee2dd0c78c863bb9ae75abad38783f0293df6e3f3b5c431a3ca4c48126510f21
6
+ metadata.gz: c81d2388596d93be2da301efafbbb96d9baf84a690cb5b75208839749ced211e690b477410b1a09bc0101f077584f138f5eb554e597ce18c09b30c2648f4ea2c
7
+ data.tar.gz: d1d3a1394b6de2bc5627f2ee0520dc61369f2ced8dbaa4ac37c89c73e53c340b4c85d911797477bf344f66562b2443eda2dd293c8e03e6a8c442b024c2c4f9ab
data/README.md CHANGED
@@ -49,20 +49,33 @@ Please refer to your particular Ruby documentation for actual installation folde
49
49
  A logger is also implemented by default, and the log can be found under `<install_location>/lib/nexpose_ticketing/logs/`
50
50
  Please refer to the log file in case of an error.
51
51
 
52
+ ### Encryption Settings
53
+
54
+ The usernames and passwords within the configuration files are automatically encrypted when the integration runs. The key and IV files used during encryption/decryption are saved within the config folder by default.
55
+
56
+ #### Setting Custom Locations for Encryption Files
57
+
58
+ To set custom locations for the key and IV files, update the following values within the encryption.config file:
59
+
60
+ - key_filename - The absolute path to where the key file will be created.
61
+ - iv_file - The absolute path to where the IV file will be created.
62
+
63
+ To set a custom path after the integration has already executed, the files must be moved to the new location manually.
64
+
52
65
  ## Contributions
53
66
 
54
67
  To develop your own implementation for Ticketing service 'foo':
55
68
 
56
69
  1. Create a helper class that implements the following methods:
57
- * Initialize: This is the constructor that will take the implementation options and the service options. It should inherit from the base_helper class.
58
- * create_ticket(tickets) - This method should implement the transport class for the 'foo' service (https, smtp, SOAP, etc).
59
- * prepare_create_tickets(vulnerability_list, nexpose_identifier_id) - This method will take the vulnerability_list in CSV format and transform it into 'foo' accepted data (JSON, XML, etc). The implemented helpers group data into a single ticket according to the current ticketing mode: Per IP in IP mode and per vulnerability in Vulnerability mode.
70
+ * Initialize: This is the constructor that will take the implementation options and the service options. It should inherit from the base_helper class.
71
+ * create_ticket(tickets) - This method should implement the transport class for the 'foo' service (https, smtp, SOAP, etc).
72
+ * prepare_create_tickets(vulnerability_list, nexpose_identifier_id) - This method will take the vulnerability_list in CSV format and transform it into 'foo' accepted data (JSON, XML, etc). The implemented helpers group data into a single ticket according to the current ticketing mode: Per IP in IP mode and per vulnerability in Vulnerability mode.
60
73
 
61
74
  2. For full functionality (updating and closing tickets), also implement the following methods:
62
- * update_tickets(tickets) - This method should implement the transport class for the 'foo' service (https, smtp, SOAP, etc), to send updated ticket descriptions to the service for specific existing tickets.
63
- * prepare_update_tickets(vulnerability_list, nexpose_identifier_id) - This method will take the vulnerability_list in CSV format and transform it into 'foo' accepted data (JSON, XML, etc) for updating exisiting tickets.
64
- * close_tickets(tickets) - This method should implement the transport class for the 'foo' service (https, smtp, SOAP, etc), to send closure messages to the service for a specific exisiting ticket.
65
- * prepare_close_tickets(vulnerability_list, nexpose_identifier_id) - This method will take the vulnerability_list in CSV format and transform it into 'foo' accepted data (JSON, XML, etc) containing information about the tickets to close.
75
+ * update_tickets(tickets) - This method should implement the transport class for the 'foo' service (https, smtp, SOAP, etc), to send updated ticket descriptions to the service for specific existing tickets.
76
+ * prepare_update_tickets(vulnerability_list, nexpose_identifier_id) - This method will take the vulnerability_list in CSV format and transform it into 'foo' accepted data (JSON, XML, etc) for updating exisiting tickets.
77
+ * close_tickets(tickets) - This method should implement the transport class for the 'foo' service (https, smtp, SOAP, etc), to send closure messages to the service for a specific exisiting ticket.
78
+ * prepare_close_tickets(vulnerability_list, nexpose_identifier_id) - This method will take the vulnerability_list in CSV format and transform it into 'foo' accepted data (JSON, XML, etc) containing information about the tickets to close.
66
79
 
67
80
  3. A configuration file will be needed in the config folder for service specific options. This is loaded at the start of operation. Please refer to the existing configuration files, as certain options are common to all services.
68
81
 
@@ -77,6 +90,11 @@ We welcome contributions to this package. We ask only that pull requests and pat
77
90
 
78
91
  ## Changelog
79
92
 
93
+ ### 1.5.0
94
+ 16-05-17
95
+ Added an encryption configuration file.
96
+ Usernames and passwords within the configuration files are now encrypted when the application runs.
97
+
80
98
  ### 1.4.2
81
99
  10-05-17
82
100
 
@@ -1,13 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'yaml'
3
3
  require 'nexpose_ticketing'
4
- require 'nexpose_ticketing/nx_logger'
4
+ require 'nexpose_ticketing/utilities/nx_logger'
5
5
  require 'nexpose_ticketing/version'
6
6
  require 'optparse'
7
+ require_relative '../lib/nexpose_ticketing/utilities/config_parser'
7
8
 
8
9
  options = {}
9
10
  OptionParser.new do |opts|
10
- opts.banner = "Usage: nexpose_ticketing [service name]"
11
+ opts.banner = 'Usage: nexpose_ticketing [service name]'
11
12
  end.parse!
12
13
 
13
14
  if ARGV.count == 0
@@ -16,20 +17,23 @@ if ARGV.count == 0
16
17
  end
17
18
 
18
19
  system = ARGV.first
19
- config_path = File.join(File.dirname(__FILE__),
20
- "../lib/nexpose_ticketing/config/#{system}.config")
20
+ config_dir = File.join(File.dirname(__FILE__),
21
+ '../lib/nexpose_ticketing/config/')
22
+ config_path = File.join(config_dir, "#{system}.config")
23
+ service_config_path = File.join(config_dir, 'ticket_service.config')
21
24
 
22
25
  unless File.exists? config_path
23
26
  puts "Configuration file could not be found at #{config_path}"
24
27
  exit -1
25
28
  end
26
29
 
27
- # Read in JIRA options from jira.config.
28
- service_options = begin
29
- YAML.load_file(config_path)
30
- rescue ArgumentError => e
31
- raise "Could not parse YAML #{config_path} : #{e.message}"
32
- end
30
+ # We need to load the general config to get the encryption details location
31
+ # This is because the ticket gem uses two configs at a time
32
+ ticket_service = YAML.load_file(service_config_path)
33
+ enc_path = ticket_service[:encryption_options][:directory]
34
+
35
+ # Now we can load the config as normal
36
+ service_options = ConfigParser.get_config(config_path, enc_path)
33
37
 
34
38
  log = NexposeTicketing::NxLogger.instance
35
39
  log.setup_statistics_collection(service_options[:vendor],
@@ -37,9 +41,9 @@ log.setup_statistics_collection(service_options[:vendor],
37
41
  NexposeTicketing::VERSION)
38
42
  log.setup_logging(true, 'info')
39
43
 
40
- current_encoding = Encoding.default_external=Encoding.find("UTF-8")
44
+ current_encoding = Encoding.default_external=Encoding.find('UTF-8')
41
45
 
42
46
  log.log_message("Current Encoding set to: #{current_encoding}")
43
47
 
44
- # Initialize Ticket Service using JIRA.
48
+ # Initialize Ticket Service.
45
49
  NexposeTicketing.start(service_options)
@@ -0,0 +1,20 @@
1
+ #
2
+ # Symmetric Encryption for Ruby
3
+ #
4
+ ---
5
+ production:
6
+ # Since the encryption key must NOT be stored along with the
7
+ # source code, only store the key encryption key here.
8
+ private_rsa_key:
9
+
10
+ # List Symmetric Key Ciphers in the order of current / newest first
11
+ ciphers:
12
+ -
13
+ # Name of the file containing the encrypted key and iv.
14
+ key_filename: <absolute/path/to/filename>.key
15
+ iv_filename: <absolute/path/to/filename>.iv
16
+
17
+ cipher: aes-256-cbc
18
+ encoding: base64strict
19
+ version: 1
20
+ always_add_header: true
@@ -54,3 +54,8 @@
54
54
  :nxuser: nxadmin
55
55
  # (M) Nexpose password.
56
56
  :nxpasswd: nxadmin
57
+ # Encryption options
58
+ :encryption_options:
59
+ # (M) Path to the encryption.config file
60
+ :directory: ../../config/encryption.config
61
+
@@ -3,7 +3,7 @@ require 'net/http'
3
3
  require 'net/https'
4
4
  require 'uri'
5
5
  require 'csv'
6
- require 'nexpose_ticketing/nx_logger'
6
+ require 'nexpose_ticketing/utilities/nx_logger'
7
7
  require 'nexpose_ticketing/version'
8
8
  require_relative '../ticket_metrics'
9
9
 
@@ -3,7 +3,7 @@ require 'net/http'
3
3
  require 'net/https'
4
4
  require 'uri'
5
5
  require 'csv'
6
- require 'nexpose_ticketing/nx_logger'
6
+ require 'nexpose_ticketing/utilities/nx_logger'
7
7
  require 'nexpose_ticketing/version'
8
8
  require_relative './base_helper'
9
9
 
@@ -4,7 +4,7 @@ require 'net/https'
4
4
  require 'uri'
5
5
  require 'csv'
6
6
  require 'savon'
7
- require 'nexpose_ticketing/nx_logger'
7
+ require 'nexpose_ticketing/utilities/nx_logger'
8
8
  require 'nexpose_ticketing/version'
9
9
  require_relative './base_helper'
10
10
 
@@ -2,7 +2,7 @@ require 'net/http'
2
2
  require 'nokogiri'
3
3
  require 'dbm'
4
4
  require_relative './base_helper'
5
- require 'nexpose_ticketing/nx_logger'
5
+ require 'nexpose_ticketing/utilities/nx_logger'
6
6
  require 'nexpose_ticketing/version'
7
7
 
8
8
  class ServiceDeskHelper < BaseHelper
@@ -3,7 +3,7 @@ require 'net/http'
3
3
  require 'net/https'
4
4
  require 'uri'
5
5
  require 'csv'
6
- require 'nexpose_ticketing/nx_logger'
6
+ require 'nexpose_ticketing/utilities/nx_logger'
7
7
  require 'nexpose_ticketing/version'
8
8
  require_relative './base_helper'
9
9
  require 'securerandom'
@@ -1,4 +1,4 @@
1
- require 'nexpose_ticketing/nx_logger'
1
+ require 'nexpose_ticketing/utilities/nx_logger'
2
2
 
3
3
  class BaseMode
4
4
 
@@ -5,7 +5,7 @@ module NexposeTicketing
5
5
  require 'nexpose'
6
6
  require 'nexpose_ticketing/queries'
7
7
  require 'nexpose_ticketing/report_helper'
8
- require 'nexpose_ticketing/nx_logger'
8
+ require 'nexpose_ticketing/utilities/nx_logger'
9
9
  require 'nexpose_ticketing/version'
10
10
 
11
11
  API_VERSION = '1.2.0'
@@ -53,22 +53,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53
53
  require 'fileutils'
54
54
  require 'nexpose_ticketing/ticket_repository'
55
55
  require 'nexpose_ticketing'
56
- require 'nexpose_ticketing/nx_logger'
56
+ require 'nexpose_ticketing/utilities/nx_logger'
57
57
  require 'nexpose_ticketing/version'
58
58
  require 'nexpose_ticketing/store'
59
+ require_relative './utilities/config_parser'
59
60
 
60
- TICKET_SERVICE_CONFIG_PATH = File.join(File.dirname(__FILE__), '/config/ticket_service.config')
61
+ TICKET_SERVICE_CONFIG_PATH = File.join(File.dirname(__FILE__),
62
+ '/config/ticket_service.config')
61
63
  LOGGER_FILE = File.join(File.dirname(__FILE__), '/logs/ticket_service.log')
62
64
 
63
65
  attr_accessor :helper_data, :nexpose_data, :options, :ticket_repository, :first_time
64
66
 
65
67
  def setup(helper_data)
66
- # Gets the Ticket Service configuration.
67
- service_data = begin
68
- YAML.load_file(TICKET_SERVICE_CONFIG_PATH)
69
- rescue ArgumentError => e
70
- raise "Could not parse YAML #{TICKET_SERVICE_CONFIG_PATH} : #{e.message}"
71
- end
68
+ service_data = ConfigParser.get_config(TICKET_SERVICE_CONFIG_PATH)
72
69
 
73
70
  @helper_data = helper_data
74
71
  @nexpose_data = service_data[:nexpose_data]
@@ -0,0 +1,140 @@
1
+ require 'erb'
2
+ require 'yaml'
3
+ require 'fileutils'
4
+ require 'symmetric-encryption'
5
+
6
+ class ConfigParser
7
+ ENCRYPTED_FORMAT = '<%%= SymmetricEncryption.try_decrypt "%s" %%>'
8
+ PLACEHOLDER = '<absolute/path/to/filename>'
9
+ # The environment to use, defined within the encryption config
10
+ STANZA = 'production'
11
+ # The line width of the YAML file before line-wrapping occurs
12
+ WIDTH = 120
13
+
14
+ # Encrypts a configuration file and returns the unencrypted hash.
15
+ def self.get_config(config_path, enc_path=nil)
16
+ # Try to load a path from the provided config
17
+ custom_enc_path = get_enc_directory(config_path)
18
+ enc_path = custom_enc_path unless custom_enc_path.nil?
19
+
20
+ enc_path = File.expand_path(enc_path, __FILE__)
21
+ config_path = File.expand_path(config_path, __FILE__)
22
+
23
+ generate_keys(enc_path, config_path)
24
+ encrypt_config(enc_path, config_path)
25
+ decrypt_config(enc_path, config_path)
26
+ end
27
+
28
+ # Writes the YAML to file with custom formatting options
29
+ def self.save_config(config_details, config_path)
30
+ yaml = config_details.to_yaml(line_width: WIDTH)
31
+ File.open(config_path, 'w') {|f| f.write yaml }
32
+ end
33
+
34
+ def self.encrypt_field(value)
35
+ encrypted_value = SymmetricEncryption.encrypt value
36
+ ENCRYPTED_FORMAT % encrypted_value
37
+ end
38
+
39
+ # Retrieves the custom directory of the encryption config
40
+ def self.get_enc_directory(config_path)
41
+ settings = YAML.load_file(config_path)
42
+ return nil if settings[:encryption_options].nil?
43
+
44
+ enc_dir = settings[:encryption_options][:directory]
45
+ return nil if (enc_dir.nil? || enc_dir == '')
46
+
47
+ File.expand_path(enc_dir, __FILE__)
48
+ end
49
+
50
+ # Generates the RSA key, associated files and directories.
51
+ def self.generate_keys(enc_path, config_path)
52
+ settings = YAML.load_file(enc_path)
53
+ key = settings[STANZA]['private_rsa_key']
54
+
55
+ # Recognise an existing key
56
+ return unless (key.nil? || key == '')
57
+
58
+ # Generate a new RSA key and store the details
59
+ new_rsa_key = SymmetricEncryption::KeyEncryptionKey.generate
60
+ settings[STANZA]['private_rsa_key'] = new_rsa_key
61
+ save_config(settings, enc_path)
62
+
63
+ # Populate the placeholder values within the config
64
+ populate_ciphers(enc_path, config_path)
65
+
66
+ # Need to create a folder (specified by the user) to store the key files
67
+ dir = File.dirname(settings[STANZA]['ciphers'].first['key_filename'])
68
+
69
+ begin
70
+ unless File.directory?(dir) || PLACEHOLDER.include?(dir)
71
+ puts "Creating folder: #{dir}"
72
+ FileUtils::mkdir_p dir
73
+ end
74
+ rescue Exception => e
75
+ msg = "Unable to create the folders used to store encryption details.\n"\
76
+ 'Please ensure the user has permissions to create folders in the ' \
77
+ "path specified in the encryption config: #{enc_path}\n"
78
+ handle_error(msg, e)
79
+ end
80
+
81
+ SymmetricEncryption.generate_symmetric_key_files(enc_path, STANZA)
82
+ end
83
+
84
+ # Replace placeholder values for the key and iv file paths,
85
+ # placing them in the config folder by default.
86
+ def self.populate_ciphers(enc_path, config_path)
87
+ settings = YAML.load_file(enc_path)
88
+ ciphers = settings[STANZA]['ciphers'].first
89
+ config_folder = File.dirname(config_path)
90
+ config_name = File.basename(config_path, File.extname(config_path))
91
+
92
+ %w(key iv).each do |file|
93
+ label = "#{file}_filename"
94
+ file_path = ciphers[label]
95
+ next unless file_path.include? PLACEHOLDER
96
+
97
+ filename = ".#{config_name}.#{file}"
98
+ ciphers[label] = File.join(config_folder, filename)
99
+ end
100
+
101
+ save_config(settings, enc_path)
102
+ end
103
+
104
+ def self.encrypt_config(enc_path, config_path)
105
+ SymmetricEncryption.load!(enc_path, STANZA)
106
+
107
+ # Read the config in as an array of strings
108
+ f = File.open(config_path)
109
+ config_lines = f.readlines
110
+ f.close
111
+
112
+ # Define the regex that can find relevant fields
113
+ regex = /^(?<label>\s*:?\w*(passw|pwd|user|usr)\w*:?\s)(?<value>.*)$/
114
+
115
+ # Line by line, write the line to file, encrypting sensitive fields
116
+ File.open(config_path, 'w+') do |f|
117
+ config_lines.each do |l|
118
+ matches = l.match(regex)
119
+
120
+ # Encrypt fields with username/password labels that are in plaintext
121
+ unless matches.nil? || matches['value'].include?('SymmetricEncryption')
122
+ l = "#{matches['label']}#{encrypt_field(matches['value'])}"
123
+ end
124
+
125
+ f.puts l
126
+ end
127
+ end
128
+ end
129
+
130
+ # Returns a hash containing the decrypted details from a config file.
131
+ def self.decrypt_config(enc_path, config_path)
132
+ SymmetricEncryption.load!(enc_path, STANZA)
133
+ return YAML.load(ERB.new(File.new(config_path).read).result)
134
+ end
135
+
136
+ def self.handle_error(message, error)
137
+ puts message
138
+ raise error
139
+ end
140
+ end
@@ -1,3 +1,3 @@
1
1
  module NexposeTicketing
2
- VERSION = "1.4.2"
2
+ VERSION = '1.5.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexpose_ticketing
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Damian Finol
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-05-10 00:00:00.000000000 Z
14
+ date: 2017-05-16 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: nexpose
@@ -81,6 +81,26 @@ dependencies:
81
81
  - - ">="
82
82
  - !ruby/object:Gem::Version
83
83
  version: 1.1.2
84
+ - !ruby/object:Gem::Dependency
85
+ name: symmetric-encryption
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '3.9'
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 3.9.0
94
+ type: :runtime
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '3.9'
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 3.9.0
84
104
  - !ruby/object:Gem::Dependency
85
105
  name: rspec
86
106
  requirement: !ruby/object:Gem::Requirement
@@ -132,10 +152,10 @@ extra_rdoc_files:
132
152
  - README.md
133
153
  files:
134
154
  - Gemfile
135
- - Gemfile.lock
136
155
  - README.md
137
156
  - bin/nexpose_ticketing
138
157
  - lib/nexpose_ticketing.rb
158
+ - lib/nexpose_ticketing/config/encryption.config
139
159
  - lib/nexpose_ticketing/config/jira.config
140
160
  - lib/nexpose_ticketing/config/remedy.config
141
161
  - lib/nexpose_ticketing/config/remedy_wsdl/HPD_IncidentInterface_Create_WS.xml
@@ -153,13 +173,14 @@ files:
153
173
  - lib/nexpose_ticketing/modes/default_mode.rb
154
174
  - lib/nexpose_ticketing/modes/ip_mode.rb
155
175
  - lib/nexpose_ticketing/modes/vulnerability_mode.rb
156
- - lib/nexpose_ticketing/nx_logger.rb
157
176
  - lib/nexpose_ticketing/queries.rb
158
177
  - lib/nexpose_ticketing/report_helper.rb
159
178
  - lib/nexpose_ticketing/store.rb
160
179
  - lib/nexpose_ticketing/ticket_metrics.rb
161
180
  - lib/nexpose_ticketing/ticket_repository.rb
162
181
  - lib/nexpose_ticketing/ticket_service.rb
182
+ - lib/nexpose_ticketing/utilities/config_parser.rb
183
+ - lib/nexpose_ticketing/utilities/nx_logger.rb
163
184
  - lib/nexpose_ticketing/version.rb
164
185
  homepage: https://github.com/rapid7/nexpose_ticketing
165
186
  licenses:
@@ -181,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
202
  version: '0'
182
203
  requirements: []
183
204
  rubyforge_project:
184
- rubygems_version: 2.5.1
205
+ rubygems_version: 2.6.7
185
206
  signing_key:
186
207
  specification_version: 4
187
208
  summary: Ruby Nexpose Ticketing Engine.
@@ -1,69 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- nexpose_ticketing (1.3.0)
5
- nexpose (~> 3.1, >= 3.1.0)
6
- nokogiri (~> 1.6)
7
- savon (~> 2.1)
8
-
9
- GEM
10
- remote: https://rubygems.org/
11
- specs:
12
- akami (1.2.2)
13
- gyoku (>= 0.4.0)
14
- nokogiri
15
- builder (3.2.2)
16
- diff-lcs (1.2.5)
17
- gyoku (1.1.1)
18
- builder (>= 2.1.2)
19
- httpi (2.1.1)
20
- rack
21
- rubyntlm (~> 0.3.2)
22
- macaddr (1.7.1)
23
- systemu (~> 2.6.2)
24
- mini_portile2 (2.0.0)
25
- nexpose (3.3.0)
26
- nokogiri (1.6.7.2)
27
- mini_portile2 (~> 2.0.0.rc2)
28
- nori (2.4.0)
29
- rack (1.6.4)
30
- rspec (3.4.0)
31
- rspec-core (~> 3.4.0)
32
- rspec-expectations (~> 3.4.0)
33
- rspec-mocks (~> 3.4.0)
34
- rspec-core (3.4.4)
35
- rspec-support (~> 3.4.0)
36
- rspec-expectations (3.4.0)
37
- diff-lcs (>= 1.2.0, < 2.0)
38
- rspec-support (~> 3.4.0)
39
- rspec-mocks (3.4.1)
40
- diff-lcs (>= 1.2.0, < 2.0)
41
- rspec-support (~> 3.4.0)
42
- rspec-support (3.4.1)
43
- rubyntlm (0.3.4)
44
- savon (2.5.1)
45
- akami (~> 1.2.0)
46
- builder (>= 2.1.2)
47
- gyoku (~> 1.1.0)
48
- httpi (~> 2.1.0)
49
- nokogiri (>= 1.4.0)
50
- nori (~> 2.4.0)
51
- uuid (~> 2.3.7)
52
- wasabi (~> 3.3.0)
53
- systemu (2.6.5)
54
- uuid (2.3.8)
55
- macaddr (~> 1.0)
56
- wasabi (3.3.1)
57
- httpi (~> 2.0)
58
- nokogiri (>= 1.4.0)
59
-
60
- PLATFORMS
61
- ruby
62
-
63
- DEPENDENCIES
64
- nexpose_ticketing!
65
- rspec (~> 3.2, >= 3.2.0)
66
- rspec-mocks (~> 3.2, >= 3.2.0)
67
-
68
- BUNDLED WITH
69
- 1.12.5