secreto 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/lib/secreto.rb +319 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YTJmZjNkNzQyYjVkOTBiMzAxMGQzMmRmY2JkM2E1ZDhjNmRhOGE3Mg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZTk2MTAzZWYyYTkyMGUxZGJhZWI5NGQyYWU5ODRhYzE2NTU1OWRiZA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
OTJmM2IxMjBkYjgxYjlkMzE4NTA1ZTIzNzQ4ZDk5OGU5NWZkMjM4NmE2Yjkx
|
10
|
+
OWZkYzE0Nzk5Njk4YTQ5OWNiMzVlYmM5ZWFjOTI5YjRkNTYwN2I4ZWEwZWY5
|
11
|
+
YjA4OTkyOTBmOTQxNzYyZDNiMGMyMTczY2MzYmUwNzJhY2NlNDI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NzA2ZmZkMGFjMjZiNzhiZWZhYjg0MTI0NWQ2MDIyYTk5MTMzNGY0ZWZhOGEy
|
14
|
+
NjVkM2QyOTZkZDQzMzkyNjJlMjI2MjQwOGVmMWQ4MWZhZDM1NjM3MmE2YjA0
|
15
|
+
MDkzODg2ZmQ5NDZjYjJhNjAwMzFjMDZkYTI5ZWQwNDVlYTBiZTM=
|
data/lib/secreto.rb
ADDED
@@ -0,0 +1,319 @@
|
|
1
|
+
require 'savon'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'crack'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
# Secreto is a ruby class to interact with Thycotic Secret Server
|
7
|
+
# == Supported Operations
|
8
|
+
# * Login
|
9
|
+
# * Retrieve a secret
|
10
|
+
# * Add a Secret
|
11
|
+
# * Add a Folder
|
12
|
+
class Secreto
|
13
|
+
|
14
|
+
# Constructor
|
15
|
+
def initialize(wsdl, ssl_verify_mode, ssl_version)
|
16
|
+
@@wsdl=wsdl
|
17
|
+
@@ssl_verify_mode=ssl_verify_mode
|
18
|
+
@@ssl_version=ssl_version
|
19
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1)
|
20
|
+
@@secretTemplates = []
|
21
|
+
end
|
22
|
+
|
23
|
+
# Authenticates with Secret Server
|
24
|
+
#
|
25
|
+
# ==== Attributes
|
26
|
+
#
|
27
|
+
# * +username+ - Username for secret Server
|
28
|
+
# * +password+ - Password
|
29
|
+
# * +domain+ - Domain Name
|
30
|
+
def Authenticate(username, password, domain)
|
31
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1)
|
32
|
+
|
33
|
+
response = client.call(:authenticate, message: {
|
34
|
+
username: username,
|
35
|
+
password: password,
|
36
|
+
organization: "",
|
37
|
+
domain: domain
|
38
|
+
})
|
39
|
+
|
40
|
+
@@token = response.to_hash[:authenticate_response][:authenticate_result][:token]
|
41
|
+
getSecretTemplates()
|
42
|
+
return @@token
|
43
|
+
end
|
44
|
+
|
45
|
+
def GetTokenIsValid #:nodoc:
|
46
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1)
|
47
|
+
response = client.call(:get_token_is_valid, message: {
|
48
|
+
token: @@token
|
49
|
+
})
|
50
|
+
|
51
|
+
return response
|
52
|
+
end
|
53
|
+
|
54
|
+
def GetSecret(secretId) #:nodoc:
|
55
|
+
thesame = lambda { |key| key }
|
56
|
+
|
57
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1, convert_request_keys_to: :none) #, convert_response_tags_to: thesame)
|
58
|
+
response = client.call(:get_secret, message: {
|
59
|
+
token: @@token,
|
60
|
+
secretId: secretId,
|
61
|
+
})
|
62
|
+
doc = Nokogiri::XML.parse(response.to_xml)
|
63
|
+
items = doc.xpath('//foo:SecretItem', 'foo' => 'urn:thesecretserver.com')
|
64
|
+
node = Hash.new
|
65
|
+
node["password"] = getField(items,"Password")
|
66
|
+
node["username"] = getField(items,"Username")
|
67
|
+
node["host"] = getField(items,"Machine")
|
68
|
+
return node
|
69
|
+
end
|
70
|
+
|
71
|
+
def getField(items,field) #:nodoc:
|
72
|
+
for item in items
|
73
|
+
for child in item.children
|
74
|
+
if child.content == field
|
75
|
+
for child1 in item.children
|
76
|
+
if child1.name == "Value"
|
77
|
+
return child1.content
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def UpdateSecret(secret) #:nodoc:
|
86
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1)
|
87
|
+
# Nokogiri is stripping the 'xsi' prefix which is required, and it also puts a 'default' prefix in, which is disallowed.
|
88
|
+
fixedXml = secret.to_s.gsub! 'nil=', 'xsi:nil='
|
89
|
+
fixedXml = fixedXml.gsub! 'default:',''
|
90
|
+
|
91
|
+
response = client.call(:update_secret, xml: fixedXml)
|
92
|
+
return response
|
93
|
+
end
|
94
|
+
|
95
|
+
def WhoAmI #:nodoc:
|
96
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1)
|
97
|
+
response = client.call(:who_am_i, message: {
|
98
|
+
token: @@token
|
99
|
+
})
|
100
|
+
return response
|
101
|
+
end
|
102
|
+
|
103
|
+
def VersionGet #:nodoc:
|
104
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1)
|
105
|
+
response = client.call(:version_get, message: {
|
106
|
+
token: @@token
|
107
|
+
})
|
108
|
+
return response
|
109
|
+
end
|
110
|
+
|
111
|
+
# Retrieve the secret Details
|
112
|
+
#
|
113
|
+
# ==== Attributes
|
114
|
+
#
|
115
|
+
# * +hostName+ - Name of the Secret to search
|
116
|
+
# * +objectType+ - Object Type. For example Machine
|
117
|
+
def GetSecretByHostName(hostName,objectType)
|
118
|
+
thesame = lambda { |key| hostName }
|
119
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1, convert_request_keys_to: :none)
|
120
|
+
response = client.call(:get_secrets_by_field_value, message: {
|
121
|
+
token: @@token,
|
122
|
+
fieldName: objectType,
|
123
|
+
searchTerm: hostName,
|
124
|
+
})
|
125
|
+
doc = Nokogiri::XML.parse(response.to_xml)
|
126
|
+
items = doc.xpath('//foo:Id', 'foo' => 'urn:thesecretserver.com')
|
127
|
+
if not items[0].nil?
|
128
|
+
if not items[0].content.nil?
|
129
|
+
return GetSecret(items[0].content)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Create a Folder
|
135
|
+
#
|
136
|
+
# ==== Attributes
|
137
|
+
#
|
138
|
+
# * +folderName+ - Name of the folder you want to create
|
139
|
+
# * +parentFolder+ - Parent Folder Name (Give full path /TOPLEVEL/Folder 1/Folder 2
|
140
|
+
def createFolder(folderName,parentFolder)
|
141
|
+
thesame = lambda { |key| hostName }
|
142
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1, convert_request_keys_to: :none)
|
143
|
+
parentId = getFolder(parentFolder)
|
144
|
+
if parentId.nil?
|
145
|
+
print "Parent Folder " + parentFolder + " doesn't exist"
|
146
|
+
return nil
|
147
|
+
else
|
148
|
+
response = client.call(:folder_create, message: {
|
149
|
+
token: @@token,
|
150
|
+
folderName: folderName,
|
151
|
+
parentFolderId: parentId,
|
152
|
+
folderTypeId: 1
|
153
|
+
})
|
154
|
+
doc = Nokogiri::XML.parse(response.to_xml)
|
155
|
+
puts doc
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def getFolder(folderName) #:nodoc:
|
160
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1, convert_request_keys_to: :none)
|
161
|
+
response = client.call(:search_folders, message: {
|
162
|
+
token: @@token,
|
163
|
+
folderName: folderName,
|
164
|
+
})
|
165
|
+
doc = Nokogiri::XML.parse(response.to_xml)
|
166
|
+
items = doc.xpath('//foo:Folder', 'foo' => 'urn:thesecretserver.com')
|
167
|
+
if items.length > 1
|
168
|
+
print "The folder " + folderName + " could not be identified uniquely " +
|
169
|
+
"Consider specifying full path like /TOPLEVEL/Level 1/Level 2/Folder Name" + "\n"
|
170
|
+
return nil
|
171
|
+
else
|
172
|
+
if not items[0].nil?
|
173
|
+
node = Hash.new
|
174
|
+
for child in items[0].children
|
175
|
+
if child.name == "Name"
|
176
|
+
node["name"] = child.content
|
177
|
+
elsif child.name == "TypeId"
|
178
|
+
node["typeId"] = child.content
|
179
|
+
elsif child.name == "Id"
|
180
|
+
node["id"] = child.content
|
181
|
+
elsif child.name == "ParentFolderId"
|
182
|
+
node["parentFolderId"] = child.content
|
183
|
+
end
|
184
|
+
end
|
185
|
+
return node["Id"]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
if folderName.include?"/"
|
189
|
+
normalizedFolderName = folderName
|
190
|
+
if folderName.start_with?("/")
|
191
|
+
normalizedFolderName = folderName.sub("/","")
|
192
|
+
end
|
193
|
+
splitted = normalizedFolderName.split("/")
|
194
|
+
$i = 0
|
195
|
+
parentId = -1
|
196
|
+
while $i < splitted.length do
|
197
|
+
parentId = getFolderId(splitted[$i],parentId)
|
198
|
+
$i+=1
|
199
|
+
end
|
200
|
+
return parentId
|
201
|
+
end
|
202
|
+
return nil
|
203
|
+
end
|
204
|
+
|
205
|
+
def getFolderId(folderName,parentFolderId) #:nodoc:
|
206
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1, convert_request_keys_to: :none)
|
207
|
+
|
208
|
+
response = client.call(:folder_get_all_children, message: {
|
209
|
+
token: @@token,
|
210
|
+
parentFolderId:parentFolderId,
|
211
|
+
})
|
212
|
+
doc = Nokogiri::XML.parse(response.to_xml)
|
213
|
+
items = doc.xpath('//foo:Folder', 'foo' => 'urn:thesecretserver.com')
|
214
|
+
for item in items
|
215
|
+
node = Hash.new
|
216
|
+
for child in item.children
|
217
|
+
node[child.name] = child.content
|
218
|
+
end
|
219
|
+
if node["Name"] == folderName
|
220
|
+
return node["Id"]
|
221
|
+
end
|
222
|
+
end
|
223
|
+
return nil
|
224
|
+
end
|
225
|
+
|
226
|
+
def getSecretTemplates() #:nodoc:
|
227
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1, convert_request_keys_to: :none)
|
228
|
+
response = client.call(:get_secret_templates, message: {
|
229
|
+
token: @@token,
|
230
|
+
})
|
231
|
+
doc = Nokogiri::XML.parse(response.to_xml)
|
232
|
+
|
233
|
+
secretTemplates = doc.xpath('//foo:SecretTemplates', 'foo' => 'urn:thesecretserver.com')
|
234
|
+
myjson = Crack::XML.parse(secretTemplates.to_xml)
|
235
|
+
@@secretTemplates = myjson["SecretTemplates"]["SecretTemplate"]
|
236
|
+
return nil
|
237
|
+
end
|
238
|
+
|
239
|
+
# Create a Secret
|
240
|
+
#
|
241
|
+
# ==== Attributes
|
242
|
+
#
|
243
|
+
# * +folderName+ - Folder Name where secret will be added (Give full path /TOPLEVEL/Folder 1/Folder 2
|
244
|
+
# * +secretType+ - Secret Type For ex Password/Active Directory Account
|
245
|
+
# * +secretName+ - Name of Secret
|
246
|
+
# * +fieldKeys+ - List of Items in secret
|
247
|
+
# * +fieldValues+ - Value of secret Items
|
248
|
+
def createSecret(folderName,secretType,secretName,fieldKeys,fieldValues)
|
249
|
+
if fieldKeys.length != fieldValues.length
|
250
|
+
print "For each key there should be a value [" + fieldKeys.join(",") + " != " + fieldValues.join(",") + "]\n"
|
251
|
+
return nil
|
252
|
+
end
|
253
|
+
templateFields = nil
|
254
|
+
templateId = nil
|
255
|
+
@@secretTemplates.each { |x|
|
256
|
+
if x['Name'] == secretType
|
257
|
+
templateFields = x['Fields']['SecretField']
|
258
|
+
templateId = x['Id']
|
259
|
+
break
|
260
|
+
end
|
261
|
+
}
|
262
|
+
if templateFields.nil?
|
263
|
+
print "secretType " + secretType + " is not available" + "\n"
|
264
|
+
return nil
|
265
|
+
else
|
266
|
+
#puts templateFields
|
267
|
+
fieldIds = []
|
268
|
+
fieldKeys.each { |fkey|
|
269
|
+
templateFields.each { |field|
|
270
|
+
if field['DisplayName'] == fkey
|
271
|
+
fieldIds.push(field['Id'])
|
272
|
+
end
|
273
|
+
}
|
274
|
+
}
|
275
|
+
if fieldIds.length != fieldKeys.length
|
276
|
+
print "Not all secretField were found [" + fieldKeys.join(",") + "]\n"
|
277
|
+
return nil
|
278
|
+
end
|
279
|
+
# All Found
|
280
|
+
end
|
281
|
+
secretFieldIds = "<ns1:secretFieldIds>"
|
282
|
+
fieldIds.each { |fid|
|
283
|
+
secretFieldIds = secretFieldIds + "<ns1:int>" + fid.to_s + "</ns1:int>"
|
284
|
+
}
|
285
|
+
secretFieldIds = secretFieldIds + "</ns1:secretFieldIds>"
|
286
|
+
|
287
|
+
secretItemValues = "<ns1:secretItemValues>"
|
288
|
+
fieldValues.each { |fval|
|
289
|
+
secretItemValues = secretItemValues + "<ns1:string>" + fval.to_s + "</ns1:string>"
|
290
|
+
}
|
291
|
+
secretItemValues = secretItemValues + "</ns1:secretItemValues>"
|
292
|
+
|
293
|
+
|
294
|
+
folderId=getFolder(folderName)
|
295
|
+
if folderId.nil?
|
296
|
+
print "Folder " + folderName + " is not found"
|
297
|
+
return nil
|
298
|
+
end
|
299
|
+
xmlString = '<?xml version="1.0" encoding="utf-8"?>' +
|
300
|
+
'<SOAP-ENV:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:thesecretserver.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">' +
|
301
|
+
'<SOAP-ENV:Header/>' +
|
302
|
+
' <ns0:Body>' +
|
303
|
+
' <ns1:AddSecret>' +
|
304
|
+
' <ns1:token><ns1:token>' + @@token.to_s + '</ns1:token>' +
|
305
|
+
' <ns1:secretTypeId>' + templateId + '</ns1:secretTypeId>' +
|
306
|
+
' <ns1:secretName>' + secretName + '</ns1:secretName>' +
|
307
|
+
secretFieldIds +
|
308
|
+
secretItemValues +
|
309
|
+
' <ns1:folderId>' + folderId + '</ns1:folderId>' +
|
310
|
+
' </ns1:token>' +
|
311
|
+
' </ns1:AddSecret>' +
|
312
|
+
' </ns0:Body>' +
|
313
|
+
'</SOAP-ENV:Envelope>'
|
314
|
+
|
315
|
+
client = Savon.client(wsdl: @@wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1)
|
316
|
+
response = client.call(:add_secret, xml: xmlString)
|
317
|
+
puts response.to_xml
|
318
|
+
end
|
319
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: secreto
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- C S P Nanda
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-04-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: savon
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: crack
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.4'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: json
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.8'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.8'
|
69
|
+
description: Supported operations are create Folder, add Secret, Retrieve a secret
|
70
|
+
from Thycotic Secret Server
|
71
|
+
email: cspnanda@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- lib/secreto.rb
|
77
|
+
homepage: https://github.com/cspnanda/secreto
|
78
|
+
licenses:
|
79
|
+
- MIT
|
80
|
+
metadata: {}
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.9.3
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 2.4.8
|
98
|
+
signing_key:
|
99
|
+
specification_version: 4
|
100
|
+
summary: Secreto is a gem to interact with Thycotic Secret Server
|
101
|
+
test_files: []
|