skles 1.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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,25 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ pkg
18
+ .rvm
19
+ .idea
20
+ .rvmrc
21
+ .bundle
22
+
23
+ ## PROJECT::DOCUMENTATION
24
+ .yardoc
25
+ doc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -cfs
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source :rubygems
2
+
3
+ # DEPENDENCIES
4
+ gem 'savon'
5
+
6
+ # DEVELOPMENT
7
+ gem 'jeweler'
8
+ gem 'yard'
9
+ gem 'RedCloth', require: 'redcloth'
10
+
11
+ # TEST
12
+ gem 'rspec'
data/Gemfile.lock ADDED
@@ -0,0 +1,38 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ RedCloth (4.2.3)
5
+ builder (2.1.2)
6
+ crack (0.1.8)
7
+ diff-lcs (1.1.2)
8
+ gemcutter (0.6.1)
9
+ git (1.2.5)
10
+ jeweler (1.4.0)
11
+ gemcutter (>= 0.1.0)
12
+ git (>= 1.2.5)
13
+ rubyforge (>= 2.0.0)
14
+ json_pure (1.4.6)
15
+ rspec (2.1.0)
16
+ rspec-core (~> 2.1.0)
17
+ rspec-expectations (~> 2.1.0)
18
+ rspec-mocks (~> 2.1.0)
19
+ rspec-core (2.1.0)
20
+ rspec-expectations (2.1.0)
21
+ diff-lcs (~> 1.1.2)
22
+ rspec-mocks (2.1.0)
23
+ rubyforge (2.0.4)
24
+ json_pure (>= 1.1.7)
25
+ savon (0.7.9)
26
+ builder (>= 2.1.2)
27
+ crack (>= 0.1.4)
28
+ yard (0.6.1)
29
+
30
+ PLATFORMS
31
+ ruby
32
+
33
+ DEPENDENCIES
34
+ RedCloth
35
+ jeweler
36
+ rspec
37
+ savon
38
+ yard
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Tim Morgan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,22 @@
1
+ h1. SKLES: Ruby interface for StrongKey Lite boxes
2
+
3
+ | *Author* | Tim Morgan |
4
+ | *Version* | Version 1.0 (Nov 13, 2010) |
5
+ | *License* | Released under the MIT license. |
6
+
7
+ The SKLES gem is an interface to StrongAuth's StrongKey Lite credit card vault
8
+ system (http://www.strongauth.com/). You will need a StrongKey Lite install to
9
+ make any reasonable use of this gem.
10
+
11
+
12
+ Usage is simple:
13
+
14
+ <pre><code>
15
+ require 'skles'
16
+ skles = StrongKeyLite.new('http://your.strongauth.server', your_domain_id)
17
+ skles.add_user('encrypt_only', 'password', :encrypt)
18
+ skles.add_user('decrypt_only', 'password', :decrypt)
19
+
20
+ skles.encrypt('1234123412341234') #=> token
21
+ skles.decrypt(token) #=> credit card number
22
+ </code></pre>
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rake'
2
+ begin
3
+ require 'bundler'
4
+ rescue LoadError
5
+ puts "Bundler is not installed; install with `gem install bundler`."
6
+ exit 1
7
+ end
8
+
9
+ Bundler.require :default
10
+
11
+ Jeweler::Tasks.new do |gem|
12
+ gem.name = "skles"
13
+ gem.summary = %Q{Ruby interface for SKLES (StrongKey Light Encryption System) boxes}
14
+ gem.description = %Q{A Ruby wrapper around the StrongKey Lite SOAP client API.}
15
+ gem.email = "git@timothymorgan.info"
16
+ gem.homepage = "http://github.com/RISCfuture/skles"
17
+ gem.authors = [ "Tim Morgan" ]
18
+ gem.add_dependency 'savon'
19
+ gem.required_ruby_version = '>= 1.9'
20
+ end
21
+ Jeweler::GemcutterTasks.new
22
+
23
+ require 'rspec/core/rake_task'
24
+ RSpec::Core::RakeTask.new
25
+
26
+ YARD::Rake::YardocTask.new('doc') do |doc|
27
+ doc.options << "-m" << "textile"
28
+ doc.options << "--protected"
29
+ doc.options << "--no-private"
30
+ doc.options << "-r" << "README.textile"
31
+ doc.options << "-o" << "doc"
32
+ doc.options << "--title" << "Ruby SKLES Documentation".inspect
33
+
34
+ doc.files = [ 'lib/**/*', 'README.textile' ]
35
+ end
36
+
37
+ task(default: :spec)
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/lib/skles.rb ADDED
@@ -0,0 +1,153 @@
1
+ require 'savon'
2
+ require File.dirname(__FILE__) + '/skles_api'
3
+
4
+ # can't have plaintext CC #s being logged
5
+ Savon::Request.log = false
6
+
7
+ # Client for the StrongKey Lite Encryption System (SKLES) SOAP-based API. An
8
+ # instance of this API interfaces with your StrongKey Lite box to encrypt and
9
+ # decrypt credit card numbers into the vault.
10
+ #
11
+ # Since many StrongKey Lite setups use different logins to perform different
12
+ # tasks (e.g., a more secure login/password is used to decrypt credit cards than
13
+ # to encrypt them), this class supports storing multiple sets of credentials,
14
+ # choosing them depending on the operation being performed.
15
+ #
16
+ # @example Single-user SKLES interface for the test domain
17
+ # skles = StrongKeyLite.new("https://demo.strongauth.com:8181", # the URL to the demo StrongKey Lite service
18
+ # 1, # your domain ID
19
+ # login: 'mylogin', password: 'mypassword' # your API user login and password for the demo box
20
+ # http: { verify_mode: OpenSSL::SSL::VERIFY_NONE }, # the demo service has an invalid cert, so we override cert verification
21
+ #
22
+ # @example Multi-user SKLES interface for a production domain
23
+ # skles = StrongKeyLite.new("https://strongauth.company.com:8181", 15)
24
+ # skles.add_user 'encrypt_only', 'thepassword', :encrypt, :batch_encrypt
25
+ # skles.add_user 'decrypt', 'anotherpassword', :decrypt, :batch_decrypt
26
+
27
+ class StrongKeyLite
28
+ include API
29
+
30
+ # The domain ID of the StrongKey service.
31
+ attr_accessor :domain_id
32
+
33
+ # Creates a new client interface.
34
+ #
35
+ # @param [String] service_url The protocol, host, and port for your StrongKey
36
+ # Lite service; _e.g._, "http://demo.strongauth.com:8181"
37
+ # @param [Fixnum] domain_id The domain ID.
38
+ # @param [Hash] options Additional options.
39
+ # @option options [String] :login You can provide the login of a user who will
40
+ # be used for all actions.
41
+ # @option options [String] :password The password for this user.
42
+ # @option options [Hash] :http Additional options to be given to the
43
+ # @Net::HTTP@ object. The keys will be invoked as setter methods on the HTTP
44
+ # object (_e.g._, passing @http: { timeout: 60 }@ will result in a call like
45
+ # @http.timeout = 60@).
46
+
47
+ def initialize(service_url, domain_id, options={})
48
+ @client = Savon::Client.new("#{service_url}/strongkeyliteWAR/EncryptionService?wsdl")
49
+ options[:http].each { |key, val| @client.request.http.send :"#{key}=", val } if options[:http].kind_of?(Hash)
50
+
51
+ self.domain_id = domain_id
52
+
53
+ @users = {}
54
+ @users_for_action = {}
55
+
56
+ add_user(options[:login], options[:password], :all) if options[:login] and options[:password]
57
+ end
58
+
59
+ # Adds a user by login and password. These users are used to perform API
60
+ # actions.
61
+ #
62
+ # @overload add_user(login, password)
63
+ # Adds a user. You can tell the client to use this user for certain actions
64
+ # by calling {#set_user_for_actions}.
65
+ # @overload add_user(login, password, action, ...)
66
+ # Adds a user and tells the client to use this user for the given list of
67
+ # actions.
68
+ # @param [Symbol] action An API action (such as @:ping@) that this user
69
+ # should be used to perform. Replaces the previous user assigned to this
70
+ # action.
71
+ # @raise [ArgumentError] If an unknown action is provided.
72
+ # @overload add_user(login, password, :all)
73
+ # Adds a user and tells the client to use this user for all API actions.
74
+ # @param [String] login The user's login.
75
+ # @param [String] password The user's password.
76
+
77
+ def add_user(login, password, *actions_for_user)
78
+ @users[login] = password
79
+ if actions_for_user == [ :all ] then
80
+ actions.each { |action| set_user_for_action(login, action) }
81
+ else
82
+ actions_for_user.each { |action| set_user_for_action(login, action) }
83
+ end
84
+ end
85
+
86
+ # @overload set_user_for_actions(login, action, ...)
87
+ # Tells the client to use this user for a list of actions. Calls made via
88
+ # the API of one of these actions will use this user. Replaces the previous
89
+ # user assigned to these actions.
90
+ # @param [String] login The user's login.
91
+ # @param [Symbol] the API action (such as @:ping@).
92
+ # @raise [ArgumentError] If an unknown action is provided.
93
+
94
+ def set_user_for_actions(login, *actions_for_user)
95
+ actions.flatten!
96
+ raise ArgumentError, "Unknown action(s): #{(actions_for_user - actions).join(',' )}" unless (actions_for_user - actions).empty?
97
+ actions_for_user.each { |action| @users_for_action[action] = login }
98
+ end
99
+ alias_method :set_user_for_action, :set_user_for_actions
100
+
101
+ # @return [Array<Symbol>] A list of actions that the API can perform.
102
+
103
+ def actions
104
+ @actions ||= @client.wsdl.soap_actions
105
+ end
106
+
107
+ # Makes an API call and returns the result as a hash. This method is the basis
108
+ # of all the more high-level API methods.
109
+ #
110
+ # @param [Symbol] meth The API method.
111
+ # @param [Hash] options The arguments for the API method. The @:did@,
112
+ # @:login@, and @:password@ arguments are set for you automatically.
113
+ # @return [Hash] The response fields.
114
+ # @raise [SOAPError] If a SOAP fault occurs.
115
+ # @raise [HTTPError] If an HTTP error occurs.
116
+
117
+ def call(meth, options={})
118
+ raise ArgumentError, "Unknown action #{meth.inspect}" unless actions.include?(meth)
119
+
120
+ login = @users_for_action[meth]
121
+ raise "No user has been assigned to action #{meth.inspect}" unless login
122
+ password = @users[login]
123
+
124
+ response = @client.send(meth) { |soap| soap.body = { did: domain_id, username: login, password: password }.merge(options) }
125
+ raise SOAPError(response.soap_fault, response) if response.soap_fault?
126
+ raise HTTPError(response.http_error, response) if response.http_error?
127
+
128
+ return response.to_hash
129
+ end
130
+
131
+ # Superclass of all {StrongKeyLite} exceptions.
132
+
133
+ class ResponseError < StandardError
134
+
135
+ # The @Savon::Response@ object resulting from the API call.
136
+ attr_reader :response
137
+
138
+ # @private
139
+ def initialize(msg, response)
140
+ super msg
141
+ @response = response
142
+ end
143
+ end
144
+
145
+ # Raised when SOAP responses indicate errors.
146
+
147
+ class SOAPError < ResponseError; end
148
+
149
+ # Raised when @Net::HTTP@ returns a response other than 200 OK, or there is a
150
+ # socket error.
151
+
152
+ class HTTPError < ResponseError; end
153
+ end
data/lib/skles_api.rb ADDED
@@ -0,0 +1,113 @@
1
+ class StrongKeyLite
2
+
3
+ # Module included into {StrongKeyLite} with higher-level API actions.
4
+
5
+ module API
6
+
7
+ # Pings the service and returns information about its health. You must have
8
+ # a user set for the @:ping@ API action.
9
+ #
10
+ # @return [Hash] A hash of service status information (see example).
11
+ # @example Example response
12
+ # { :version => "1.0",
13
+ # :build => 40,
14
+ # :hostname => "demo.strongauth.com",
15
+ # :current_time => #<Time Thu Nov 11 18:52:45 PST 2010>,
16
+ # :up_since => #<Time Mon Sep 27 20:58:05 PDT 2010>,
17
+ # :well_known_pan => 1235711131719230,
18
+ # :encryptions_since_startup => 6,
19
+ # :encryptions_total => 17,
20
+ # :decryptions_since_startup => 9,
21
+ # :decryptions_total => 20,
22
+ # :deletions_since_startup => 0,
23
+ # :deletions_total => 0,
24
+ # :searches_since_startup => 1,
25
+ # :searches_total => 3,
26
+ # :batch_operations_since_startup => 0,
27
+ # :batch_operations_total => 0,
28
+ # :domain_id => 21
29
+ # }
30
+
31
+ def ping
32
+ msg = call(:ping)[:ping_response][:return]
33
+ info = Hash.new
34
+ msg.each_line do |line|
35
+ if line =~ /^SKLES (.+?) \(Build (\d+)\)$/
36
+ info[:version] = $1
37
+ info[:build] = $2.to_i
38
+ elsif line =~ /^Hostname: (.+?)$/ then
39
+ info[:hostname] = $1
40
+ elsif line =~ /^Current time: (.+?)$/ then
41
+ info[:current_time] = Time.parse($1)
42
+ elsif line =~ /^Up since: (.+?)$/ then
43
+ info[:up_since] = Time.parse($1)
44
+ elsif line =~ /^Well-known PAN: (\d+?)$/ then
45
+ info[:well_known_pan] = $1.to_i
46
+ elsif line =~ /^ENC: (\d+)\/(\d+)$/ then
47
+ info[:encryptions_since_startup] = $1.to_i
48
+ info[:encryptions_total] = $2.to_i
49
+ elsif line =~ /^DEC: (\d+)\/(\d+)$/ then
50
+ info[:decryptions_since_startup] = $1.to_i
51
+ info[:decryptions_total] = $2.to_i
52
+ elsif line =~ /^DEL: (\d+)\/(\d+)$/ then
53
+ info[:deletions_since_startup] = $1.to_i
54
+ info[:deletions_total] = $2.to_i
55
+ elsif line =~ /^SRC: (\d+)\/(\d+)$/ then
56
+ info[:searches_since_startup] = $1.to_i
57
+ info[:searches_total] = $2.to_i
58
+ elsif line =~ /^BAT: (\d+)\/(\d+)$/ then
59
+ info[:batch_operations_since_startup] = $1.to_i
60
+ info[:batch_operations_total] = $2.to_i
61
+ elsif line =~ /SKLES Domain (\d+) is (.+?)$/ then
62
+ info[:domain_id] = $1.to_i
63
+ end
64
+ end
65
+
66
+ return info
67
+ end
68
+
69
+ # Stores a credit card number (or any other plain text content) to the vault
70
+ # and returns an obscured token for later retrieval.
71
+ #
72
+ # @param [String] plaintext The text to encrypt and store.
73
+ # @return [String] A token that can be used to {#decrypt} the text. The text
74
+ # is not derivable from the token without access to the StrongKey Lite
75
+ # server.
76
+
77
+ def encrypt(plaintext)
78
+ call(:encrypt, plaintext: plaintext)[:encrypt_response][:return]
79
+ end
80
+
81
+ # Retrieves a credit card number (or any other encrypted content) from the
82
+ # vault using a ciphered token generated by a call to {#encrypt}.
83
+ #
84
+ # @param [String] token The ciphertext returned from @encrypt@.
85
+ # @return [String] The text that was encrypted.
86
+
87
+ def decrypt(token)
88
+ call(:decrypt, token: token)[:decrypt_response][:return]
89
+ end
90
+
91
+ # Removes a credit card number (or any other encrypted content) from the
92
+ # vault.
93
+ #
94
+ # @param [String] token The ciphertext returned from {#encrypt}.
95
+ # @return [true, false] Whether or not the encrypted content was
96
+ # successfully deleted.
97
+
98
+ def delete(token)
99
+ call(:delete, token: token)[:delete_response][:return]
100
+ end
101
+
102
+ # Determines if a credit card number (or any other plain text content) is
103
+ # stored in the vault. If so, returns its token.
104
+ #
105
+ # @param [String] plaintext The text to search for.
106
+ # @return [String, nil] The token for the text, if stored, or @nil@ if no
107
+ # such text is stored in the vault.
108
+
109
+ def search(plaintext)
110
+ call(:search, plaintext: plaintext)[:search_response][:return]
111
+ end
112
+ end
113
+ end
data/skles.gemspec ADDED
@@ -0,0 +1,61 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{skles}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Tim Morgan"]
12
+ s.date = %q{2010-11-13}
13
+ s.description = %q{A Ruby wrapper around the StrongKey Lite SOAP client API.}
14
+ s.email = %q{git@timothymorgan.info}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.textile"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ ".rspec",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE",
26
+ "README.textile",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "lib/skles.rb",
30
+ "lib/skles_api.rb",
31
+ "skles.gemspec",
32
+ "spec/skles_api_spec.rb",
33
+ "spec/skles_spec.rb",
34
+ "spec/spec_helper.rb"
35
+ ]
36
+ s.homepage = %q{http://github.com/RISCfuture/skles}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.required_ruby_version = Gem::Requirement.new(">= 1.9")
40
+ s.rubygems_version = %q{1.3.7}
41
+ s.summary = %q{Ruby interface for SKLES (StrongKey Light Encryption System) boxes}
42
+ s.test_files = [
43
+ "spec/skles_api_spec.rb",
44
+ "spec/skles_spec.rb",
45
+ "spec/spec_helper.rb"
46
+ ]
47
+
48
+ if s.respond_to? :specification_version then
49
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
50
+ s.specification_version = 3
51
+
52
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
53
+ s.add_runtime_dependency(%q<savon>, [">= 0"])
54
+ else
55
+ s.add_dependency(%q<savon>, [">= 0"])
56
+ end
57
+ else
58
+ s.add_dependency(%q<savon>, [">= 0"])
59
+ end
60
+ end
61
+
@@ -0,0 +1,130 @@
1
+ require 'spec_helper'
2
+
3
+ describe StrongKeyLite::API do
4
+ before :each do
5
+ @client = mock('Savon::Client', request: nil, wsdl: mock('Savon::WSDL', soap_actions: [ :ping ]))
6
+ Savon::Client.stub!(:new).and_return(@client)
7
+ @response = mock('Soap::Response', :soap_fault? => false, :http_error? => false, soap_fault: nil, http_error: nil, to_hash: {})
8
+ @skles = StrongKeyLite.new('http://test.host', 1, login: 'login', password: 'password')
9
+ end
10
+
11
+ describe "#ping" do
12
+ before :each do
13
+ @time = mock('Time')
14
+ Time.stub!(:parse).and_return(@time)
15
+ @client.should_receive(:ping).once.and_return(@response)
16
+ end
17
+
18
+ it "should parse the ping response" do
19
+ ping_response = <<-EOF
20
+ SKLES 1.0 (Build 40)
21
+ Hostname: demo.strongauth.com
22
+ Current time: Sat Nov 13 12:44:03 PST 2010
23
+ Up since: Mon Sep 27 20:58:05 PDT 2010
24
+ Well-known PAN: 1235711131719230
25
+ ENC: 8/19
26
+ DEC: 10/21
27
+ DEL: 1/1
28
+ SRC: 11/13
29
+ BAT: 0/0
30
+ SKLES Domain 21 is alive!
31
+ EOF
32
+
33
+ @response.stub(:to_hash).and_return(ping_response: { return: ping_response })
34
+ @skles.ping.should eql({ version: "1.0", build: 40, hostname: "demo.strongauth.com",
35
+ current_time: @time, up_since: @time,
36
+ well_known_pan: 1235711131719230,
37
+ encryptions_since_startup: 8, encryptions_total: 19,
38
+ decryptions_since_startup: 10, decryptions_total: 21,
39
+ deletions_since_startup: 1, deletions_total: 1,
40
+ searches_since_startup: 11, searches_total: 13,
41
+ batch_operations_since_startup: 0, batch_operations_total: 0,
42
+ domain_id: 21 })
43
+ end
44
+
45
+ it "should not error if the response is malformed" do
46
+ ping_response = <<-EOF
47
+ SKLES 1.0 (Build 40)
48
+ Hostname: demo.strongauth.com
49
+ Current time: Sat Nov 13 12:44:03 PST 2010
50
+ Up since: Mon Sep 27 20:58:05 PDT 2010
51
+ Well-known PAN: 1235711131719230
52
+ ENC: 8/19
53
+ DEL: 1/1
54
+ SRC: 11/13
55
+ BAT: 0/0
56
+ SKLES Domain 21 is alive!
57
+ EOF
58
+
59
+ @response.stub(:to_hash).and_return(ping_response: { return: ping_response })
60
+ @skles.ping.should eql({ version: "1.0", build: 40, hostname: "demo.strongauth.com",
61
+ current_time: @time, up_since: @time,
62
+ well_known_pan: 1235711131719230,
63
+ encryptions_since_startup: 8, encryptions_total: 19,
64
+ deletions_since_startup: 1, deletions_total: 1,
65
+ searches_since_startup: 11, searches_total: 13,
66
+ batch_operations_since_startup: 0, batch_operations_total: 0,
67
+ domain_id: 21 })
68
+ end
69
+ end
70
+
71
+ describe "#encrypt" do
72
+ it "should make the appropriate API call" do
73
+ @skles.stub!(:actions).and_return([ :encrypt ])
74
+ @skles.add_user('login', 'password', :encrypt)
75
+
76
+ @response.stub(:to_hash).and_return(encrypt_response: { return: '123456' })
77
+ soap = mock('Savon::SOAP')
78
+ soap.should_receive(:body=).once.with(hash_including(plaintext: 'plaintext'))
79
+
80
+ @client.should_receive(:encrypt).once.and_yield(soap).and_return(@response)
81
+
82
+ @skles.encrypt('plaintext').should eql('123456')
83
+ end
84
+ end
85
+
86
+ describe "#decrypt" do
87
+ it "should make the appropriate API call" do
88
+ @skles.stub!(:actions).and_return([ :decrypt ])
89
+ @skles.add_user('login', 'password', :decrypt)
90
+
91
+ @response.stub(:to_hash).and_return(decrypt_response: { return: 'plaintext' })
92
+ soap = mock('Savon::SOAP')
93
+ soap.should_receive(:body=).once.with(hash_including(token: '123456'))
94
+
95
+ @client.should_receive(:decrypt).once.and_yield(soap).and_return(@response)
96
+
97
+ @skles.decrypt('123456').should eql('plaintext')
98
+ end
99
+ end
100
+
101
+ describe "#delete" do
102
+ it "should make the appropriate API call" do
103
+ @skles.stub!(:actions).and_return([ :delete ])
104
+ @skles.add_user('login', 'password', :delete)
105
+
106
+ @response.stub(:to_hash).and_return(delete_response: { return: true })
107
+ soap = mock('Savon::SOAP')
108
+ soap.should_receive(:body=).once.with(hash_including(token: '123456'))
109
+
110
+ @client.should_receive(:delete).once.and_yield(soap).and_return(@response)
111
+
112
+ @skles.delete('123456').should be_true
113
+ end
114
+ end
115
+
116
+ describe "#search" do
117
+ it "should make the appropriate API call" do
118
+ @skles.stub!(:actions).and_return([ :search ])
119
+ @skles.add_user('login', 'password', :search)
120
+
121
+ @response.stub(:to_hash).and_return(search_response: { return: '123456' })
122
+ soap = mock('Savon::SOAP')
123
+ soap.should_receive(:body=).once.with(hash_including(plaintext: 'plaintext'))
124
+
125
+ @client.should_receive(:search).once.and_yield(soap).and_return(@response)
126
+
127
+ @skles.search('plaintext').should eql('123456')
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+ describe StrongKeyLite do
4
+ before :each do
5
+ @client = mock('Savon::Client', request: nil)
6
+ Savon::Client.stub!(:new).and_return(@client)
7
+ end
8
+
9
+ describe "#initialize" do
10
+ it "should accept a host for the WSDL" do
11
+ Savon::Client.should_receive(:new).once.with("http://test.host/strongkeyliteWAR/EncryptionService?wsdl").and_return(@client)
12
+ StrongKeyLite.new('http://test.host', 1)
13
+ end
14
+
15
+ it "should set the domain ID" do
16
+ StrongKeyLite.new('http://test.host', 15).domain_id.should eql(15)
17
+ end
18
+
19
+ it "should accept and apply HTTP options" do
20
+ http = mock('Net::HTTP')
21
+ request = mock('Savon::Request', http: http)
22
+ @client.stub!(:request).and_return(request)
23
+
24
+ http.should_receive(:timeout=).once.with(60)
25
+ StrongKeyLite.new('http://test.host', 1, http: { timeout: 60 })
26
+ end
27
+
28
+ it "should optionally accept a login and password" do
29
+ pending "Need a good way to test this"
30
+ end
31
+ end
32
+
33
+ describe "#call" do
34
+ before :each do
35
+ @client = mock('Savon::Client', request: nil, wsdl: mock('Savon::WSDL', soap_actions: [ :ping ]))
36
+ Savon::Client.stub!(:new).and_return(@client)
37
+ @skles = StrongKeyLite.new('http://test.host', 1)
38
+
39
+ @response = mock('Soap::Response', :soap_fault? => false, :http_error? => false, soap_fault: nil, http_error: nil, to_hash: {})
40
+ @response.stub(:to_hash).and_return(ping_response: { return: '' })
41
+ end
42
+
43
+ it "should raise an error if no user has been assigned to the action" do
44
+ -> { @skles.ping }.should raise_error(/No user/)
45
+ end
46
+
47
+ it "should invoke the proper action on the Savon client and use the appropriate user" do
48
+ @skles.add_user('login', 'password', :ping)
49
+
50
+ soap = mock('Savon::Request')
51
+ soap.should_receive(:body=).once.with({ did: 1, username: 'login', password: 'password' })
52
+ @client.should_receive(:ping).once.and_yield(soap).and_return(@response)
53
+ @skles.ping
54
+ end
55
+
56
+ it "should assign a user to all actions when given :all" do
57
+ @skles.add_user('all', 'password', :all)
58
+
59
+ soap = mock('Savon::Request')
60
+ soap.should_receive(:body=).once.with({ did: 1, username: 'all', password: 'password' })
61
+ @client.should_receive(:ping).once.and_yield(soap).and_return(@response)
62
+ @skles.ping
63
+ end
64
+
65
+ it "should replace an older user assigned to an action" do
66
+ @skles.add_user('all', 'password', :all)
67
+ @skles.add_user('ping', 'password', :ping)
68
+
69
+ soap = mock('Savon::Request')
70
+ soap.should_receive(:body=).once.with({ did: 1, username: 'ping', password: 'password' })
71
+ @client.should_receive(:ping).once.and_yield(soap).and_return(@response)
72
+ @skles.ping
73
+ end
74
+ end
75
+
76
+ describe "#actions" do
77
+ before :each do
78
+ @wsdl = mock('Savon::WSDL')
79
+ @client = mock('Savon::Client', request: nil, wsdl: @wsdl)
80
+ Savon::Client.stub!(:new).and_return(@client)
81
+ @skles = StrongKeyLite.new('http://test.host', 1)
82
+ end
83
+
84
+ it "should return a list of SOAP actions" do
85
+ @wsdl.should_receive(:soap_actions).once.and_return([ :one, :two, :three ])
86
+ @skles.actions.should eql([ :one, :two, :three ])
87
+ end
88
+
89
+ it "should cache the list" do
90
+ @wsdl.should_receive(:soap_actions).once.and_return([ :one, :two, :three ])
91
+ @skles.actions.should eql([ :one, :two, :three ])
92
+
93
+ @wsdl.should_not_receive(:soap_actions)
94
+ @skles.actions.should eql([ :one, :two, :three ])
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ Bundler.require :test
5
+ require 'skles'
6
+
7
+ RSpec.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: skles
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Tim Morgan
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-11-13 00:00:00 -08:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: savon
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ prerelease: false
32
+ version_requirements: *id001
33
+ description: A Ruby wrapper around the StrongKey Lite SOAP client API.
34
+ email: git@timothymorgan.info
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files:
40
+ - LICENSE
41
+ - README.textile
42
+ files:
43
+ - .document
44
+ - .gitignore
45
+ - .rspec
46
+ - Gemfile
47
+ - Gemfile.lock
48
+ - LICENSE
49
+ - README.textile
50
+ - Rakefile
51
+ - VERSION
52
+ - lib/skles.rb
53
+ - lib/skles_api.rb
54
+ - skles.gemspec
55
+ - spec/skles_api_spec.rb
56
+ - spec/skles_spec.rb
57
+ - spec/spec_helper.rb
58
+ has_rdoc: true
59
+ homepage: http://github.com/RISCfuture/skles
60
+ licenses: []
61
+
62
+ post_install_message:
63
+ rdoc_options:
64
+ - --charset=UTF-8
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 1
74
+ - 9
75
+ version: "1.9"
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ requirements: []
85
+
86
+ rubyforge_project:
87
+ rubygems_version: 1.3.7
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: Ruby interface for SKLES (StrongKey Light Encryption System) boxes
91
+ test_files:
92
+ - spec/skles_api_spec.rb
93
+ - spec/skles_spec.rb
94
+ - spec/spec_helper.rb