commit 728f727dc72f6a8819bc53af58b5e90ae78c134c Author: Jason Davis-Cooke Date: Mon Jan 12 10:49:59 2015 -0500 Initiaize Repo diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae3fdc2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +/.bundle/ +/.yardoc +/Gemfile.lock +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ +*.bundle +*.so +*.o +*.a +mkmf.log diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..3ce429f --- /dev/null +++ b/Gemfile @@ -0,0 +1,9 @@ +source 'https://rubygems.org' + +gem 'savon' +gem 'savon_spec' +gem 'rspec' +gem 'webmock' + +# Specify your gem's dependencies in zanzibar.gemspec +gemspec diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..07b3529 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,13 @@ +Copyright (c) 2015 Cimpress + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e8f70ac --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# Zanzibar + + +Zanzibar is a utility to retrieve secrets from a Secret Server installation. It supports retrieval of a password, public/private key, or secret attachment. + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'zanzibar' +``` + +And then execute: + + $ bundle + +Or install it yourself as: + + $ gem install zanzibar + +## Usage + +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. + +```ruby + my_object = Zanzibar::Zanzibar.new(:domain => 'my.domain.net', :wsdl => 'my.scrt.srvr.com/webservices/sswebservice.asmx?wdsl', :pwd => get_encrypted_password_from_somewhere) +``` + +Example: + +```ruby +require 'zanzibar' + +## Constructor takes hash as argument, all optional :domain, :wsdl, :pwd, :globals +secrets = Zanzibar::Zanzibar.new(:domain => 'mydomain.net', :wsdl => "https://my.scrt.server/webservices/sswebservice.asmx?wsdl") +# On windows with self-signed certs, +# Zanzibar::Zanzibar.new(:domain => 'mydomain.net', :wsdl => "https://my.scrt.server/webservices/sswebservice.asmx?wsdl", :globals => {:ssl_verify_mode => :none}) + +## Simple password -> takes secret id as argument +secrets.get_secret(1234) + +## Private Key -> takes hash as argument, requires :scrt_id, optional :scrt_item_id, :path +secrets.download_private_key(:scrt_id => 2345, :path => 'secrets/') + +## Public Key -> takes hash as argument, requires :scrt_id, optional :scrt_item_id, :path +secrets.download_public_key(:scrt_id => 2345, :path => 'secrets/') + +## Attachment; only supports secrets with single attachment -> takes hash as argument, requires :scrt_id, optional :scrt_item_id, :path +secrets.download_attachment(:scrt_id => 3456, :path => 'secrets/') + +``` + +## Contributing + +1. Fork it ( https://github.com/Cimpress-MCP/zanzibar/fork ) +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create a new Pull Request diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..899c1b2 --- /dev/null +++ b/Rakefile @@ -0,0 +1,10 @@ +require "bundler/gem_tasks" + +task 'test' do + Dir.chdir('test') + system("rspec zanzibar_spec.rb") +end + +task 'install_dependencies' do + system('bundle install') +end diff --git a/lib/zanzibar.rb b/lib/zanzibar.rb new file mode 100644 index 0000000..fc3ebfb --- /dev/null +++ b/lib/zanzibar.rb @@ -0,0 +1,209 @@ +require "zanzibar/version" +require 'savon' +require 'io/console' +require 'fileutils' + +module Zanzibar + + ## + # Class for interacting with Secret Server + class Zanzibar + + ## + # @param args{:domain, :wsdl, :pwd, :globals{}} + + def initialize(args = {}) + if args[:wsdl] + @@wsdl = args[:wsdl] + else + @@wsdl = get_wsdl_location + end + if args[:pwd] + @@password = args[:pwd] + else + @@password = prompt_for_password + end + if args[:domain] + @@domain = args[:domain] + else + @@domain = prompt_for_domain + end + args[:globals] = {} unless args[:globals] + init_client(args[:globals]) + end + + ## Initializes the Savon client class variable with the wdsl document location and optional global variables + # @param globals{}, optional + + def init_client(globals = {}) + globals = {} if globals == nil + @@client = Savon.client(globals) do + wsdl @@wsdl + end + end + + ## Gets the user's password if none is provided in the constructor. + # @return [String] the password for the current user + + def prompt_for_password + puts "Please enter password for #{ENV['USER']}:" + return STDIN.noecho(&:gets).chomp + end + + ## Gets the wsdl document location if none is provided in the constructor + # @return [String] the location of the WDSL document + + def get_wsdl_location + puts "Enter the URL of the Secret Server WSDL:" + return STDIN.gets.chomp + end + + ## Gets the domain of the Secret Server installation if none is provided in the constructor + # @return [String] the domain of the secret server installation + + def prompt_for_domain + puts "Enter the domain of your Secret Server:" + return STDIN.gets.chomp + end + + + ## 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. + # Will raise an error if there is an issue with the authentication. + # @return the authentication token for the current user. + + def get_token + begin + response = @@client.call(:authenticate, message: { username: ENV['USER'], password: @@password, organization: "", domain: @@domain }).hash + if response[:envelope][:body][:authenticate_response][:authenticate_result][:errors] + raise "Error generating the authentication token for user #{ENV['USER']}: #{response[:envelope][:body][:authenticate_response][:authenticate_result][:errors][:string]}" + end + response[:envelope][:body][:authenticate_response][:authenticate_result][:token] + rescue Savon::Error => err + raise "There was an error generating the authentiaton token for user #{ENV['USER']}: #{err}" + end + end + + ## Get a secret returned as a hash + # Will raise an error if there was an issue getting the secret + # @param [Integer] the secret id + # @return [Hash] the secret hash retrieved from the wsdl + + def get_secret(scrt_id, token = nil) + begin + secret = @@client.call(:get_secret, message: { token: token || get_token, secretId: scrt_id}).hash + if secret[:envelope][:body][:get_secret_response][:get_secret_result][:errors] + raise "There was an error getting secret #{scrt_id}: #{secret[:envelope][:body][:get_secret_response][:get_secret_result][:errors][:string]}" + end + return secret + rescue Savon::Error => err + raise "There was an error getting the secret with id #{scrt_id}: #{err}" + end + end + + ## Retrieve a simple password from a secret + # Will raise an error if there are any issues + # @param [Integer] the secret id + # @return [String] the password for the given secret + + def get_password(scrt_id) + begin + secret = get_secret(scrt_id) + return secret[:envelope][:body][:get_secret_response][:get_secret_result][:secret][:items][:secret_item][1][:value] + rescue Savon::Error => err + raise "There was an error getting the password for secret #{scrt_id}: #{err}" + end + end + + ## Get the secret item id that relates to a key file or attachment. + # Will raise on error + # @param [Integer] the secret id + # @param [String] the type of secret item to get, one of privatekey, publickey, attachment + # @return [Integer] the secret item id + + def get_scrt_item_id(scrt_id, type, token) + secret = get_secret(scrt_id, token) + case type + when 'privatekey' + ## Get private key item id + secret[:envelope][:body][:get_secret_response][:get_secret_result][:secret][:items][:secret_item].each do |item| + return item[:id] if item[:field_name] == 'Private Key' + end + when 'publickey' + ## Get public key item id + secret[:envelope][:body][:get_secret_response][:get_secret_result][:secret][:items][:secret_item].each do |item| + return item[:id] if item[:field_name] == 'Public Key' + end + when 'attachment' + ## Get attachment item id. This currently only supports secrets with one attachment. + secret[:envelope][:body][:get_secret_response][:get_secret_result][:secret][:items][:secret_item].each do |item| + return item[:id] if item[:field_name] == 'Attachment' + end + else + raise "Unknown type, #{type}." + end + end + + ## Downloads the private key for a secret and places it where Zanzibar is running, or :path if specified + # Raise on error + # @param [Hash] args, :scrt_id, :scrt_item_id - optional, :path - optional + + def download_private_key(args = {}) + token = get_token + FileUtils.mkdir_p(args[:path]) if args[:path] + path = args[:path] ? args[:path] : '.' ## The File.join below doesn't handle nils well, so let's take that possibility away. + begin + 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 + if response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:errors] + 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]}" + end + 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| + file.puts Base64.decode64(response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:file_attachment]) + end + rescue Savon::Error => err + raise "There was an error getting the private key for secret #{args[:scrt_id]}: #{err}" + end + end + + ## Downloads the public key for a secret and places it where Zanzibar is running, or :path if specified + # Raise on error + # @param [Hash] args, :scrt_id, :scrt_item_id - optional, :path - optional + + def download_public_key(args = {}) + token = get_token + FileUtils.mkdir_p(args[:path]) if args[:path] + path = args[:path] ? args[:path] : '.' ## The File.join below doesn't handle nils well, so let's take that possibility away. + begin + 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 + if response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:errors] + 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]}" + end + 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| + file.puts Base64.decode64(response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:file_attachment]) + end + rescue Savon::Error => err + raise "There was an error getting the public key for secret #{args[:scrt_id]}: #{err}" + end + end + + ## Downloads an attachment for a secret and places it where Zanzibar is running, or :path if specified + # Raise on error + # @param [Hash] args, :scrt_id, :scrt_item_id - optional, :path - optional + + def download_attachment(args = {}) + token = get_token + FileUtils.mkdir_p(args[:path]) if args[:path] + path = args[:path] ? args[:path] : '.' ## The File.join below doesn't handle nils well, so let's take that possibility away. + begin + 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 + if response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:errors] + 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]}" + end + 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| + file.puts Base64.decode64(response[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result][:file_attachment]) + end + rescue Savon::Error => err + raise "There was an error getting the attachment from secret #{args[:scrt_id]}: #{err}" + end + end + end +end diff --git a/lib/zanzibar/version.rb b/lib/zanzibar/version.rb new file mode 100644 index 0000000..89f1163 --- /dev/null +++ b/lib/zanzibar/version.rb @@ -0,0 +1,3 @@ +module Zanzibar + VERSION = "0.0.8" +end diff --git a/test/.rspec b/test/.rspec new file mode 100644 index 0000000..83e16f8 --- /dev/null +++ b/test/.rspec @@ -0,0 +1,2 @@ +--color +--require spec_helper diff --git a/test/responses/attachment_response.xml b/test/responses/attachment_response.xml new file mode 100644 index 0000000..bf07e26 --- /dev/null +++ b/test/responses/attachment_response.xml @@ -0,0 +1,12 @@ + + + + + + + SSBhbSBhIHNlY3JldCBhdHRhY2htZW50 + attachment.txt + + + + diff --git a/test/responses/authenticate_response.xml b/test/responses/authenticate_response.xml new file mode 100644 index 0000000..ff4d213 --- /dev/null +++ b/test/responses/authenticate_response.xml @@ -0,0 +1,12 @@ + + + + + + + + imatoken + + + + diff --git a/test/responses/download_private_key_response.xml b/test/responses/download_private_key_response.xml new file mode 100644 index 0000000..588ffb6 --- /dev/null +++ b/test/responses/download_private_key_response.xml @@ -0,0 +1,12 @@ + + + + + + + LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVkgLS0tLS0KemFuemliYXJUZXN0UGFzc3dvcmQKLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0= + zanzi_key + + + + diff --git a/test/responses/download_public_key_response.xml b/test/responses/download_public_key_response.xml new file mode 100644 index 0000000..cac60cc --- /dev/null +++ b/test/responses/download_public_key_response.xml @@ -0,0 +1,12 @@ + + + + + + + MTIzNFB1YmxpY0tleTU2Nzg9PQ== + zanzi_key.pub + + + + diff --git a/test/responses/get_secret_response.xml b/test/responses/get_secret_response.xml new file mode 100644 index 0000000..2a76c9f --- /dev/null +++ b/test/responses/get_secret_response.xml @@ -0,0 +1,57 @@ + + + + + + + + Zanzi Test Secret + + + ZanziUser + 15391 + 284 + Username + false + false + false + Username + + + zanziUserPassword + 15392 + 285 + Password + false + false + true + Password + + + + 15395 + 287 + Attachment + true + false + false + Attachment + + + 1234 + 6028 + 106 + false + true + + + + + + false + + + + + + diff --git a/test/responses/get_secret_with_attachment_response.xml b/test/responses/get_secret_with_attachment_response.xml new file mode 100644 index 0000000..9a4a41c --- /dev/null +++ b/test/responses/get_secret_with_attachment_response.xml @@ -0,0 +1,57 @@ + + + + + + + + Zanzi Secret Attachment + + + N/A + 20144 + 284 + Username + false + false + false + Username + + + N/A + 20145 + 285 + Password + false + false + true + Password + + + + 20148 + 287 + Attachment + true + false + false + Attachment + + + 3456 + 6028 + 85 + false + true + + + + + + false + + + + + + diff --git a/test/responses/get_secret_with_keys_response.xml b/test/responses/get_secret_with_keys_response.xml new file mode 100644 index 0000000..3d0cb4a --- /dev/null +++ b/test/responses/get_secret_with_keys_response.xml @@ -0,0 +1,47 @@ + + + + + + + + Zanzibar Test Keys + + + + 15214 + 486 + Private Key + true + false + false + Private Key + + + + 15215 + 487 + Public Key + true + false + false + Public Key + + + 2345 + 6054 + 85 + false + true + + + + + + false + + + + + + diff --git a/test/scrt.wsdl b/test/scrt.wsdl new file mode 100644 index 0000000..61bb79a --- /dev/null +++ b/test/scrt.wsdl @@ -0,0 +1,629 @@ + + + Webservice for standard integration. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Webservice for standard integration. + + + + + + + + + + + + + + diff --git a/test/spec/spec_helper.rb b/test/spec/spec_helper.rb new file mode 100644 index 0000000..b6a6cf6 --- /dev/null +++ b/test/spec/spec_helper.rb @@ -0,0 +1,90 @@ +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause this +# file to always be loaded, without a need to explicitly require it in any files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +require 'webmock/rspec' +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # These two settings work together to allow you to limit a spec run + # to individual examples or groups you care about by tagging them with + # `:focus` metadata. When nothing is tagged with `:focus`, all examples + # get run. + config.filter_run :focus + config.run_all_when_everything_filtered = true + + # Limits the available syntax to the non-monkey patched syntax that is recommended. + # For more details, see: + # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax + # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching + config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/test/zanzibar_spec.rb b/test/zanzibar_spec.rb new file mode 100644 index 0000000..3c4de9e --- /dev/null +++ b/test/zanzibar_spec.rb @@ -0,0 +1,80 @@ +require '../lib/zanzibar.rb' +require 'savon' +require 'webmock' +require 'rspec' +require 'webmock/rspec' + +include WebMock::API + +describe "Zanzibar Test" do + + client = Zanzibar::Zanzibar.new(:domain => "zanzitest.net", :pwd=>'password', :wsdl => "scrt.wsdl") + auth_xml = File.read('responses/authenticate_response.xml') + secret_xml = File.read('responses/get_secret_response.xml') + secret_with_key_xml = File.read('responses/get_secret_with_keys_response.xml') + secret_with_attachment_xml = File.read('responses/get_secret_with_attachment_response.xml') + private_key_xml = File.read('responses/download_private_key_response.xml') + public_key_xml = File.read('responses/download_public_key_response.xml') + attachment_xml = File.read('responses/attachment_response.xml') + + + it 'should return an auth token' do + stub_request(:any, "https://www.zanzitest.net/webservices/sswebservice.asmx"). + to_return(:body => auth_xml, :status => 200) + + expect(client.get_token).to eq("imatoken") + end + + it 'should get a secret' do + stub_request(:any, "https://www.zanzitest.net/webservices/sswebservice.asmx"). + to_return(:body => auth_xml, :status => 200).then. + to_return(:body => secret_xml, :status => 200) + + expect(client.get_secret(1234)[:envelope][:body][:get_secret_response][:get_secret_result][:secret][:name]).to eq("Zanzi Test Secret") + end + + it 'should get a password' do + stub_request(:any, "https://www.zanzitest.net/webservices/sswebservice.asmx"). + to_return(:body => auth_xml, :status => 200).then. + to_return(:body => secret_xml, :status => 200) + + expect(client.get_password(1234)).to eq("zanziUserPassword") + end + + it 'should download a private key' do + stub_request(:any, "https://www.zanzitest.net/webservices/sswebservice.asmx"). + to_return(:body => auth_xml, :status => 200).then. + to_return(:body => secret_with_key_xml, :status => 200).then. + to_return(:body => private_key_xml, :status => 200) + + client.download_private_key(:scrt_id => 2345) + expect(File.exist? 'zanzi_key') + expect(File.read('zanzi_key')).to eq("-----BEGIN RSA PRIVATE KEY -----\nzanzibarTestPassword\n-----END RSA PRIVATE KEY-----\n") + File.delete('zanzi_key') + end + + + it 'should download a public key' do + stub_request(:any, "https://www.zanzitest.net/webservices/sswebservice.asmx"). + to_return(:body => auth_xml, :status => 200).then. + to_return(:body => secret_with_key_xml, :status => 200).then. + to_return(:body => public_key_xml, :status => 200) + + client.download_public_key(:scrt_id => 2345) + expect(File.exist? 'zanzi_key.pub') + expect(File.read('zanzi_key.pub')).to eq("1234PublicKey5678==\n") + File.delete('zanzi_key.pub') + end + + it 'should download an attachment' do + stub_request(:any, "https://www.zanzitest.net/webservices/sswebservice.asmx"). + to_return(:body => auth_xml, :status => 200).then. + to_return(:body => secret_with_attachment_xml, :status => 200).then. + to_return(:body => attachment_xml, :status => 200) + + client.download_attachment(:scrt_id => 3456) + expect(File.exist? 'attachment.txt') + expect(File.read('attachment.txt')).to eq("I am a secret attachment\n") + File.delete('attachment.txt') + end +end diff --git a/zanzibar.gemspec b/zanzibar.gemspec new file mode 100644 index 0000000..8e223d1 --- /dev/null +++ b/zanzibar.gemspec @@ -0,0 +1,24 @@ +# coding: utf-8 +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'zanzibar/version' + +Gem::Specification.new do |spec| + spec.name = "zanzibar" + spec.version = Zanzibar::VERSION + spec.authors = ["Jason Davis-Cooke"] + spec.email = ["jdaviscooke@cimpress.com"] + spec.summary = "Retrieve secrets from Secret Server" + spec.description = "Programatically get secrets from Secret Server via the Web Service API" + spec.homepage = "https://github.com/Cimpress-MCP/zanzibar" + spec.license = "Apache 2.0" + + spec.files = `git ls-files -z`.split("\x0") + spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } + spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.require_paths = ["lib"] + + spec.add_development_dependency "bundler", "~> 1.7" + spec.add_development_dependency "rake", "~> 10.0" + spec.add_runtime_dependency "savon", "~> 2.8.0" +end