varanus 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3f1e3b8a3c5d8b1999ab00642afaef76bfa69be3872b9af2ab91af9aa4731bc
4
- data.tar.gz: bf2cd9f9449d290133f6a8f21a5c64fb5541d42c6349b0179eaa85af153bf3e9
3
+ metadata.gz: 9495d1c66215f0313068a30921d24545643441237139ced9220570e16b771b0f
4
+ data.tar.gz: cb104ae0cc2e2b8269e0d8914e90978870f402a386e2d9064e542e757fcab188
5
5
  SHA512:
6
- metadata.gz: 6890038fac5dfa28e212cdb119d16ff35bfa5344359df100076ddd533f5226b3b4c00f8302442d24c27ecdd233d9e23991d37ac3ca6400066ff050f168937d2a
7
- data.tar.gz: df2e85079624160c161e8d8849c97c0e7287f5e89585dd3a1f9fa2c6fddd100876b72b6fff6e0dc3c028090c7830835c047d8bd22ffbb477c6935ed19d857496
6
+ metadata.gz: 8415fc14216976c5e989d82e676fdbf25868ab2dfe55b645a85b43f162f60e1029a2a68d8f72fe9acd14a2d911e708402ca6160c6a101e2d0e3f233484a8ab05
7
+ data.tar.gz: 87710705995b46e27314aad6e4eadce44fab7ca7b3e4515cb91b1c65edfe0c85a542c5e2fafb59e39d32f30b563c13bb8d125c9a9d1156c4c8b1dbce82009945
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /test.rb
data/.rubocop.yml CHANGED
@@ -28,23 +28,12 @@ Naming/FileName:
28
28
  Exclude:
29
29
  - Gemfile
30
30
 
31
- Naming/UncommunicativeMethodParamName:
32
- AllowedNames:
33
- - gb
34
- - id
35
- - ip
36
- - os
37
- - vm
38
-
39
31
  Style/ClassAndModuleChildren:
40
- Enabled: false
32
+ EnforcedStyle: compact
41
33
 
42
34
  Style/ConditionalAssignment:
43
35
  Enabled: false
44
36
 
45
- Style/FrozenStringLiteralComment:
46
- Enabled: false
47
-
48
37
  Style/MethodDefParentheses:
49
38
  EnforcedStyle: require_no_parentheses_except_multiline
50
39
 
@@ -57,14 +46,5 @@ Style/RescueModifier:
57
46
  Style/SymbolArray:
58
47
  EnforcedStyle: brackets
59
48
 
60
- Style/TrailingCommaInArguments:
61
- EnforcedStyleForMultiline: no_comma
62
-
63
- Style/TrailingCommaInArrayLiteral:
64
- EnforcedStyleForMultiline: no_comma
65
-
66
- Style/TrailingCommaInHashLiteral:
67
- EnforcedStyleForMultiline: no_comma
68
-
69
49
  Style/WordArray:
70
50
  EnforcedStyle: brackets
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ ### 0.2.0 (2018-11-09)
2
+ * Added Varanus::SSL::CSR.generate
3
+ * Added Reports
4
+ * Varanus::Reports#ssl - list of SSL/TLS certs
5
+ * Varanus::Reports#domains - list of domains validated with DCV
6
+
7
+ ### 0.1.0 (2018-11-07)
8
+ * Initial release
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
data/Gemfile.lock CHANGED
@@ -1,16 +1,21 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- varanus (0.1.0)
4
+ varanus (0.2.0)
5
5
  faraday
6
6
  faraday_middleware
7
+ savon (~> 2.0)
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
10
11
  specs:
11
12
  addressable (2.5.2)
12
13
  public_suffix (>= 2.0.2, < 4.0)
14
+ akami (1.3.1)
15
+ gyoku (>= 0.4.0)
16
+ nokogiri
13
17
  ast (2.4.0)
18
+ builder (3.2.3)
14
19
  crack (0.4.3)
15
20
  safe_yaml (~> 1.0.0)
16
21
  docile (1.3.1)
@@ -18,21 +23,31 @@ GEM
18
23
  multipart-post (>= 1.2, < 3)
19
24
  faraday_middleware (0.12.2)
20
25
  faraday (>= 0.7.4, < 1.0)
26
+ gyoku (1.3.1)
27
+ builder (>= 2.1.2)
21
28
  hashdiff (0.3.7)
29
+ httpi (2.4.4)
30
+ rack
31
+ socksify
22
32
  jaro_winkler (1.5.1)
23
33
  json (2.1.0)
24
34
  metaclass (0.0.4)
35
+ mini_portile2 (2.3.0)
25
36
  minitest (5.11.3)
26
37
  minitest-rg (5.2.0)
27
38
  minitest (~> 5.0)
28
39
  mocha (1.7.0)
29
40
  metaclass (~> 0.0.1)
30
41
  multipart-post (2.0.0)
42
+ nokogiri (1.8.5)
43
+ mini_portile2 (~> 2.3.0)
44
+ nori (2.6.0)
31
45
  parallel (1.12.1)
32
46
  parser (2.5.3.0)
33
47
  ast (~> 2.4.0)
34
48
  powerpack (0.1.2)
35
49
  public_suffix (3.0.3)
50
+ rack (2.0.6)
36
51
  rainbow (3.0.0)
37
52
  rake (10.5.0)
38
53
  rubocop (0.60.0)
@@ -45,12 +60,24 @@ GEM
45
60
  unicode-display_width (~> 1.4.0)
46
61
  ruby-progressbar (1.10.0)
47
62
  safe_yaml (1.0.4)
63
+ savon (2.12.0)
64
+ akami (~> 1.2)
65
+ builder (>= 2.1.2)
66
+ gyoku (~> 1.2)
67
+ httpi (~> 2.3)
68
+ nokogiri (>= 1.8.1)
69
+ nori (~> 2.4)
70
+ wasabi (~> 3.4)
48
71
  simplecov (0.16.1)
49
72
  docile (~> 1.1)
50
73
  json (>= 1.8, < 3)
51
74
  simplecov-html (~> 0.10.0)
52
75
  simplecov-html (0.10.2)
76
+ socksify (1.7.1)
53
77
  unicode-display_width (1.4.0)
78
+ wasabi (3.5.0)
79
+ httpi (~> 2.0)
80
+ nokogiri (>= 1.4.2)
54
81
  webmock (3.4.2)
55
82
  addressable (>= 2.3.6)
56
83
  crack (>= 0.3.2)
data/README.md CHANGED
@@ -7,24 +7,29 @@ Support for Sectigo's other APIs (S/MIME, code signing, device certificates, etc
7
7
  be added at a later date. Merge requests to add some of this functionality would be
8
8
  greatly appreciated.
9
9
 
10
- ## Installation
10
+ [![Build Status](https://travis-ci.org/duke-automation/varanus.svg?branch=master)](https://travis-ci.org/duke-automation/varanus)
11
+ [![Gem Version](https://badge.fury.io/rb/varanus.svg)](http://badge.fury.io/rb/varanus)
12
+ [![Maintainability](https://api.codeclimate.com/v1/badges/593ef1aa2ba757b5374f/maintainability)](https://codeclimate.com/github/duke-automation/varanus/maintainability)
13
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/593ef1aa2ba757b5374f/test_coverage)](https://codeclimate.com/github/duke-automation/varanus/test_coverage)
11
14
 
12
- Add this line to your application's Gemfile:
15
+ ## Usage
16
+
17
+ #### Generate and sign SSL cert
13
18
 
14
19
  ```ruby
15
- gem 'varanus'
20
+ key, csr = Varanus::SSL::CSR.generate(['example.com'])
21
+ varanus = Varanus.new(customer_uri, username, password)
22
+ id = varanus.ssl.sign csr, org_id
23
+ begin
24
+ cert = varanus.ssl.collect id
25
+ rescue Varanus::Error::StillProcessing
26
+ sleep 1
27
+ retry
28
+ end
29
+ puts key
30
+ puts cert
16
31
  ```
17
32
 
18
- And then execute:
19
-
20
- $ bundle
21
-
22
- Or install it yourself as:
23
-
24
- $ gem install varanus
25
-
26
- ## Usage
27
-
28
33
  #### Sign SSL cert from CSR
29
34
 
30
35
  ```ruby
@@ -46,6 +51,18 @@ puts cert
46
51
  Varanus.new(customer_uri, username, password).ssl.revoke(id)
47
52
  ```
48
53
 
54
+ #### Reports
55
+
56
+ Report on all SSL certs
57
+ ```ruby
58
+ pp Varanus.new(customer_uri, usernams, password).reports.ssl
59
+ ```
60
+
61
+ Report on all domains (DCV status)
62
+ ```ruby
63
+ pp Varanus.new(customer_uri, usernams, password).reports.domains
64
+ ```
65
+
49
66
  #### Authentication
50
67
 
51
68
  Authentication requires the same credentials you use to login to cert-manager.com as well as the ```customer_uri```. If your URL to log into cert-manager.com is https://cert-manager.com/customer/MyCompany then your ```customer_uri``` will be ```'MyCompany'```
@@ -56,6 +73,22 @@ Signing a cert requires specifying an ```org_id```. Each department in cert-man
56
73
 
57
74
  To find the ```org_id```, log into cert-manager.com, go to **Settings** -> **Departments**, then click to edit the department you are interested in. The value you want is in the **OrgID** field.
58
75
 
76
+ ## Installation
77
+
78
+ Add this line to your application's Gemfile:
79
+
80
+ ```ruby
81
+ gem 'varanus'
82
+ ```
83
+
84
+ And then execute:
85
+
86
+ $ bundle
87
+
88
+ Or install it yourself as:
89
+
90
+ $ gem install varanus
91
+
59
92
  ## Development
60
93
 
61
94
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rake/testtask'
3
5
 
data/bin/console CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'bundler/setup'
4
5
  require 'varanus'
data/lib/varanus/error.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Error returned from the Sectigo API
2
4
  class Varanus::Error < StandardError
3
5
  # @return [Integer] Code associated with error
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ # An connection to the Reports API. This should not be initialized directly. Instead,
4
+ # use Varanus#reports
5
+ class Varanus::Reports
6
+ SSL_CERT_STATUSES = {
7
+ any: 0,
8
+ requested: 1,
9
+ downloaded: 2,
10
+ revoked: 3,
11
+ expired: 4,
12
+ pending_download: 5,
13
+ not_enrolled: 6
14
+ }.freeze
15
+
16
+ # @note Do not call this directly. Use {Varanus#reports} to initialize
17
+ def initialize varanus
18
+ @varanus = varanus
19
+ end
20
+
21
+ def domains
22
+ r = soap_call :get_domain_report, {}
23
+ format_results r[:report_row_domains]
24
+ end
25
+
26
+ # Return report on SSL request
27
+ # @param [opts] [Hash]
28
+ # @option opts [String, Array] :orgs Name(s) of organizations (departments) to limit
29
+ # the report to. If this is unset, results from all departments are returned.
30
+ # @option opts [Symbol] :status (:any) One of :any, :requested, :downloaded, :revoked,
31
+ # :expired, :pending_download, :not_enrolled. :downloaded and :pending_download
32
+ # mean the cert has been enrolled/signed.
33
+ # @return [Array<Hash>]
34
+ def ssl opts = {}
35
+ msg = { organizationNames: nil, certificateStatus: 0 }
36
+
37
+ msg[:organizationNames] = Array(opts[:orgs]).join(',') if opts.include? :orgs
38
+ if opts.include? :status
39
+ msg[:certificateStatus] = SSL_CERT_STATUSES[opts[:status]]
40
+ raise ArgumentError, 'Invalid status' if msg[:certificateStatus].nil?
41
+ end
42
+
43
+ r = soap_call :get_SSL_report, msg
44
+ format_results r[:reports]
45
+ end
46
+
47
+ private
48
+
49
+ def format_results results
50
+ if results.is_a? Hash
51
+ [results]
52
+ else
53
+ results.to_a
54
+ end
55
+ end
56
+
57
+ def savon
58
+ @savon ||= Savon.client(
59
+ namespace: 'http://report.ws.epki.comodo.com/',
60
+ endpoint: 'https://cert-manager.com:443/ws/ReportService',
61
+ log: false
62
+ )
63
+ end
64
+
65
+ def soap_call func, opts = {}
66
+ msg = opts.dup
67
+ msg[:authData] = { customerLoginUri: @varanus.customer_uri, login: @varanus.username,
68
+ password: @varanus.password }
69
+
70
+ result = savon.call func, message: msg
71
+ result.body[(func.to_s.downcase + '_response').to_sym][:return]
72
+ end
73
+ end
@@ -1,23 +1,65 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Wrapper class around a OpenSSL::X509::Request
2
4
  # Provides helper functions to make reading information from the CSR easier
3
5
  class Varanus::SSL::CSR
6
+ # Key size used when calling {.generate}
7
+ DEFAULT_KEY_SIZE = 4096
8
+
9
+ # Generate a CSR
10
+ # @param names [Array<String>] List of DNS names. The first one will be the CN
11
+ # @param key [OpenSSL::PKey::RSA, OpenSSL::PKey::DSA, nil] Secret key for the cert.
12
+ # A DSA key will be generated if +nil+ is passed in.
13
+ # @param subject [Hash] Options for the subject of the cert. By default only CN will
14
+ # be set
15
+ # @return [Array(OpenSSL::PKey::PKey, Varanus::SSL::CSR)] The private key for the cert
16
+ # and CSR
17
+ def self.generate names, key = nil, subject = {}
18
+ raise ArgumentError, 'names cannot be empty' if names.empty?
19
+
20
+ subject = subject.dup
21
+ subject['CN'] = names.first
22
+
23
+ key ||= OpenSSL::PKey::DSA.new(DEFAULT_KEY_SIZE)
24
+
25
+ request = OpenSSL::X509::Request.new
26
+ request.version = 0
27
+ request.subject = OpenSSL::X509::Name.parse subject.map { |k, v| "/#{k}=#{v}" }.join
28
+
29
+ # Set Subject Alternate Names
30
+ ef = OpenSSL::X509::ExtensionFactory.new
31
+ name_str = names.map { |n| "DNS:#{n}" }.join(', ')
32
+ ext = ef.create_extension('subjectAltName', name_str, false)
33
+ seq = OpenSSL::ASN1::Sequence([ext])
34
+ ext_req = OpenSSL::ASN1::Set([seq])
35
+ request.add_attribute OpenSSL::X509::Attribute.new('extReq', ext_req)
36
+
37
+ request.public_key = key.public_key
38
+ request.sign(key, OpenSSL::Digest::SHA256.new)
39
+ [key, Varanus::SSL::CSR.new(request)]
40
+ end
41
+
4
42
  # Common Name (CN) for cert.
5
43
  # @return [String]
6
44
  attr_reader :cn
7
45
 
46
+ # OpenSSL::X509::Request representation of CSR
47
+ # @return [OpenSSL::X509::Request]
48
+ attr_reader :request
49
+
8
50
  # @param csr [String, OpenSSL::X509::Request]
9
51
  def initialize csr
10
52
  if csr.is_a? OpenSSL::X509::Request
11
- @req = csr
53
+ @request = csr
12
54
  @text = csr.to_s
13
55
  else
14
56
  @text = csr.to_s
15
- @req = OpenSSL::X509::Request.new @text
57
+ @request = OpenSSL::X509::Request.new @text
16
58
  end
17
59
 
18
- raise 'Improperly signed CSR' unless @req.verify @req.public_key
60
+ raise 'Improperly signed CSR' unless @request.verify @request.public_key
19
61
 
20
- cn_ref = @req.subject.to_a.find { |a| a[0] == 'CN' }
62
+ cn_ref = @request.subject.to_a.find { |a| a[0] == 'CN' }
21
63
  @cn = cn_ref && cn_ref[1].downcase
22
64
 
23
65
  _parse_sans
@@ -35,13 +77,13 @@ class Varanus::SSL::CSR
35
77
  # Key size for the cert
36
78
  # @return [Integer]
37
79
  def key_size
38
- case @req.public_key
80
+ case @request.public_key
39
81
  when OpenSSL::PKey::RSA
40
- @req.public_key.n.num_bytes * 8
82
+ @request.public_key.n.num_bytes * 8
41
83
  when OpenSSL::PKey::DSA
42
- @req.public_key.p.num_bytes * 8
84
+ @request.public_key.p.num_bytes * 8
43
85
  else
44
- raise "Unknown public key type: #{@req.public_key.class}"
86
+ raise "Unknown public key type: #{@request.public_key.class}"
45
87
  end
46
88
  end
47
89
 
@@ -59,7 +101,7 @@ class Varanus::SSL::CSR
59
101
  private
60
102
 
61
103
  def _parse_sans
62
- extensions = @req.attributes.select { |at| at.oid == 'extReq' }
104
+ extensions = @request.attributes.select { |at| at.oid == 'extReq' }
63
105
  sans_extensions = extensions.flat_map do |extension|
64
106
  extension.value.value[0].value
65
107
  .select { |ext| ext.first.value == 'subjectAltName' }
data/lib/varanus/ssl.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # An connection to the SSL/TSL API. This should not be initialized directly. Instead,
2
4
  # use Varanus#ssl
3
5
  class Varanus::SSL
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Varanus
2
- VERSION = '0.1.0'.freeze
4
+ VERSION = '0.2.0'
3
5
  end
data/lib/varanus.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Interface for Sectigo's (formerly Comodo CA) API.
2
4
  class Varanus
3
5
  attr_reader :customer_uri, :username, :password
@@ -12,6 +14,12 @@ class Varanus
12
14
  @password = password
13
15
  end
14
16
 
17
+ # Retrieve Reports instance
18
+ # @return [Varanus::Reports]
19
+ def reports
20
+ @reports ||= Reports.new(self)
21
+ end
22
+
15
23
  # Retrive SSL instance
16
24
  # @return [Varanus::SSL]
17
25
  def ssl
@@ -23,9 +31,11 @@ end
23
31
  require 'faraday'
24
32
  require 'faraday_middleware'
25
33
  require 'openssl'
34
+ require 'savon'
26
35
 
27
36
  # Require other files in this gem
28
37
  require 'varanus/error'
38
+ require 'varanus/reports'
29
39
  require 'varanus/ssl'
30
40
  require 'varanus/ssl/csr'
31
41
  require 'varanus/version'
data/varanus.gemspec CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  lib = File.expand_path('lib', __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require 'varanus/version'
@@ -40,5 +42,6 @@ Gem::Specification.new do |spec|
40
42
 
41
43
  spec.add_runtime_dependency 'faraday'
42
44
  spec.add_runtime_dependency 'faraday_middleware'
45
+ spec.add_runtime_dependency 'savon', '~> 2.0'
43
46
  end
44
47
  # rubocop:enable Metrics/BlockLength
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: varanus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Dilda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-07 00:00:00.000000000 Z
11
+ date: 2018-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: savon
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '2.0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '2.0'
167
181
  description: |
168
182
  This gem provides an interface to Sectigo's (formerly Comodo CA) APIs for working
169
183
  with SSL/TLS certificates as well as its reporting API.
@@ -180,6 +194,7 @@ files:
180
194
  - ".gitignore"
181
195
  - ".rubocop.yml"
182
196
  - ".travis.yml"
197
+ - CHANGELOG.md
183
198
  - Gemfile
184
199
  - Gemfile.lock
185
200
  - LICENSE.txt
@@ -190,6 +205,7 @@ files:
190
205
  - docker-compose.yml
191
206
  - lib/varanus.rb
192
207
  - lib/varanus/error.rb
208
+ - lib/varanus/reports.rb
193
209
  - lib/varanus/ssl.rb
194
210
  - lib/varanus/ssl/csr.rb
195
211
  - lib/varanus/version.rb