varanus 0.1.0 → 0.2.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
  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