exact4r 0.5 → 1.7
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/CHANGELOG +69 -0
- data/LICENCE +3 -0
- data/README +186 -0
- data/Rakefile +74 -0
- data/VERSION +1 -0
- data/certs/e-xact.com.crt +31 -0
- data/certs/exact.cer +10 -10
- data/certs/valicert_class2_root.crt +18 -0
- data/lib/ews/certificate_helper.rb +68 -0
- data/lib/ews/transaction/fake_response.rb +137 -0
- data/lib/ews/transaction/mapping.rb +87 -65
- data/lib/ews/transaction/request.rb +51 -62
- data/lib/ews/transaction/response.rb +11 -2
- data/lib/ews/transaction/rexml-expansion-fix.rb +42 -0
- data/lib/ews/transaction/validator.rb +250 -0
- data/lib/ews/transporter.rb +139 -0
- data/lib/exact4r.rb +10 -2
- data/prod.log +49 -0
- data/test/credentials.rb +63 -0
- data/test/credentials.yml +53 -0
- data/test/exhaustive/batch_query_close_test.rb +205 -0
- data/test/exhaustive/forced_post_test.rb +81 -0
- data/test/exhaustive/online_debit_purchase_test.rb +70 -0
- data/test/exhaustive/online_debit_refund_test.rb +70 -0
- data/test/exhaustive/pre_auth_completion_test.rb +99 -0
- data/test/exhaustive/pre_auth_only_test.rb +74 -0
- data/test/exhaustive/pre_auth_test.rb +68 -0
- data/test/exhaustive/purchase_correction_test.rb +85 -0
- data/test/exhaustive/purchase_test.rb +68 -0
- data/test/exhaustive/recurring_seed_pre_auth_test.rb +68 -0
- data/test/exhaustive/recurring_seed_purchase_test.rb +68 -0
- data/test/exhaustive/referenced_void_test.rb +131 -0
- data/test/exhaustive/refund_correction_test.rb +85 -0
- data/test/exhaustive/refund_test.rb +68 -0
- data/test/exhaustive/secure_storage_test.rb +75 -0
- data/test/exhaustive/tagged_online_debit_refund_test.rb +195 -0
- data/test/exhaustive/tagged_pre_auth_completion_test.rb +119 -0
- data/test/exhaustive/tagged_pre_auth_test.rb +116 -0
- data/test/exhaustive/tagged_purchase_test.rb +116 -0
- data/test/exhaustive/tagged_refund_test.rb +142 -0
- data/test/exhaustive/tagged_update_test.rb +158 -0
- data/test/exhaustive/tagged_void_test.rb +174 -0
- data/test/exhaustive/transaction_details_test.rb +145 -0
- data/test/exhaustive/void_test.rb +118 -0
- data/test/general/avs_test.rb +87 -0
- data/test/general/client_certificate_test.rb +64 -0
- data/test/general/json_encoding_test.rb +62 -0
- data/test/general/request_test.rb +179 -0
- data/test/general/rest_encoding_test.rb +174 -0
- data/test/general/soap_encoding_test.rb +211 -0
- data/test/general/transporter_test.rb +74 -0
- data/test/general/validator_test.rb +150 -0
- data/test/samples/dsa_cert.pem +22 -0
- data/test/samples/dsa_key.pem +12 -0
- data/test/samples/rest.dodgy.response.xml +60 -0
- data/test/samples/rest.everything.response.xml +67 -0
- data/test/samples/rest.response.xml +60 -0
- data/test/samples/rsa_cert.pem +63 -0
- data/test/samples/rsa_key.pem +15 -0
- data/test/samples/soap.deserialization.fault.xml +10 -0
- data/test/samples/soap.dodgy.response.xml +95 -0
- data/test/samples/soap.everything.response.xml +75 -0
- data/test/samples/soap.generalfailure.fault.xml +13 -0
- data/test/samples/soap.nulltransaction.fault.xml +14 -0
- data/test/samples/soap.response.xml +95 -0
- data/test/test_helper.rb +107 -0
- metadata +127 -45
- data/doc/classes/EWS/Transaction/Request.html +0 -488
- data/doc/classes/EWS/Transaction/Response.html +0 -280
- data/doc/classes/EWS/Transaction/Transporter.html +0 -251
- data/doc/created.rid +0 -1
- data/doc/files/README.html +0 -230
- data/doc/files/lib/ews/transaction/mapping_rb.html +0 -108
- data/doc/files/lib/ews/transaction/request_rb.html +0 -101
- data/doc/files/lib/ews/transaction/response_rb.html +0 -101
- data/doc/files/lib/ews/transaction/transporter_rb.html +0 -108
- data/doc/files/lib/exact4r_rb.html +0 -113
- data/doc/fr_class_index.html +0 -29
- data/doc/fr_file_index.html +0 -32
- data/doc/fr_method_index.html +0 -33
- data/doc/index.html +0 -24
- data/doc/rdoc-style.css +0 -208
- data/lib/ews/transaction/transporter.rb +0 -128
data/CHANGELOG
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
== v1.7
|
|
2
|
+
Added support for setting a client certificate/key pair for use w/ SSL connections.
|
|
3
|
+
|
|
4
|
+
== v1.6
|
|
5
|
+
Added support for use w/ ActiveSupport v3.
|
|
6
|
+
|
|
7
|
+
== v1.5
|
|
8
|
+
Added support for specifying authorization_num & reference_no in CR requests, to obtain decrypted CC numbers.
|
|
9
|
+
|
|
10
|
+
== v1.4
|
|
11
|
+
Added support for specifying alternative SSL certificates
|
|
12
|
+
|
|
13
|
+
== v1.3
|
|
14
|
+
Added support for TaggedUpdate transactions
|
|
15
|
+
Added support for ReferencedVoid transactions
|
|
16
|
+
|
|
17
|
+
== v1.2
|
|
18
|
+
Updated with new SSL certificates for https://api.e-xact.com
|
|
19
|
+
|
|
20
|
+
== v1.1
|
|
21
|
+
Removed debugger statement. Sorry!
|
|
22
|
+
|
|
23
|
+
== v1.0
|
|
24
|
+
Added support for Batch Query and Batch Close transactions.
|
|
25
|
+
|
|
26
|
+
== v0.9.3
|
|
27
|
+
Reinstated Tagged Void support.
|
|
28
|
+
|
|
29
|
+
== v0.9.2
|
|
30
|
+
Converted tests to Test::Unit
|
|
31
|
+
Added complete test suite, testing all transaction types.
|
|
32
|
+
Enhanced validation of mandatory request information.
|
|
33
|
+
|
|
34
|
+
== v0.9.1
|
|
35
|
+
Added unified Address Verification API
|
|
36
|
+
|
|
37
|
+
== v0.9
|
|
38
|
+
Fixed incorrect decoding of boolean attributes from SOAP response
|
|
39
|
+
|
|
40
|
+
== v0.8
|
|
41
|
+
Added User-Agent string to HTTP requests
|
|
42
|
+
|
|
43
|
+
== v0.7
|
|
44
|
+
Updated with latest certificates for api.e-xact.com
|
|
45
|
+
Fixed SOAP namespace issue
|
|
46
|
+
Ensured expiry_date always submitted at MMYY
|
|
47
|
+
|
|
48
|
+
== v0.6
|
|
49
|
+
Added client-side request validation
|
|
50
|
+
|
|
51
|
+
== v0.5.3
|
|
52
|
+
Added fake response messages for testing purposes
|
|
53
|
+
Moved EWS::Transaction::Transporter to EWS::Transporter
|
|
54
|
+
Fixed typos
|
|
55
|
+
|
|
56
|
+
== v0.5.2
|
|
57
|
+
Updated Transporter to play nicely with mod_security
|
|
58
|
+
Stripped trailing '/'s from URLs
|
|
59
|
+
Transporter ow re-uses connection
|
|
60
|
+
Updated RDoc with test login details
|
|
61
|
+
|
|
62
|
+
== v0.5.1
|
|
63
|
+
Added CHANGELOG, LICENCE & VERSION
|
|
64
|
+
Ensured README etc. were included in gem and displayed as default in RDoc
|
|
65
|
+
Renamed send() to submit() in Transporter
|
|
66
|
+
Fixed path to default E-xact certificates
|
|
67
|
+
|
|
68
|
+
== v0.5
|
|
69
|
+
Initial Release
|
data/LICENCE
ADDED
data/README
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
= exact4r
|
|
2
|
+
A gem which provides access to E-xact's Web Services API, allowing the submission
|
|
3
|
+
of financial transactions via REST, JSON or SOAP.
|
|
4
|
+
|
|
5
|
+
== Getting Started
|
|
6
|
+
|
|
7
|
+
To submit requests to our transaction processing service, you must first have a Gateway ID,
|
|
8
|
+
and a password. Test logins are as follows:
|
|
9
|
+
|
|
10
|
+
Account 1: :gateway_id => "A00049-01", :password => "test1"
|
|
11
|
+
Account 2: :gateway_id => "A00427-01", :password => "testus"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
=1. Submit a transaction
|
|
15
|
+
|
|
16
|
+
require 'rubygems'
|
|
17
|
+
require 'exact4r'
|
|
18
|
+
|
|
19
|
+
# build a purchase request
|
|
20
|
+
request = EWS::Transaction::Request.new({
|
|
21
|
+
:transaction_type => :purchase,
|
|
22
|
+
:amount => 10.50,
|
|
23
|
+
:cardholder_name => "Simon Brown",
|
|
24
|
+
:cc_number => "4111111111111111",
|
|
25
|
+
:cc_expiry => "1012", # MUST be MMYY format
|
|
26
|
+
:gateway_id => "XXXXXXX", # which gateway to submit the request to
|
|
27
|
+
:password => "YYYYYY" # your password for that gateway
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
transporter = EWS::Transporter.new
|
|
31
|
+
response = transporter.submit(request) # submits using REST (XML) by default
|
|
32
|
+
|
|
33
|
+
# submit using JSON, or
|
|
34
|
+
response = transporter.submit(request, :json)
|
|
35
|
+
|
|
36
|
+
# submit using SOAP, or
|
|
37
|
+
response = transporter.submit(request, :soap)
|
|
38
|
+
|
|
39
|
+
# submit explicitly via REST
|
|
40
|
+
response = transporter.submit(request, :rest)
|
|
41
|
+
|
|
42
|
+
# The response object is independent of type of transport chosen.
|
|
43
|
+
# We decode the payload into a regular object
|
|
44
|
+
response.transaction_tag # 1234
|
|
45
|
+
response.exact_resp_code # "00"
|
|
46
|
+
response.exact_message # "Transaction Normal"
|
|
47
|
+
response.bank_resp_code # "00"
|
|
48
|
+
response.bank_message # "APPROVED"
|
|
49
|
+
|
|
50
|
+
=2. Find information on an existing transaction
|
|
51
|
+
|
|
52
|
+
require 'rubygems'
|
|
53
|
+
require 'exact4r'
|
|
54
|
+
|
|
55
|
+
# build a purchase request
|
|
56
|
+
request = EWS::Transaction::Request.new({
|
|
57
|
+
:transaction_type => :purchase,
|
|
58
|
+
:amount => 10.50,
|
|
59
|
+
:cardholder_name => "Simon Brown",
|
|
60
|
+
:cc_number => "4111111111111111",
|
|
61
|
+
:cc_expiry => "1012", # MUST be MMYY format
|
|
62
|
+
:gateway_id => "XXXXXXX", # which gateway to submit the request to
|
|
63
|
+
:password => "YYYYYY" # your password for that gateway
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
transporter = EWS::Transporter.new
|
|
67
|
+
response = transporter.submit(request) # submits using REST (XML) by default
|
|
68
|
+
|
|
69
|
+
# you need to know the transaction tag of the transaction you are looking for
|
|
70
|
+
find_request = EWS::Transaction::Request.new({
|
|
71
|
+
:transaction_type => :transaction_details,
|
|
72
|
+
:transaction_tag => response.transaction_tag,
|
|
73
|
+
:gateway_id => "XXXXXXX",
|
|
74
|
+
:password => "YYYYYY"
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
find_response = transporter.submit(find_request, :json) # again, can choose your transport type as before
|
|
78
|
+
find_response.cc_number # 4111111111111111
|
|
79
|
+
find_response.amount # 10.50
|
|
80
|
+
|
|
81
|
+
=3. Re-using a Transporter
|
|
82
|
+
|
|
83
|
+
require 'rubygems'
|
|
84
|
+
require 'exact4r'
|
|
85
|
+
|
|
86
|
+
# The transporter object can be re-used across multiple transactions, so set it up once
|
|
87
|
+
# and forget about it.
|
|
88
|
+
# In this example, we will continue to use E-xact's default web-service URL, but we
|
|
89
|
+
# will specify a default transport_type of :soap
|
|
90
|
+
transporter = EWS::Transporter.new("https://api.e-xact.com/", {:transaction_type => :soap})
|
|
91
|
+
|
|
92
|
+
# now let's submit do a recurring seed purchase...
|
|
93
|
+
rsp_req = EWS::Transaction::Request.new({
|
|
94
|
+
:transaction_type => :recurring_seed_purchase,
|
|
95
|
+
:amount => 12.00,
|
|
96
|
+
:cardholder_name => "Simon Brown",
|
|
97
|
+
:cc_number => "4111111111111111",
|
|
98
|
+
:cc_expiry => "1012",
|
|
99
|
+
:gateway_id => "XXXXXX",
|
|
100
|
+
:password => "YYYYYY"
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
rsp_resp = transporter.submit(rsp_req)
|
|
104
|
+
raise "Seed Purchase failed" unless rsp_resp.approved?
|
|
105
|
+
|
|
106
|
+
# ...then do multiple refunds against it
|
|
107
|
+
1.upto(10) do
|
|
108
|
+
rf_req = EWS::Transaction::Request.new({
|
|
109
|
+
:transaction_type => :tagged_refund,
|
|
110
|
+
:transaction_tag => rsp_resp.transaction_tag, # need to know which transaction we're refunding against...
|
|
111
|
+
:authorization_num => rsp_resp.authorization_num, # and its authorization_num
|
|
112
|
+
:amount => 1.00, # refund a dollar at a time
|
|
113
|
+
:gateway_id => "XXXXXX",
|
|
114
|
+
:password => "YYYYYY"
|
|
115
|
+
})
|
|
116
|
+
rf_resp = transporter.submit(rf_req)
|
|
117
|
+
raise "Refund failed: #{rf_resp.exact_resp_code}, #{rf_resp.exact_message}" unless rf_resp.approved?
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
=4. Using the AVS API
|
|
121
|
+
|
|
122
|
+
Allowable AVS params are:
|
|
123
|
+
|
|
124
|
+
- :avs_street_address => "7501ELMST."
|
|
125
|
+
- :avs_unit_no => "801"
|
|
126
|
+
- :avs_po_box => nil # P.O. Box or street address may be specified, but not both
|
|
127
|
+
- :avs_postal_code => "90210"
|
|
128
|
+
- :avs_test_flag => "X" # AVS test flag (optional)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
===Test Flags
|
|
132
|
+
In order to simulate an AVS response in the test environment, set the :+avs_test_flag+ to the AVS result code you would like
|
|
133
|
+
returned. The AVS result is a one-character response that indicates the degree of match for the provided address.
|
|
134
|
+
The following AVS responses are currently supported:
|
|
135
|
+
|
|
136
|
+
===North American Response Codes
|
|
137
|
+
AVS Code - ABS Definition - Explanation
|
|
138
|
+
- X - Exact match, 9 digit zip - Street Address, and 9 digit ZIP Code match
|
|
139
|
+
- Y - Exact match, 5 digit zip - Street Address, and 5 digit ZIP Code match
|
|
140
|
+
- A - Partial match - Street Address matches, ZIP Code does not
|
|
141
|
+
- W - Partial match - ZIP Code matches, Street Address does not
|
|
142
|
+
- Z - Partial match - 5 digit ZIP Code match only
|
|
143
|
+
- N - No match - No Address or ZIP Code match
|
|
144
|
+
- U - Unavailable - Address information is unavailable for that account number, or the card issuer does not support
|
|
145
|
+
- G - Service Not supported, non-US Issuer does not participate
|
|
146
|
+
- R - Retry - Issuer system unavailable, retry later
|
|
147
|
+
- E - Not a mail or phone order
|
|
148
|
+
- S - Service not supported
|
|
149
|
+
|
|
150
|
+
===International Response Codes
|
|
151
|
+
AVS Code - ABS Definition and Explanation
|
|
152
|
+
- G - Global non-AVS participant
|
|
153
|
+
- B - Address matches only
|
|
154
|
+
- C - Address and Postal Code do not match
|
|
155
|
+
- D - Address and Postal Code match
|
|
156
|
+
- F - Address and Postal Code match (UK only)
|
|
157
|
+
- I - Address information not verified for international transaction
|
|
158
|
+
- M - Address and Postal Code match
|
|
159
|
+
- P - Postal Code matches only
|
|
160
|
+
|
|
161
|
+
===Code Sample
|
|
162
|
+
avs_params = {
|
|
163
|
+
:avs_test_flag => 'N',
|
|
164
|
+
:avs_street_address => '123BROWNSTREET',
|
|
165
|
+
:avs_unit_no => '4,
|
|
166
|
+
:avs_po_box => nil,
|
|
167
|
+
:avs_postal_code => '902101234'
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
tx_params = {
|
|
171
|
+
:transaction_type => :purchase,
|
|
172
|
+
:amount => 10.50,
|
|
173
|
+
:cardholder_name => "Simon Brown",
|
|
174
|
+
:cc_number => "4111111111111111",
|
|
175
|
+
:cc_expiry => "1012",
|
|
176
|
+
:gateway_id => "XXXXXXX",
|
|
177
|
+
:password => "YYYYYY"
|
|
178
|
+
}.merge(avs_params)
|
|
179
|
+
|
|
180
|
+
request = EWS::Transaction::Request.new(tx_params)
|
|
181
|
+
|
|
182
|
+
transporter = EWS::Transporter.new("https://api.e-xact.com/")
|
|
183
|
+
response = transporter.submit(request)
|
|
184
|
+
|
|
185
|
+
response.cc_verification_str1.should == "N123BROWNSTREET4902101234"
|
|
186
|
+
response.avs.should == N
|
data/Rakefile
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'rake/rdoctask'
|
|
2
|
+
require 'rake/testtask'
|
|
3
|
+
require "rubygems"
|
|
4
|
+
require "rake/gempackagetask"
|
|
5
|
+
|
|
6
|
+
task :default => :'test:chase'
|
|
7
|
+
|
|
8
|
+
namespace :test do
|
|
9
|
+
|
|
10
|
+
desc 'Run all tests against all processors. Use LOCATION to specify web service URL.'
|
|
11
|
+
task :all do
|
|
12
|
+
%w(chase tsys emergis moneris).each do |processor|
|
|
13
|
+
3.times { puts }
|
|
14
|
+
puts "#-----------------------"
|
|
15
|
+
puts "# Testing: " + processor
|
|
16
|
+
puts "#-----------------------"
|
|
17
|
+
|
|
18
|
+
ENV['PROCESSOR'] = processor
|
|
19
|
+
begin
|
|
20
|
+
Rake::Task[:'test:processor'].execute
|
|
21
|
+
rescue
|
|
22
|
+
# don't care, just run it again. can examine output later
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
desc 'Run all tests against Chase processor and Production web service. Use LOCATION to specify web service URL.'
|
|
28
|
+
task :chase do
|
|
29
|
+
ENV['PROCESSOR'] = 'chase'
|
|
30
|
+
ENV['LOCATION'] = 'PROD' if ENV['LOCATION'].nil?
|
|
31
|
+
begin
|
|
32
|
+
Rake::Task[:'test:processor'].execute
|
|
33
|
+
rescue
|
|
34
|
+
# don't care, just run it again. can examine output later
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
desc 'Run all the tests against a specific processor. Use LOCATION to specify web service URL.'
|
|
39
|
+
Rake::TestTask.new(:processor) do |t|
|
|
40
|
+
t.libs << 'lib'
|
|
41
|
+
t.pattern = 'test/**/*_test.rb'
|
|
42
|
+
t.verbose = true
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
desc "Build the RDoc"
|
|
48
|
+
Rake::RDocTask.new { |rdoc|
|
|
49
|
+
rdoc.rdoc_dir = 'doc'
|
|
50
|
+
rdoc.title = "exact4r"
|
|
51
|
+
rdoc.options << '--main' << 'README' << "--inline-source" << "--line-numbers"
|
|
52
|
+
rdoc.rdoc_files.include('CHANGELOG', 'LICENCE', 'README', 'VERSION', 'lib/**/*.rb')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
desc "Build the exact4r gem"
|
|
56
|
+
spec = Gem::Specification.new do |s|
|
|
57
|
+
s.name="exact4r"
|
|
58
|
+
s.author = "E-xact Transactions Ltd."
|
|
59
|
+
s.homepage = "http://e-xact4r.rubyforge.org/"
|
|
60
|
+
s.rubyforge_project = "exact4r"
|
|
61
|
+
s.email = "dredmond@e-xact.com"
|
|
62
|
+
s.version=`cat VERSION`
|
|
63
|
+
s.summary = 'E-xact Web Services Client Library.'
|
|
64
|
+
s.files = FileList["./**/**"].to_a
|
|
65
|
+
s.has_rdoc = true
|
|
66
|
+
s.extra_rdoc_files = ['CHANGELOG', 'LICENCE', 'README', 'VERSION']
|
|
67
|
+
s.rdoc_options << '--main' << 'README' << '--inline-source' << '--line-numbers'
|
|
68
|
+
s.add_dependency('activesupport', '>= 2.3.2')
|
|
69
|
+
s.add_dependency('builder', '>= 2.1.2')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
|
73
|
+
pkg.need_tar = true
|
|
74
|
+
end
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.7
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIFVTCCBD2gAwIBAgIHBITApWVLMTANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
|
|
3
|
+
BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY
|
|
4
|
+
BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm
|
|
5
|
+
aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5
|
|
6
|
+
IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky
|
|
7
|
+
ODcwHhcNMTAwMjE2MjMzNTQzWhcNMTUwMjE2MjMzNTQzWjBRMRUwEwYDVQQKDAwq
|
|
8
|
+
LmUteGFjdC5jb20xITAfBgNVBAsMGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEV
|
|
9
|
+
MBMGA1UEAwwMKi5lLXhhY3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
|
10
|
+
CgKCAQEApvqzJMP4vtbvyXwepZhj8uaKXONIo4H8aN51FOL1PDdGEfWktlWw38Xj
|
|
11
|
+
dU0KJrGeTcBgsfg8NehFwasilW6IbojhMmnvWyYaTzklEjMDmgda3hGRJRqbg/dW
|
|
12
|
+
v0nZRMO7Xy0NNMGHeN9Sxs8977LRV5Y1VjK1M3WhilP3oxe49Ov1K4FEZrxT0fbn
|
|
13
|
+
sqClwAm059XM+qWkUY5tBs6KSZQf1/+Xlx5txB/IqDWLrN5oRuCa+mBi5mIFE7nA
|
|
14
|
+
suFtI/26szCYVuK6r8spbsYeo13c/qTv4yaZbLW3uXgbgTuI4FAtOR9NpUYvLQHR
|
|
15
|
+
9kYYPeusqj0DnLD6ELMXkujHW0V6MQIDAQABo4IBtjCCAbIwDwYDVR0TAQH/BAUw
|
|
16
|
+
AwEBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDgYDVR0PAQH/BAQD
|
|
17
|
+
AgWgMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Rz
|
|
18
|
+
MS0xNC5jcmwwUwYDVR0gBEwwSjBIBgtghkgBhv1tAQcXATA5MDcGCCsGAQUFBwIB
|
|
19
|
+
FitodHRwOi8vY2VydGlmaWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMIGA
|
|
20
|
+
BggrBgEFBQcBAQR0MHIwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmdvZGFkZHku
|
|
21
|
+
Y29tLzBKBggrBgEFBQcwAoY+aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv
|
|
22
|
+
bS9yZXBvc2l0b3J5L2dkX2ludGVybWVkaWF0ZS5jcnQwHwYDVR0jBBgwFoAU/axh
|
|
23
|
+
MpNsRdbi7oVfmrrndplozOcwIwYDVR0RBBwwGoIMKi5lLXhhY3QuY29tggplLXhh
|
|
24
|
+
Y3QuY29tMB0GA1UdDgQWBBRmlEOazZNz8dfnnl7UimMDqciOOzANBgkqhkiG9w0B
|
|
25
|
+
AQUFAAOCAQEArQNhlZ3ij3Yz1U2GHiNY4fpYtNCAhzlrnNZUHaDlhiWEvOcXSB4j
|
|
26
|
+
ER77sgaHmZOm8PW0mXg3eK0+Km5ANWbNbPLe0yPpKRa1GbmgxQx/P4MWMiM+872l
|
|
27
|
+
QmpZlgLw2cGvivALAt7S74QTiqjYX10nNyHlpnlvB9Am2WgzQHQDzyKuKGglFjlw
|
|
28
|
+
ItZpTFFkSGEWK99cxE69GMwtZCsr4b+RB80sDA+ckd45GISg808GkWHfqJVa64k8
|
|
29
|
+
dlXVgRNQwLfrWN+BQeUsfsKu5jiNI7H2a8zrRt4mCa9urh15O+d4pDhXhrYSkQpI
|
|
30
|
+
ezmbzKzCEd1mpiT+sjCzByN3uX6n7eF/Eg==
|
|
31
|
+
-----END CERTIFICATE-----
|
data/certs/exact.cer
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
-----BEGIN CERTIFICATE-----
|
|
2
|
-
|
|
2
|
+
MIIC7DCCAlWgAwIBAgIDCqSQMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
|
|
3
3
|
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
|
|
4
|
-
|
|
4
|
+
aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDkwMjEzMDAxMDQ2WhcNMTAwMzE1MjMxMDQ2
|
|
5
5
|
WjB3MQswCQYDVQQGEwJDQTEZMBcGA1UECBMQQnJpdGlzaCBDb2x1bWJpYTESMBAG
|
|
6
6
|
A1UEBxMJVmFuY291dmVyMSIwIAYDVQQKExlFLXhhY3QgVHJhbnNhY3Rpb25zLCBM
|
|
7
7
|
dGQuMRUwEwYDVQQDFAwqLmUteGFjdC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0A
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
gaswDgYDVR0PAQH/
|
|
12
|
-
|
|
8
|
+
MIGJAoGBAKAEtyoEOQMqbYNTo/XGXx68vElKFb3lhQ9qimRlggadSCA3F1P40dMz
|
|
9
|
+
3PlXDtKN9TcvqYalvmrntjmtY7/QgBu59AJOIoFDXe/XCtW16XAlANIrTvS9zhHd
|
|
10
|
+
nnLhCHcLAhEJIssWb3ddXiK8NDIyHtIbWYRIdzT0aPOLtoUXfcBLAgMBAAGjga4w
|
|
11
|
+
gaswDgYDVR0PAQH/BAQDAgTwMB0GA1UdDgQWBBSTkCQC1iSGLxD/+kL5elS75kLe
|
|
12
|
+
hDA6BgNVHR8EMzAxMC+gLaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxz
|
|
13
13
|
L3NlY3VyZWNhLmNybDAfBgNVHSMEGDAWgBRI5mj5K9KylddH2CMgEE8zmJCf1DAd
|
|
14
14
|
BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEA
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
iHFOvsHR2SZ93jry4TaDWXXVN3gBuK9S7j4ubcGbT4HZe/1OJXE8Hpdc6lFaBgdi
|
|
16
|
+
ZK2qHFzZ7suhcOiF6f7HCtDDXdoGAhYJVWGvhd/2CsvaRzdVWkUQzfRgDXKoYU9W
|
|
17
|
+
BEQs/Y5lG23rmq4WJe6HSVN0FMaZS3aVIr54821hKPc=
|
|
18
18
|
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
|
|
3
|
+
IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
|
|
4
|
+
BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
|
|
5
|
+
aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
|
|
6
|
+
9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
|
|
7
|
+
NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
|
|
8
|
+
azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
|
|
9
|
+
YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
|
|
10
|
+
Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
|
|
11
|
+
cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
|
|
12
|
+
dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
|
|
13
|
+
WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
|
|
14
|
+
v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
|
|
15
|
+
UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
|
|
16
|
+
IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
|
|
17
|
+
W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
|
|
18
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module EWS # :nodoc:
|
|
2
|
+
module CertificateHelper
|
|
3
|
+
|
|
4
|
+
EXACT_ISSUER_CERT_FILE = File.dirname(__FILE__)+"/../../certs/valicert_class2_root.crt" unless defined?(EXACT_ISSUER_CERT_FILE)
|
|
5
|
+
EXACT_SERVER_CERT_FILE = File.dirname(__FILE__)+"/../../certs/e-xact.com.crt" unless defined?(EXACT_SERVER_CERT_FILE)
|
|
6
|
+
|
|
7
|
+
attr_accessor :issuer_cert_file, :server_cert, :client_cert, :client_key
|
|
8
|
+
|
|
9
|
+
def configure_certificates(options)
|
|
10
|
+
self.issuer_cert_file = (options[:issuer_cert] || EXACT_ISSUER_CERT_FILE)
|
|
11
|
+
server_cert_file = (options[:server_cert] || EXACT_SERVER_CERT_FILE)
|
|
12
|
+
self.server_cert = File.new(server_cert_file).read
|
|
13
|
+
if options[:client_cert]
|
|
14
|
+
raise ArgumentError.new "Key file not supplied" if options[:client_key].blank?
|
|
15
|
+
self.client_cert = OpenSSL::X509::Certificate.new(File.new(options[:client_cert]).read)
|
|
16
|
+
self.client_key = client_cert.public_key.class.send(:new, File.new(options[:client_key]).read)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
private :configure_certificates
|
|
20
|
+
|
|
21
|
+
def validate_certificate(is_ok, ctx)
|
|
22
|
+
cert = ctx.current_cert
|
|
23
|
+
return false if cert.nil?
|
|
24
|
+
|
|
25
|
+
# preverify failed?
|
|
26
|
+
return false unless is_ok
|
|
27
|
+
|
|
28
|
+
self_signed = false
|
|
29
|
+
ca = false
|
|
30
|
+
pathlen = nil
|
|
31
|
+
server_auth = true
|
|
32
|
+
self_signed = (cert.subject.cmp(cert.issuer) == 0)
|
|
33
|
+
|
|
34
|
+
# Check extensions for the certificate purpose according to http://www.openssl.org/docs/apps/x509.html (Certificate Extensions) and
|
|
35
|
+
# http://www.ietf.org/rfc/rfc3280.txt.
|
|
36
|
+
cert.extensions.each do |ex|
|
|
37
|
+
case ex.oid
|
|
38
|
+
when 'basicConstraints'
|
|
39
|
+
/CA:(TRUE|FALSE)(?:, pathlen:)*(\d*)/ =~ ex.value
|
|
40
|
+
ca ||= ($1 == 'TRUE')
|
|
41
|
+
pathlen = $2.to_i
|
|
42
|
+
when 'keyUsage'
|
|
43
|
+
usage = ex.value.split(/\s*,\s*/)
|
|
44
|
+
# a CA must have
|
|
45
|
+
ca &&= !usage.grep(/Certificate Sign/i).empty?
|
|
46
|
+
# Server Cert Must have
|
|
47
|
+
server_auth &&= !usage.grep(/Key Encipherment/i).empty?
|
|
48
|
+
when 'extendedKeyUsage'
|
|
49
|
+
usage = ex.value.split(/\s*,\s*/)
|
|
50
|
+
# Server Cert Must have
|
|
51
|
+
server_auth &&= !usage.grep(/TLS Web Server Authentication/i).empty?
|
|
52
|
+
when 'nsCertType'
|
|
53
|
+
usage = ex.value.split(/\s*,\s*/)
|
|
54
|
+
ca ||= !usage.grep(/SSL CA/i).empty?
|
|
55
|
+
server_auth ||= !usage.grep(/SSL Server/i).empty?
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# We're looking for the server cert, so accept all CAs (which have already passed pre-verification)
|
|
60
|
+
return true if self_signed || ca
|
|
61
|
+
|
|
62
|
+
# ensure the server cert is the one we're expecting
|
|
63
|
+
return server_auth && self.server_cert == cert.to_pem
|
|
64
|
+
end
|
|
65
|
+
private :validate_certificate
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
end
|