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 +5 -0
- data/.gitignore +25 -0
- data/.rspec +1 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +38 -0
- data/LICENSE +20 -0
- data/README.textile +22 -0
- data/Rakefile +37 -0
- data/VERSION +1 -0
- data/lib/skles.rb +153 -0
- data/lib/skles_api.rb +113 -0
- data/skles.gemspec +61 -0
- data/spec/skles_api_spec.rb +130 -0
- data/spec/skles_spec.rb +97 -0
- data/spec/spec_helper.rb +9 -0
- metadata +94 -0
data/.document
ADDED
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
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
|
data/spec/skles_spec.rb
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
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
|