skles 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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