tss-sdk 0.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 +7 -0
- data/lib/server.rb +4 -0
- data/lib/server/secret.rb +38 -0
- data/lib/server/server.rb +184 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c4ed8a314a6339abf161455030a68b95b5acdf89c6b776874b49eaa96f27c07c
|
4
|
+
data.tar.gz: 8fb041e5ead5023d94ecb87ef7707a171c9801de3b3efb1b7bfe1355f4439385
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c06b5b42b1da8a583a0e8c92475e95c574ee8ca5ac4ab88ae5f1abd71ae8bfc9cca50d333fc2b2ee6d01cc6f1f802ec9a6f966880f246d8a0a6d8297d0be857b
|
7
|
+
data.tar.gz: 0be9bab6d50434b47a9c5fe1c182bb93bb2ceba248275c698d25f06cba14072d0efba5225ca2ba5b280e7e6ec81da1799711b27427f72b479503638d251ea37a
|
data/lib/server.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
class InvalidSecretException < StandardError; end;
|
3
|
+
|
4
|
+
# Utilized to fetch secrets from an initialzed +Server+
|
5
|
+
class Server::Secret
|
6
|
+
SECRETS_RESOURCE = "secrets".freeze
|
7
|
+
|
8
|
+
# Fetch secrets from the server
|
9
|
+
#
|
10
|
+
# @param server [Server]
|
11
|
+
#
|
12
|
+
# @return [Hash] of the secret and associated file contents
|
13
|
+
def self.fetch(server, id)
|
14
|
+
@server = server
|
15
|
+
|
16
|
+
begin
|
17
|
+
@secret = @server.accessResource("GET", SECRETS_RESOURCE, id.to_s)
|
18
|
+
rescue Exception => e
|
19
|
+
$logger.error "Error accessing resource: #{e.to_s}"
|
20
|
+
raise InvalidSecretException
|
21
|
+
end
|
22
|
+
|
23
|
+
raise InvalidSecretException if @secret.nil?
|
24
|
+
|
25
|
+
# automatically download file attachments and substitute them for the
|
26
|
+
@secret['items'].each do |item|
|
27
|
+
next if item['fileAttachmentId'].nil?
|
28
|
+
|
29
|
+
path = sprintf("%d/fields/%s", id, item['slug'])
|
30
|
+
|
31
|
+
item_data = @server.accessResource("GET", SECRETS_RESOURCE, path, false)
|
32
|
+
|
33
|
+
item['itemValue'] = item_data
|
34
|
+
end
|
35
|
+
|
36
|
+
return @secret
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,184 @@
|
|
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
|
+
|
18
|
+
class InvalidConfigurationException < StandardError; end;
|
19
|
+
class InvalidCredentialsException < StandardError; end;
|
20
|
+
class InvalidMethodTypeException < StandardError; end;
|
21
|
+
class UnrecognizedResourceException < StandardError; end;
|
22
|
+
|
23
|
+
class Server
|
24
|
+
DEFAULT_URL_TEMPLATE = "https://%s.secretservercloud.%s/"
|
25
|
+
DEFAULT_TLD = "com"
|
26
|
+
DEFAULT_API_PATH_URI = "/api/v1"
|
27
|
+
DEFAULT_TOKEN_PATH_URI = "/oauth2/token"
|
28
|
+
|
29
|
+
# Initialize a +Server+ object with provided configuration.
|
30
|
+
#
|
31
|
+
# @param config [Hash]
|
32
|
+
# - username: ''
|
33
|
+
# - password: ''
|
34
|
+
# - tld: 'com'
|
35
|
+
# - api_path_uri: '/api/v1'
|
36
|
+
# - token_path_uri: '/oauth2/token'
|
37
|
+
# - tenant: ''
|
38
|
+
# - server_url: ''
|
39
|
+
def initialize(config)
|
40
|
+
@configuration = config.collect{|k,v| [k.to_s, v]}.to_h
|
41
|
+
if @configuration['server_url'] == "" && @configuration['tenant'] == ""
|
42
|
+
$logger.error("Either ServerURL or Tenant must be set")
|
43
|
+
raise InvalidConfigurationException
|
44
|
+
end
|
45
|
+
|
46
|
+
if @configuration['username'].nil? || @configuration['password'].nil?
|
47
|
+
$logger.error("Must provide username and password")
|
48
|
+
raise InvalidConfigurationException
|
49
|
+
end
|
50
|
+
|
51
|
+
if @configuration['tld'].nil?
|
52
|
+
@configuration['tld'] = DEFAULT_TLD
|
53
|
+
end
|
54
|
+
|
55
|
+
if @configuration['api_path_uri'].nil?
|
56
|
+
@configuration['api_path_uri'] = DEFAULT_API_PATH_URI
|
57
|
+
end
|
58
|
+
@configuration['api_path_uri'].delete_suffix!("/")
|
59
|
+
|
60
|
+
if @configuration['token_path_uri'].nil?
|
61
|
+
@configuration['token_path_uri'] = DEFAULT_TOKEN_PATH_URI
|
62
|
+
end
|
63
|
+
@configuration['token_path_uri'].delete_suffix!("/")
|
64
|
+
end
|
65
|
+
|
66
|
+
# Helper method to access a resource via API
|
67
|
+
#
|
68
|
+
# @param method [String] HTTP Request Method
|
69
|
+
# @param resource [String] The resource type to invoke
|
70
|
+
# @param path [String] The API Path to request
|
71
|
+
# @param parse_json [Boolean] Determine whether we want to return a hash, or raw output
|
72
|
+
#
|
73
|
+
# @return [Hash] - If +parse_json+, return Hash of JSON contents
|
74
|
+
# @return [String] - Otherwise, return raw HTTP Response Body
|
75
|
+
#
|
76
|
+
# - +AccessDeniedException+ is raised if the server responds with an +API_AccessDenied+ error
|
77
|
+
# - +InvalidMethodTypeException+ is raised if a method other than +["GET", "POST", "PUT", "DELETE"]+ is provided
|
78
|
+
# - +UnrecognizedResourceException+ is raised if a resource other than +["secrets"]+ is requested
|
79
|
+
def accessResource(method, resource, path, parse_json = true)
|
80
|
+
unless ["GET", "POST", "PUT", "DELETE"].include?(method.upcase)
|
81
|
+
$logger.error "Invalid request method: #{method}"
|
82
|
+
raise InvalidMethodTypeException
|
83
|
+
end
|
84
|
+
|
85
|
+
unless ["secrets"].include? resource
|
86
|
+
$logger.debug "unrecognized resource: #{resource}"
|
87
|
+
raise UnrecognizedResourceException
|
88
|
+
end
|
89
|
+
|
90
|
+
accessToken = getAccessToken
|
91
|
+
|
92
|
+
url = urlFor(resource, path)
|
93
|
+
$logger.debug "Sending request to: #{url}"
|
94
|
+
resp = Faraday.send(method.downcase, url) do | req |
|
95
|
+
req.headers['Authorization'] = "Bearer #{accessToken}"
|
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
|
+
rescue JSON::ParserError => e
|
113
|
+
$logger.error "Error parsing JSON: #{e.to_s}"
|
114
|
+
raise e
|
115
|
+
end
|
116
|
+
|
117
|
+
return hash
|
118
|
+
end
|
119
|
+
|
120
|
+
# Query API for OAuth token
|
121
|
+
#
|
122
|
+
# - +InvalidCredentialsException+ is returned if the provided credentials are not valid
|
123
|
+
#
|
124
|
+
# @return [String]
|
125
|
+
def getAccessToken
|
126
|
+
grantRequest = {
|
127
|
+
grant_type: 'password',
|
128
|
+
username: @configuration['username'],
|
129
|
+
password: @configuration['password']
|
130
|
+
}
|
131
|
+
|
132
|
+
url = urlFor("token")
|
133
|
+
|
134
|
+
response = Faraday.post(
|
135
|
+
url,
|
136
|
+
grantRequest
|
137
|
+
)
|
138
|
+
|
139
|
+
unless response.status == 200
|
140
|
+
$logger.error "Unable to retrive credentials for username: #{@configuration['username']}"
|
141
|
+
$logger.error "\t #{response.body}"
|
142
|
+
raise InvalidCredentialsException
|
143
|
+
end
|
144
|
+
|
145
|
+
begin
|
146
|
+
grant = JSON.parse(response.body)
|
147
|
+
return grant['access_token']
|
148
|
+
rescue JSON::ParserError => e
|
149
|
+
$logger.error "Error parsing JSON: #{e.to_s}"
|
150
|
+
raise e
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Generate the URL for a specific request.
|
155
|
+
# This factors in several configuration options including:
|
156
|
+
# - +tenant+
|
157
|
+
# - +server_url+
|
158
|
+
# - +token_path_uri+
|
159
|
+
# - +api_path_uri+
|
160
|
+
#
|
161
|
+
# @param resource [String] The specific API resource to request
|
162
|
+
# @param path [String] The path to the resource
|
163
|
+
#
|
164
|
+
# @return [String] The generated URL for the request
|
165
|
+
def urlFor(resource, path=nil)
|
166
|
+
|
167
|
+
if @configuration['server_url'].nil? || @configuration['server_url'] == ""
|
168
|
+
baseURL = sprintf(DEFAULT_URL_TEMPLATE, @configuration['tenant'], @configuration['tld']).delete_suffix("/")
|
169
|
+
else
|
170
|
+
baseURL = @configuration['server_url'].delete_suffix("/")
|
171
|
+
end
|
172
|
+
|
173
|
+
if resource == "token"
|
174
|
+
return sprintf("%s/%s", baseURL, @configuration['token_path_uri'].delete_prefix("/"))
|
175
|
+
end
|
176
|
+
|
177
|
+
if path != "/"
|
178
|
+
path = path.delete_prefix("/")
|
179
|
+
end
|
180
|
+
|
181
|
+
sprintf("%s/%s/%s/%s", baseURL, @configuration['api_path_uri'].delete_prefix("/"), resource.delete_suffix("/").delete_prefix("/"), path)
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tss-sdk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Poulin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-04-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.7'
|
27
|
+
description: The Thycotic TSS SDK for Ruby
|
28
|
+
email: john.m.poulin@gmail.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- lib/server.rb
|
34
|
+
- lib/server/secret.rb
|
35
|
+
- lib/server/server.rb
|
36
|
+
homepage: https://rubygems.org/gems/hola
|
37
|
+
licenses:
|
38
|
+
- Apache-2.0
|
39
|
+
metadata: {}
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubygems_version: 3.0.3
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: tss-sdk
|
59
|
+
test_files: []
|