zanzibar 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'savon'
4
+ gem 'savon_spec'
5
+ gem 'rspec'
6
+ gem 'webmock'
7
+
8
+ # Specify your gem's dependencies in zanzibar.gemspec
9
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2015 Cimpress
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # Zanzibar
2
+
3
+
4
+ Zanzibar is a utility to retrieve secrets from a Secret Server installation. It supports retrieval of a password, public/private key, or secret attachment.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'zanzibar'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install zanzibar
21
+
22
+ ## Usage
23
+
24
+ In your ruby project, rakefile, etc., create a new Zanzibar object. The constructor takes a hash of optional parameters for the WSDL location, the domain of the Secret Server, a hash of global variables to pass to savon (necessary for windows environments with self-signed certs) and a password for the current user (intended to be passed in through some encryption method, unless you really want a plaintext password there.). All of these parameters are optional and the user will be prompted to enter them if they are missing.
25
+
26
+ ```ruby
27
+ my_object = Zanzibar::Zanzibar.new(:domain => 'my.domain.net', :wsdl => 'my.scrt.srvr.com/webservices/sswebservice.asmx?wdsl', :pwd => get_encrypted_password_from_somewhere)
28
+ ```
29
+
30
+ Example:
31
+
32
+ ```ruby
33
+ require 'zanzibar'
34
+
35
+ ## Constructor takes hash as argument, all optional :domain, :wsdl, :pwd, :globals
36
+ secrets = Zanzibar::Zanzibar.new(:domain => 'mydomain.net', :wsdl => "https://my.scrt.server/webservices/sswebservice.asmx?wsdl")
37
+ # On windows with self-signed certs,
38
+ # Zanzibar::Zanzibar.new(:domain => 'mydomain.net', :wsdl => "https://my.scrt.server/webservices/sswebservice.asmx?wsdl", :globals => {:ssl_verify_mode => :none})
39
+
40
+ ## Simple password -> takes secret id as argument
41
+ secrets.get_secret(1234)
42
+
43
+ ## Private Key -> takes hash as argument, requires :scrt_id, optional :scrt_item_id, :path
44
+ secrets.download_private_key(:scrt_id => 2345, :path => 'secrets/')
45
+
46
+ ## Public Key -> takes hash as argument, requires :scrt_id, optional :scrt_item_id, :path
47
+ secrets.download_public_key(:scrt_id => 2345, :path => 'secrets/')
48
+
49
+ ## Attachment; only supports secrets with single attachment -> takes hash as argument, requires :scrt_id, optional :scrt_item_id, :path
50
+ secrets.download_attachment(:scrt_id => 3456, :path => 'secrets/')
51
+
52
+ ```
53
+
54
+ ## Contributing
55
+
56
+ 1. Fork it ( https://github.com/Cimpress-MCP/zanzibar/fork )
57
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
58
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
59
+ 4. Push to the branch (`git push origin my-new-feature`)
60
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task 'test' do
4
+ Dir.chdir('test')
5
+ system("rspec zanzibar_spec.rb")
6
+ end
7
+
8
+ task 'install_dependencies' do
9
+ system('bundle install')
10
+ end
data/lib/zanzibar.rb ADDED
@@ -0,0 +1,209 @@
1
+ require "zanzibar/version"
2
+ require 'savon'
3
+ require 'io/console'
4
+ require 'fileutils'
5
+
6
+ module Zanzibar
7
+
8
+ ##
9
+ # Class for interacting with Secret Server
10
+ class Zanzibar
11
+
12
+ ##
13
+ # @param args{:domain, :wsdl, :pwd, :globals{}}
14
+
15
+ def initialize(args = {})
16
+ if args[:wsdl]
17
+ @@wsdl = args[:wsdl]
18
+ else
19
+ @@wsdl = get_wsdl_location
20
+ end
21
+ if args[:pwd]
22
+ @@password = args[:pwd]
23
+ else
24
+ @@password = prompt_for_password
25
+ end
26
+ if args[:domain]
27
+ @@domain = args[:domain]
28
+ else
29
+ @@domain = prompt_for_domain
30
+ end
31
+ args[:globals] = {} unless args[:globals]
32
+ init_client(args[:globals])
33
+ end
34
+
35
+ ## Initializes the Savon client class variable with the wdsl document location and optional global variables
36
+ # @param globals{}, optional
37
+
38
+ def init_client(globals = {})
39
+ globals = {} if globals == nil
40
+ @@client = Savon.client(globals) do
41
+ wsdl @@wsdl
42
+ end
43
+ end
44
+
45
+ ## Gets the user's password if none is provided in the constructor.
46
+ # @return [String] the password for the current user
47
+
48
+ def prompt_for_password
49
+ puts "Please enter password for #{ENV['USER']}:"
50
+ return STDIN.noecho(&:gets).chomp
51
+ end
52
+
53
+ ## Gets the wsdl document location if none is provided in the constructor
54
+ # @return [String] the location of the WDSL document
55
+
56
+ def get_wsdl_location
57
+ puts "Enter the URL of the Secret Server WSDL:"
58
+ return STDIN.gets.chomp
59
+ end
60
+
61
+ ## Gets the domain of the Secret Server installation if none is provided in the constructor
62
+ # @return [String] the domain of the secret server installation
63
+
64
+ def prompt_for_domain
65
+ puts "Enter the domain of your Secret Server:"
66
+ return STDIN.gets.chomp
67
+ end
68
+
69
+
70
+ ## Get an authentication token for interacting with Secret Server. These are only good for about 10 minutes so just get a new one each time.
71
+ # Will raise an error if there is an issue with the authentication.
72
+ # @return the authentication token for the current user.
73
+
74
+ def get_token
75
+ begin
76
+ response = @@client.call(:authenticate, message: { username: ENV['USER'], password: @@password, organization: "", domain: @@domain }).hash
77
+ if response[:envelope][:body][:authenticate_response][:authenticate_result][:errors]
78
+ raise "Error generating the authentication token for user #{ENV['USER']}: #{response[:envelope][:body][:authenticate_response][:authenticate_result][:errors][:string]}"
79
+ end
80
+ response[:envelope][:body][:authenticate_response][:authenticate_result][:token]
81
+ rescue Savon::Error => err
82
+ raise "There was an error generating the authentiaton token for user #{ENV['USER']}: #{err}"
83
+ end
84
+ end
85
+
86
+ ## Get a secret returned as a hash
87
+ # Will raise an error if there was an issue getting the secret
88
+ # @param [Integer] the secret id
89
+ # @return [Hash] the secret hash retrieved from the wsdl
90
+
91
+ def get_secret(scrt_id, token = nil)
92
+ begin
93
+ secret = @@client.call(:get_secret, message: { token: token || get_token, secretId: scrt_id}).hash
94
+ if secret[:envelope][:body][:get_secret_response][:get_secret_result][:errors]
95
+ raise "There was an error getting secret #{scrt_id}: #{secret[:envelope][:body][:get_secret_response][:get_secret_result][:errors][:string]}"
96
+ end
97
+ return secret
98
+ rescue Savon::Error => err
99
+ raise "There was an error getting the secret with id #{scrt_id}: #{err}"
100
+ end
101
+ end
102
+
103
+ ## Retrieve a simple password from a secret
104
+ # Will raise an error if there are any issues
105
+ # @param [Integer] the secret id
106
+ # @return [String] the password for the given secret
107
+
108
+ def get_password(scrt_id)
109
+ begin
110
+ secret = get_secret(scrt_id)
111
+ return secret[:envelope][:body][:get_secret_response][:get_secret_result][:secret][:items][:secret_item][1][:value]
112
+ rescue Savon::Error => err
113
+ raise "There was an error getting the password for secret #{scrt_id}: #{err}"
114
+ end
115
+ end
116
+
117
+ ## Get the secret item id that relates to a key file or attachment.
118
+ # Will raise on error
119
+ # @param [Integer] the secret id
120
+ # @param [String] the type of secret item to get, one of privatekey, publickey, attachment
121
+ # @return [Integer] the secret item id
122
+
123
+ def get_scrt_item_id(scrt_id, type, token)
124
+ secret = get_secret(scrt_id, token)
125
+ case type
126
+ when 'privatekey'
127
+ ## Get private key item id
128
+ secret[:envelope][:body][:get_secret_response][:get_secret_result][:secret][:items][:secret_item].each do |item|
129
+ return item[:id] if item[:field_name] == 'Private Key'
130
+ end
131
+ when 'publickey'
132
+ ## Get public key item id
133
+ secret[:envelope][:body][:get_secret_response][:get_secret_result][:secret][:items][:secret_item].each do |item|
134
+ return item[:id] if item[:field_name] == 'Public Key'
135
+ end
136
+ when 'attachment'
137
+ ## Get attachment item id. This currently only supports secrets with one attachment.
138
+ secret[:envelope][:body][:get_secret_response][:get_secret_result][:secret][:items][:secret_item].each do |item|
139
+ return item[:id] if item[:field_name] == 'Attachment'
140
+ end
141
+ else
142
+ raise "Unknown type, #{type}."
143
+ end
144
+ end
145
+
146
+ ## Downloads the private key for a secret and places it where Zanzibar is running, or :path if specified
147
+ # Raise on error
148
+ # @param [Hash] args, :scrt_id, :scrt_item_id - optional, :path - optional
149
+
150
+ def download_private_key(args = {})
151
+ token = get_token
152
+ FileUtils.mkdir_p(args[:path]) if args[:path]
153
+ path = args[:path] ? args[:path] : '.' ## The File.join below doesn't handle nils well, so let's take that possibility away.
154
+ begin
155
+ response = @@client.call(:download_file_attachment_by_item_id, message: { token: token, secretId: args[:scrt_id], secretItemId: args[:scrt_item_id] || get_scrt_item_id(args[:scrt_id], 'privatekey', token)}).hash
156
+ if response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:errors]
157
+ raise "There was an error getting the private key for secret #{args[:scrt_id]}: #{response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:string]}"
158
+ end
159
+ File.open(File.join(path, response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:file_name]), 'wb') do |file|
160
+ file.puts Base64.decode64(response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:file_attachment])
161
+ end
162
+ rescue Savon::Error => err
163
+ raise "There was an error getting the private key for secret #{args[:scrt_id]}: #{err}"
164
+ end
165
+ end
166
+
167
+ ## Downloads the public key for a secret and places it where Zanzibar is running, or :path if specified
168
+ # Raise on error
169
+ # @param [Hash] args, :scrt_id, :scrt_item_id - optional, :path - optional
170
+
171
+ def download_public_key(args = {})
172
+ token = get_token
173
+ FileUtils.mkdir_p(args[:path]) if args[:path]
174
+ path = args[:path] ? args[:path] : '.' ## The File.join below doesn't handle nils well, so let's take that possibility away.
175
+ begin
176
+ response = @@client.call(:download_file_attachment_by_item_id, message: { token: token, secretId: args[:scrt_id], secretItemId: args[:scrt_item_id] || get_scrt_item_id(args[:scrt_id], 'publickey', token)}).hash
177
+ if response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:errors]
178
+ raise "There was an error getting the public key for secret #{args[:scrt_id]}: #{response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:string]}"
179
+ end
180
+ File.open(File.join(path, response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:file_name]), 'wb') do |file|
181
+ file.puts Base64.decode64(response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:file_attachment])
182
+ end
183
+ rescue Savon::Error => err
184
+ raise "There was an error getting the public key for secret #{args[:scrt_id]}: #{err}"
185
+ end
186
+ end
187
+
188
+ ## Downloads an attachment for a secret and places it where Zanzibar is running, or :path if specified
189
+ # Raise on error
190
+ # @param [Hash] args, :scrt_id, :scrt_item_id - optional, :path - optional
191
+
192
+ def download_attachment(args = {})
193
+ token = get_token
194
+ FileUtils.mkdir_p(args[:path]) if args[:path]
195
+ path = args[:path] ? args[:path] : '.' ## The File.join below doesn't handle nils well, so let's take that possibility away.
196
+ begin
197
+ response = @@client.call(:download_file_attachment_by_item_id, message: { token: token, secretId: args[:scrt_id], secretItemId: args[:scrt_item_id] || get_scrt_item_id(args[:scrt_id], 'attachment', token)}).hash
198
+ if response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:errors]
199
+ raise "There was an error getting the attachment for secret #{args[:scrt_id]}: #{response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:string]}"
200
+ end
201
+ File.open(File.join(path, response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:file_name]), 'wb') do |file|
202
+ file.puts Base64.decode64(response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:file_attachment])
203
+ end
204
+ rescue Savon::Error => err
205
+ raise "There was an error getting the attachment from secret #{args[:scrt_id]}: #{err}"
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,3 @@
1
+ module Zanzibar
2
+ VERSION = "0.0.8"
3
+ end
data/test/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3
+ <soap:Body>
4
+ <DownloadFileAttachmentByItemIdResponse xmlns="urn:thesecretserver.com">
5
+ <DownloadFileAttachmentByItemIdResult>
6
+ <Errors />
7
+ <FileAttachment>SSBhbSBhIHNlY3JldCBhdHRhY2htZW50</FileAttachment>
8
+ <FileName>attachment.txt</FileName>
9
+ </DownloadFileAttachmentByItemIdResult>
10
+ </DownloadFileAttachmentByItemIdResponse>
11
+ </soap:Body>
12
+ </soap:Envelope>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
3
+ <soap:Body>
4
+ <AuthenticateResponse xmlns="urn:thesecretserver.com">
5
+ <AuthenticateResult>
6
+ <Errors>
7
+ </Errors>
8
+ <Token>imatoken</Token>
9
+ </AuthenticateResult>
10
+ </AuthenticateResponse>
11
+ </soap:Body>
12
+ </soap:Envelope>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3
+ <soap:Body>
4
+ <DownloadFileAttachmentByItemIdResponse xmlns="urn:thesecretserver.com">
5
+ <DownloadFileAttachmentByItemIdResult>
6
+ <Errors />
7
+ <FileAttachment>LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVkgLS0tLS0KemFuemliYXJUZXN0UGFzc3dvcmQKLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0=</FileAttachment>
8
+ <FileName>zanzi_key</FileName>
9
+ </DownloadFileAttachmentByItemIdResult>
10
+ </DownloadFileAttachmentByItemIdResponse>
11
+ </soap:Body>
12
+ </soap:Envelope>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3
+ <soap:Body>
4
+ <DownloadFileAttachmentByItemIdResponse xmlns="urn:thesecretserver.com">
5
+ <DownloadFileAttachmentByItemIdResult>
6
+ <Errors />
7
+ <FileAttachment>MTIzNFB1YmxpY0tleTU2Nzg9PQ==</FileAttachment>
8
+ <FileName>zanzi_key.pub</FileName>
9
+ </DownloadFileAttachmentByItemIdResult>
10
+ </DownloadFileAttachmentByItemIdResponse>
11
+ </soap:Body>
12
+ </soap:Envelope>
@@ -0,0 +1,57 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3
+ <soap:Body>
4
+ <GetSecretResponse xmlns="urn:thesecretserver.com">
5
+ <GetSecretResult>
6
+ <Errors />
7
+ <Secret>
8
+ <Name>Zanzi Test Secret</Name>
9
+ <Items>
10
+ <SecretItem>
11
+ <Value>ZanziUser</Value>
12
+ <Id>15391</Id>
13
+ <FieldId>284</FieldId>
14
+ <FieldName>Username</FieldName>
15
+ <IsFile>false</IsFile>
16
+ <IsNotes>false</IsNotes>
17
+ <IsPassword>false</IsPassword>
18
+ <FieldDisplayName>Username</FieldDisplayName>
19
+ </SecretItem>
20
+ <SecretItem>
21
+ <Value>zanziUserPassword</Value>
22
+ <Id>15392</Id>
23
+ <FieldId>285</FieldId>
24
+ <FieldName>Password</FieldName>
25
+ <IsFile>false</IsFile>
26
+ <IsNotes>false</IsNotes>
27
+ <IsPassword>true</IsPassword>
28
+ <FieldDisplayName>Password</FieldDisplayName>
29
+ </SecretItem>
30
+ <SecretItem>
31
+ <Value />
32
+ <Id>15395</Id>
33
+ <FieldId>287</FieldId>
34
+ <FieldName>Attachment</FieldName>
35
+ <IsFile>true</IsFile>
36
+ <IsNotes>false</IsNotes>
37
+ <IsPassword>false</IsPassword>
38
+ <FieldDisplayName>Attachment</FieldDisplayName>
39
+ </SecretItem>
40
+ </Items>
41
+ <Id>1234</Id>
42
+ <SecretTypeId>6028</SecretTypeId>
43
+ <FolderId>106</FolderId>
44
+ <IsWebLauncher>false</IsWebLauncher>
45
+ <Active>true</Active>
46
+ <CheckOutMinutesRemaining xsi:nil="true" />
47
+ <IsCheckedOut xsi:nil="true" />
48
+ <CheckOutUserDisplayName />
49
+ <CheckOutUserId xsi:nil="true" />
50
+ <IsOutOfSync xsi:nil="true" />
51
+ <IsRestricted>false</IsRestricted>
52
+ <OutOfSyncReason />
53
+ </Secret>
54
+ </GetSecretResult>
55
+ </GetSecretResponse>
56
+ </soap:Body>
57
+ </soap:Envelope>