dsv-sdk 0.0.4 → 0.0.6.pre.dev

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: 7852bac952052c86909bbefa031d64af43920e7658fe522b962bff8515a1f711
4
- data.tar.gz: 716caf976f0b6b90923162a07210076ad4f5acd70f246592809e5452e55caa93
3
+ metadata.gz: ef58849c45425870cb24105d3399712dffc14fe46cbcfc384062acddd34dbb63
4
+ data.tar.gz: 963dabfba1bad411711c8c95aab628477fafff699cb3a381ffeb38be3abeeeb0
5
5
  SHA512:
6
- metadata.gz: 38b4142bcf7412b4213120580ecfc12475c4de2d6b904d33848fe3a7b0e6e22fee8f52b58d5aaacff138342d7c6389fd039fca7e723eb2d910e393fe9125e441
7
- data.tar.gz: 3b4e130e8f7c73e3d61640253f46a86e709f33f12d8e5bbde1849e3717f410f398617fa8349fa0c389715992388d78677e991ceb6eaf3e4c8673576ce7ac4ab7
6
+ metadata.gz: dba5aa908ff38e851778cd0664ac14e5fb568a54aaecf97a96ffbc583c04317d01450ce204c409aab763a459bfba2c906e49c2d4d48aa916364456ab0efba1e0
7
+ data.tar.gz: 1c101637a50f07ba426f197a10a9d90ba2c185305abafd4f85f1df2e530b1265aa876579ad4b5745287f882360f1c84521d5ed2af995e91b3e543afbb421af40
@@ -0,0 +1,189 @@
1
+ require 'json'
2
+ require 'faraday'
3
+ require 'logger'
4
+
5
+ ##
6
+ # If we're in the +test+ environment just dump logs to Null
7
+ # Otherwise, use stdout
8
+ if ENV['test']
9
+ $logger = Logger.new(IO::NULL)
10
+ else
11
+ $logger = Logger.new(STDOUT)
12
+ end
13
+
14
+ ##
15
+ # Invoked when the API returns an +API_AccessDenied+ error
16
+ class AccessDeniedException < StandardError; end;
17
+ class ResourceNotFoundException < StandardError; end;
18
+ class InvalidConfigurationException < StandardError; end;
19
+ class InvalidCredentialsException < StandardError; end;
20
+ class InvalidMethodTypeException < StandardError; end;
21
+ class UnrecognizedResourceException < StandardError; end;
22
+
23
+
24
+ module Dsv
25
+ require_relative 'dsv/client'
26
+ require_relative 'dsv/secret'
27
+ require_relative 'dsv/role'
28
+
29
+ class Vault
30
+ DEFAULT_URL_TEMPLATE = "https://%s.secretsvaultcloud.%s/v1/%s%s"
31
+ DEFAULT_TLD = "com"
32
+
33
+ # Initialize a +Vault+ object with provided configuration.
34
+ #
35
+ # @param config [Hash]
36
+ # - client_id: ''
37
+ # - client_secret: ''
38
+ # - tld: 'com'
39
+ # - tenant: ''
40
+ def initialize(config = nil)
41
+
42
+ unless config.nil?
43
+ @configuration = config.collect{|k,v| [k.to_s, v]}.to_h
44
+ else
45
+ @configuration = {}
46
+
47
+ @configuration['client_id'] = ENV['DSV_CLIENT_ID']
48
+ @configuration['client_secret'] = ENV['DSV_CLIENT_SECRET']
49
+ @configuration['tenant'] = ENV['DSV_TENANT']
50
+ @configuration['tld'] = ENV['DSV_TLD']
51
+ end
52
+
53
+ if @configuration['client_id'].nil? || @configuration['client_secret'].nil?
54
+ $logger.error("Must provide client_id and client_secret")
55
+ raise InvalidConfigurationException
56
+ end
57
+
58
+ $logger.debug("Vault is configured for client_id: #{@configuration['client_id']}")
59
+ end
60
+
61
+ # Helper method to access a resource via API
62
+ #
63
+ # @param method [String] HTTP Request Method
64
+ # @param resource [String] The resource type to invoke
65
+ # @param path [String] The API Path to request
66
+ # @param input [String] Input to send via POST/PUT body
67
+ #
68
+ # @return [Hash] - return Hash of JSON contents
69
+ #
70
+ # - +AccessDeniedException+ is raised if the server responds with an +API_AccessDenied+ error
71
+ # - +InvalidMethodTypeException+ is raised if a method other than +["GET", "POST", "PUT", "DELETE"]+ is provided
72
+ # - +UnrecognizedResourceException+ is raised if a resource other than +["clients", "roles", "secrets"]+ is requested
73
+ def accessResource(method, resource, path, input, parse_json=true)
74
+ unless ["GET", "POST", "PUT", "DELETE"].include?(method.upcase)
75
+ $logger.error "Invalid request method: #{method}"
76
+ raise InvalidMethodTypeException
77
+ end
78
+
79
+ unless ["clients", "roles", "secrets"].include? resource
80
+ message = "unrecognized resource"
81
+ $logger.debug "#{message}, #{resource}"
82
+
83
+ raise UnrecognizedResourceException
84
+ end
85
+
86
+ body = ""
87
+
88
+ unless input.nil?
89
+ body = input.to_json
90
+ end
91
+
92
+ accessToken = getAccessToken
93
+
94
+ # Yikes, normally not a fan of metaprogramming
95
+ # We first ensured that `method` is legit to prevent
96
+ # arbitrary method invocation
97
+ url = urlFor(resource, path)
98
+ $logger.debug "Sending request to: #{url}"
99
+ resp = Faraday.send(method.downcase, url) do | req |
100
+ req.headers['Authorization'] = "Bearer #{accessToken}"
101
+ req.body = body unless body.empty?
102
+
103
+ if ["POST", "PUT"].include?(method.upcase)
104
+ req.headers['Content-Type'] = 'application/json'
105
+ end
106
+ end
107
+
108
+ data = resp.body
109
+
110
+ return data unless parse_json
111
+
112
+ begin
113
+ hash = JSON.parse(data)
114
+
115
+ if hash['errorCode'] == "API_AccessDenied"
116
+ raise AccessDeniedException
117
+ end
118
+
119
+ if hash['message'] == "Invalid permissions"
120
+ raise AccessDeniedException
121
+ end
122
+
123
+ if hash['code'] == 404
124
+ raise ResourceNotFoundException
125
+ end
126
+
127
+ rescue JSON::ParserError => e
128
+ $logger.error "Error parsing JSON: #{e.to_s}"
129
+ raise e
130
+ end
131
+
132
+ return hash
133
+ end
134
+
135
+ # Query API for OAuth token
136
+ #
137
+ # - +InvalidCredentialsException+ is returned if the provided credentials are not valid
138
+ #
139
+ # @return [String]
140
+ def getAccessToken
141
+ grantRequest = {
142
+ grant_type: "client_credentials",
143
+ client_id: @configuration['client_id'],
144
+ client_secret: @configuration['client_secret']
145
+ }.to_json
146
+
147
+ url = urlFor("token")
148
+
149
+ $logger.debug "calling #{url} with client_id #{@configuration['client_id']}"
150
+
151
+ response = Faraday.post(
152
+ url,
153
+ grantRequest,
154
+ "Content-Type" => "application/json"
155
+ )
156
+
157
+ unless response.status == 200
158
+ $logger.debug "grant response error: #{response.body}"
159
+ raise InvalidCredentialsException
160
+ end
161
+
162
+ begin
163
+ grant = JSON.parse(response.body)
164
+ return grant['accessToken']
165
+ rescue JSON::ParserError => e
166
+ $logger.error "Error parsing JSON: #{e.to_s}"
167
+ raise e
168
+ end
169
+ end
170
+
171
+ # Generate the URL for a specific request.
172
+ # This factors in several configuration options including:
173
+ # - +tenant+
174
+ # - +tld+
175
+ #
176
+ # @param resource [String] The specific API resource to request
177
+ # @param path [String] The path to the resource
178
+ #
179
+ # @return [String] The generated URL for the request
180
+ def urlFor(resource, path=nil)
181
+
182
+ if path != nil
183
+ path = "/#{path.delete_prefix("/")}"
184
+ end
185
+
186
+ sprintf(DEFAULT_URL_TEMPLATE, @configuration['tenant'], @configuration['tld'] || DEFAULT_TLD, resource, path)
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,35 @@
1
+ module Dsv
2
+ class Client
3
+ CLIENTS_RESOURCE = "clients".freeze
4
+
5
+ # Fetch desired client information from the specified Vault
6
+ #
7
+ # @param vault [Vault] The initialized Vault
8
+ # @param id [String] The ID of the client
9
+ #
10
+ # @return client [Hash]
11
+ def self.fetch(vault, id)
12
+ @vault = vault
13
+ client = @vault.accessResource("GET", CLIENTS_RESOURCE, id, nil)
14
+ end
15
+
16
+ # Mark the client as ready to be removed
17
+ #
18
+ # @param vault [Vault] The initialized Vault
19
+ # @param id [String] The ID of the client
20
+ def self.delete(vault, id)
21
+ vault.accessResource("DELETE", CLIENTS_RESOURCE, id, nil, nil)
22
+ end
23
+
24
+ # Create the client for the desired Vault
25
+ #
26
+ # @param vault [Vault] The initialized Vault
27
+ # @param role_Name [String] Name of the role to create
28
+ def self.create(vault, role_name)
29
+ client_data = {
30
+ role: role_name
31
+ }
32
+ vault.accessResource("POST", CLIENTS_RESOURCE, "/", client_data)
33
+ end
34
+ end
35
+ end
@@ -1,5 +1,5 @@
1
- require './lib/vault.rb'
2
- class Vault::Role
1
+ module Dsv
2
+ class Role
3
3
  ROLES_RESOURCE = "roles".freeze
4
4
 
5
5
  # Return the specified role
@@ -13,4 +13,5 @@ class Vault::Role
13
13
 
14
14
  role = @vault.accessResource("GET", ROLES_RESOURCE, name, nil)
15
15
  end
16
- end
16
+ end
17
+ end
@@ -1,6 +1,5 @@
1
-
2
- # Utilized to fetch secrets from an initialzed +Vault+
3
- class Vault::Secret
1
+ module Dsv
2
+ class Secret
4
3
  SECRETS_RESOURCE = "secrets".freeze
5
4
 
6
5
  # Fetch secrets from the server
@@ -14,4 +13,5 @@ class Vault::Secret
14
13
 
15
14
  @secret = @vault.accessResource("GET", SECRETS_RESOURCE, path, nil)
16
15
  end
17
- end
16
+ end
17
+ end
metadata CHANGED
@@ -1,16 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dsv-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.6.pre.dev
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Poulin
8
- - Adam Migus
9
- autorequire:
8
+ autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
11
  date: 2020-04-08 00:00:00.000000000 Z
13
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: logger
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
14
55
  - !ruby/object:Gem::Dependency
15
56
  name: rspec
16
57
  requirement: !ruby/object:Gem::Requirement
@@ -26,24 +67,21 @@ dependencies:
26
67
  - !ruby/object:Gem::Version
27
68
  version: '3.7'
28
69
  description: The Thycotic DevOps Secrets Vault SDK for Ruby
29
- email:
30
- - john.m.poulin@gmail.com
31
- - adam@migus.org
70
+ email: john.m.poulin@gmail.com
32
71
  executables: []
33
72
  extensions: []
34
73
  extra_rdoc_files: []
35
74
  files:
36
- - lib/vault.rb
37
- - lib/vault/client.rb
38
- - lib/vault/role.rb
39
- - lib/vault/secret.rb
40
- - lib/vault/vault.rb
41
- homepage: https://rubygems.org/gems/hola
75
+ - lib/dsv.rb
76
+ - lib/dsv/client.rb
77
+ - lib/dsv/role.rb
78
+ - lib/dsv/secret.rb
79
+ homepage: https://github.com/thycotic/dsv-sdk-ruby
42
80
  licenses:
43
81
  - Apache-2.0
44
82
  metadata:
45
83
  github_repo: ssh://github.com/thycotic/dsv-sdk-ruby
46
- post_install_message:
84
+ post_install_message:
47
85
  rdoc_options: []
48
86
  require_paths:
49
87
  - lib
@@ -54,12 +92,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
54
92
  version: '0'
55
93
  required_rubygems_version: !ruby/object:Gem::Requirement
56
94
  requirements:
57
- - - ">="
95
+ - - ">"
58
96
  - !ruby/object:Gem::Version
59
- version: '0'
97
+ version: 1.3.1
60
98
  requirements: []
61
- rubygems_version: 3.0.3
62
- signing_key:
99
+ rubygems_version: 3.0.8
100
+ signing_key:
63
101
  specification_version: 4
64
- summary: dsv-sdk
102
+ summary: dsv_sdk
65
103
  test_files: []
@@ -1,7 +0,0 @@
1
- class Vault
2
- require 'vault/vault'
3
-
4
- require 'vault/client'
5
- require 'vault/secret'
6
- require 'vault/role'
7
- end
@@ -1,33 +0,0 @@
1
- class Vault::Client
2
- CLIENTS_RESOURCE = "clients".freeze
3
-
4
- # Fetch desired client information from the specified Vault
5
- #
6
- # @param vault [Vault] The initialized Vault
7
- # @param id [String] The ID of the client
8
- #
9
- # @return client [Hash]
10
- def self.fetch(vault, id)
11
- @vault = vault
12
- client = @vault.accessResource("GET", CLIENTS_RESOURCE, id, nil)
13
- end
14
-
15
- # Mark the client as ready to be removed
16
- #
17
- # @param vault [Vault] The initialized Vault
18
- # @param id [String] The ID of the client
19
- def self.delete(vault, id)
20
- vault.accessResource("DELETE", CLIENTS_RESOURCE, id, nil, nil)
21
- end
22
-
23
- # Create the client for the desired Vault
24
- #
25
- # @param vault [Vault] The initialized Vault
26
- # @param role_Name [String] Name of the role to create
27
- def self.create(vault, role_name)
28
- client_data = {
29
- role: role_name
30
- }
31
- vault.accessResource("POST", CLIENTS_RESOURCE, "/", client_data)
32
- end
33
- end
@@ -1,183 +0,0 @@
1
- require 'json'
2
- require 'faraday'
3
- require 'logger'
4
-
5
- ##
6
- # If we're in the +test+ environment just dump logs to Null
7
- # Otherwise, use stdout
8
- if ENV['test']
9
- $logger = Logger.new(IO::NULL)
10
- else
11
- $logger = Logger.new(STDOUT)
12
- end
13
-
14
- ##
15
- # Invoked when the API returns an +API_AccessDenied+ error
16
- class AccessDeniedException < StandardError; end;
17
- class ResourceNotFoundException < StandardError; end;
18
- class InvalidConfigurationException < StandardError; end;
19
- class InvalidCredentialsException < StandardError; end;
20
- class InvalidMethodTypeException < StandardError; end;
21
- class UnrecognizedResourceException < StandardError; end;
22
-
23
- class Vault
24
- DEFAULT_URL_TEMPLATE = "https://%s.secretsvaultcloud.%s/v1/%s%s"
25
- DEFAULT_TLD = "com"
26
-
27
- # Initialize a +Vault+ object with provided configuration.
28
- #
29
- # @param config [Hash]
30
- # - client_id: ''
31
- # - client_secret: ''
32
- # - tld: 'com'
33
- # - tenant: ''
34
- def initialize(config = nil)
35
-
36
- if config
37
- @configuration = config.collect{|k,v| [k.to_s, v]}.to_h
38
- else
39
- @configuration = {}
40
-
41
- @configuration['client_id'] = ENV['DSV_CLIENT_ID']
42
- @configuration['client_secret'] = ENV['DSV_CLIENT_SECRET']
43
- @configuration['tenant'] = ENV['DSV_TENANT']
44
- @configuration['tld'] = ENV['DSV_TLD']
45
- end
46
-
47
- if @configuration['client_id'].nil? || @configuration['client_secret'].nil?
48
- $logger.error("Must provide client_id and client_secret")
49
- raise InvalidConfigurationException
50
- end
51
-
52
- $logger.debug("Vault is configured for client_id: #{@configuration['client_id']}")
53
- end
54
-
55
- # Helper method to access a resource via API
56
- #
57
- # @param method [String] HTTP Request Method
58
- # @param resource [String] The resource type to invoke
59
- # @param path [String] The API Path to request
60
- # @param input [String] Input to send via POST/PUT body
61
- #
62
- # @return [Hash] - return Hash of JSON contents
63
- #
64
- # - +AccessDeniedException+ is raised if the server responds with an +API_AccessDenied+ error
65
- # - +InvalidMethodTypeException+ is raised if a method other than +["GET", "POST", "PUT", "DELETE"]+ is provided
66
- # - +UnrecognizedResourceException+ is raised if a resource other than +["clients", "roles", "secrets"]+ is requested
67
- def accessResource(method, resource, path, input, parse_json=true)
68
- unless ["GET", "POST", "PUT", "DELETE"].include?(method.upcase)
69
- $logger.error "Invalid request method: #{method}"
70
- raise InvalidMethodTypeException
71
- end
72
-
73
- unless ["clients", "roles", "secrets"].include? resource
74
- message = "unrecognized resource"
75
- $logger.debug "#{message}, #{resource}"
76
-
77
- raise UnrecognizedResourceException
78
- end
79
-
80
- body = ""
81
-
82
- unless input.nil?
83
- body = input.to_json
84
- end
85
-
86
- accessToken = getAccessToken
87
-
88
- # Yikes, normally not a fan of metaprogramming
89
- # We first ensured that `method` is legit to prevent
90
- # arbitrary method invocation
91
- url = urlFor(resource, path)
92
- $logger.debug "Sending request to: #{url}"
93
- resp = Faraday.send(method.downcase, url) do | req |
94
- req.headers['Authorization'] = "Bearer #{accessToken}"
95
- req.body = body unless body.empty?
96
-
97
- if ["POST", "PUT"].include?(method.upcase)
98
- req.headers['Content-Type'] = 'application/json'
99
- end
100
- end
101
-
102
- data = resp.body
103
-
104
- return data unless parse_json
105
-
106
- begin
107
- hash = JSON.parse(data)
108
-
109
- if hash['errorCode'] == "API_AccessDenied"
110
- raise AccessDeniedException
111
- end
112
-
113
- if hash['message'] == "Invalid permissions"
114
- raise AccessDeniedException
115
- end
116
-
117
- if hash['code'] == 404
118
- raise ResourceNotFoundException
119
- end
120
-
121
- rescue JSON::ParserError => e
122
- $logger.error "Error parsing JSON: #{e.to_s}"
123
- raise e
124
- end
125
-
126
- return hash
127
- end
128
-
129
- # Query API for OAuth token
130
- #
131
- # - +InvalidCredentialsException+ is returned if the provided credentials are not valid
132
- #
133
- # @return [String]
134
- def getAccessToken
135
- grantRequest = {
136
- grant_type: "client_credentials",
137
- client_id: @configuration['client_id'],
138
- client_secret: @configuration['client_secret']
139
- }.to_json
140
-
141
- url = urlFor("token")
142
-
143
- $logger.debug "calling #{url} with client_id #{@configuration['client_id']}"
144
-
145
- response = Faraday.post(
146
- url,
147
- grantRequest,
148
- "Content-Type" => "application/json"
149
- )
150
-
151
- unless response.status == 200
152
- $logger.debug "grant response error: #{response.body}"
153
- raise InvalidCredentialsException
154
- end
155
-
156
- begin
157
- grant = JSON.parse(response.body)
158
- return grant['accessToken']
159
- rescue JSON::ParserError => e
160
- $logger.error "Error parsing JSON: #{e.to_s}"
161
- raise e
162
- end
163
- end
164
-
165
- # Generate the URL for a specific request.
166
- # This factors in several configuration options including:
167
- # - +tenant+
168
- # - +tld+
169
- #
170
- # @param resource [String] The specific API resource to request
171
- # @param path [String] The path to the resource
172
- #
173
- # @return [String] The generated URL for the request
174
- def urlFor(resource, path=nil)
175
-
176
- if path != nil
177
- path = "/#{path.delete_prefix("/")}"
178
- end
179
-
180
- sprintf(DEFAULT_URL_TEMPLATE, @configuration['tenant'], @configuration['tld'] || DEFAULT_TLD, resource, path)
181
- end
182
-
183
- end