intuit_ids_aggcat 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +202 -0
- data/README.markdown +103 -0
- data/lib/intuit_ids_aggcat/client/intuit_xml_mappings.rb +396 -0
- data/lib/intuit_ids_aggcat/client/saml.rb +126 -0
- data/lib/intuit_ids_aggcat/client/services.rb +213 -0
- data/lib/intuit_ids_aggcat/core/configuration.rb +135 -0
- data/lib/intuit_ids_aggcat/core.rb +4 -0
- data/lib/intuit_ids_aggcat/rails.rb +106 -0
- data/lib/intuit_ids_aggcat/version.rb +3 -0
- data/lib/intuit_ids_aggcat.rb +23 -0
- data/spec/config/intuit_ids_aggcat.yml +5 -0
- data/spec/config/test.crt +17 -0
- data/spec/configuration_spec.rb +23 -0
- data/spec/rails_spec.rb +15 -0
- data/spec/saml_spec.rb +25 -0
- data/spec/services_spec.rb +109 -0
- data/spec/spec_helper.rb +7 -0
- metadata +166 -0
@@ -0,0 +1,396 @@
|
|
1
|
+
# forward classdefs for mapping
|
2
|
+
class DateTimeNode < XML::Mapping::SingleAttributeNode
|
3
|
+
def initialize(*args)
|
4
|
+
path,*args = super(*args)
|
5
|
+
@path = XML::XXPath.new(path)
|
6
|
+
args
|
7
|
+
end
|
8
|
+
|
9
|
+
def extract_attr_value(xml)
|
10
|
+
# without millisecs
|
11
|
+
r1 = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}-\d{2}:\d{2}/
|
12
|
+
# with millisecs
|
13
|
+
r2 = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}-\d{2}:\d{2}/
|
14
|
+
dt_format = ""
|
15
|
+
dt_string = default_when_xpath_err{ @path.first(xml).text }
|
16
|
+
if dt_string =~ r1
|
17
|
+
dt_format = "%Y-%m-%dT%H:%M:%S%z"
|
18
|
+
elsif dt_string =~ r2
|
19
|
+
dt_format = "%Y-%m-%dT%H:%M:%S.%L%z"
|
20
|
+
end
|
21
|
+
DateTime.strptime(dt_string, dt_format)
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_attr_value(xml, value)
|
25
|
+
@path.first(xml,:ensure_created=>true).text = value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
XML::Mapping.add_node_class DateTimeNode
|
30
|
+
|
31
|
+
module IntuitIdsAggcat
|
32
|
+
class Institution; end
|
33
|
+
class Address; end
|
34
|
+
class Key; end
|
35
|
+
class Credentials; end
|
36
|
+
class Credential; end
|
37
|
+
class Challenge; end
|
38
|
+
class ChallengeResponses; end
|
39
|
+
class Account; end
|
40
|
+
class BankingAccount < Account; end
|
41
|
+
class CreditAccount < Account; end
|
42
|
+
class Choice; end
|
43
|
+
class Transaction; end
|
44
|
+
class BankingTransaction < Transaction; end
|
45
|
+
class CreditCardTransaction < Transaction; end
|
46
|
+
class InvestmentBankingTransaction < Transaction; end
|
47
|
+
class InvestmentTransaction < Transaction; end
|
48
|
+
class LoanTransaction < Transaction; end
|
49
|
+
class RewardsTransaction < Transaction; end
|
50
|
+
class TransactionList; end
|
51
|
+
#class Common; end
|
52
|
+
class Context; end
|
53
|
+
|
54
|
+
class Institutions
|
55
|
+
include XML::Mapping
|
56
|
+
array_node :institutions, "institution", :class=>Institution, :default_value => []
|
57
|
+
end
|
58
|
+
|
59
|
+
class Institution
|
60
|
+
include XML::Mapping
|
61
|
+
numeric_node :id, "institutionId", :default_value => nil
|
62
|
+
text_node :name, "institutionName", :default_value => nil
|
63
|
+
text_node :url, "homeUrl", :default_value => nil
|
64
|
+
text_node :phone, "phoneNumber", :default_value => nil
|
65
|
+
boolean_node :virtual, "virtual", "true", "false", :default_value => true
|
66
|
+
end
|
67
|
+
|
68
|
+
class InstitutionDetail
|
69
|
+
include XML::Mapping
|
70
|
+
numeric_node :id, "institutionId", :default_value => nil
|
71
|
+
text_node :name, "institutionName", :default_value => nil
|
72
|
+
text_node :url, "homeUrl", :default_value => nil
|
73
|
+
text_node :phone, "phoneNumber", :default_value => nil
|
74
|
+
boolean_node :virtual, "virtual", "true", "false", :default_value => true
|
75
|
+
text_node :currency_code, "currencyCode", :default_value => nil
|
76
|
+
text_node :email_address, "emailAddress", :default_value => nil
|
77
|
+
text_node :special_text, "specialText", :default_value => nil
|
78
|
+
object_node :address, "address", :default_value => nil
|
79
|
+
array_node :keys, "keys/key", :class=>Key, :default_value => []
|
80
|
+
end
|
81
|
+
|
82
|
+
class Address
|
83
|
+
include XML::Mapping
|
84
|
+
text_node :address1, "address1", :default_value => nil
|
85
|
+
text_node :address2, "address2", :default_value => nil
|
86
|
+
text_node :address3, "address3", :default_value => nil
|
87
|
+
text_node :city, "city", :default_value => nil
|
88
|
+
text_node :state, "state", :default_value => nil
|
89
|
+
text_node :postal_code, "postalCode", :default_value => nil
|
90
|
+
text_node :country, "country", :default_value => nil
|
91
|
+
end
|
92
|
+
|
93
|
+
class Key
|
94
|
+
include XML::Mapping
|
95
|
+
text_node :name, "name", :default_value => nil
|
96
|
+
text_node :status, "status", :default_value => nil
|
97
|
+
text_node :min_length, "valueLengthMin", :default_value => nil
|
98
|
+
text_node :max_length, "valueLengthMax", :default_value => nil
|
99
|
+
boolean_node :is_displayed, "displayFlag", "true", "false", :default_value => true
|
100
|
+
boolean_node :is_masked, "mask", "true", "false", :default_value => false
|
101
|
+
text_node :display_order, "displayOrder", :default_value => nil
|
102
|
+
text_node :instructions, "instructions", :default_value => nil
|
103
|
+
text_node :description, "description", :default_value => nil
|
104
|
+
end
|
105
|
+
|
106
|
+
class InstitutionLogin
|
107
|
+
include XML::Mapping
|
108
|
+
# added namespaces to make root element compliant with Intuit's expectation
|
109
|
+
def post_save xml, options={:mapping=>:_default}
|
110
|
+
# using REXML's element namespace method doesn't seem to set the namespace correctly...?
|
111
|
+
xml.root.add_attributes("xmlns"=>"http://schema.intuit.com/platform/fdatafeed/institutionlogin/v1")
|
112
|
+
xml.root.add_namespace "xsi", "http://www.w3.org/2001/XMLSchema-instance"
|
113
|
+
xml.root.add_namespace "xsd", "http://www.w3.org/2001/XMLSchema"
|
114
|
+
# for challengeResponses/response
|
115
|
+
xml.each_element("//response") do |x|
|
116
|
+
x.add_namespace "v11", "http://schema.intuit.com/platform/fdatafeed/challenge/v1"
|
117
|
+
x.name = "v11:response"
|
118
|
+
end
|
119
|
+
# for challengeResponses root
|
120
|
+
xml.each_element("//challengeResponses") do |x|
|
121
|
+
x.add_namespace "v1", "http://schema.intuit.com/platform/fdatafeed/institutionlogin/v1"
|
122
|
+
x.name = "challengeResponses"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
self.root_element_name "InstitutionLogin"
|
127
|
+
object_node :credentials, "credentials", :default_value => nil
|
128
|
+
object_node :challenge_responses, "challengeResponses", :default_value => nil
|
129
|
+
end
|
130
|
+
|
131
|
+
class Credentials
|
132
|
+
include XML::Mapping
|
133
|
+
array_node :credential, "credential", :default_value => nil
|
134
|
+
end
|
135
|
+
|
136
|
+
class Credential
|
137
|
+
include XML::Mapping
|
138
|
+
text_node :name, "name", :default_value => nil
|
139
|
+
text_node :value, "value", :default_value => nil
|
140
|
+
end
|
141
|
+
|
142
|
+
class Challenges
|
143
|
+
include XML::Mapping
|
144
|
+
array_node :challenge, "challenge", :class => Challenge, :default_value => nil
|
145
|
+
end
|
146
|
+
|
147
|
+
class Choice
|
148
|
+
include XML::Mapping
|
149
|
+
text_node :text, "text", :default_value => nil
|
150
|
+
text_node :val, "val", :default_value => nil
|
151
|
+
end
|
152
|
+
|
153
|
+
class Challenge
|
154
|
+
include XML::Mapping
|
155
|
+
text_node :text, "text", :default_value => nil
|
156
|
+
text_node :image, "image", :default_value => nil
|
157
|
+
array_node :choice, "choice", :class => Choice, :default_value => nil
|
158
|
+
end
|
159
|
+
|
160
|
+
class ChallengeResponses
|
161
|
+
include XML::Mapping
|
162
|
+
def post_save xml, options={:mapping=>:_default}
|
163
|
+
# using REXML's element na1espace method doesn't seem to set the namespace correctly...?
|
164
|
+
xml.root.add_namespace "v1", "http://schema.intuit.com/platform/fdatafeed/institutionlogin/v1"
|
165
|
+
xml.each_element("//response"){|x| x.add_namespace "v11", "http://schema.intuit.com/platform/fdatafeed/challenge/v1"}
|
166
|
+
xml
|
167
|
+
end
|
168
|
+
self.root_element_name "ChallengeResponses"
|
169
|
+
array_node :response, "response", :class => String
|
170
|
+
end
|
171
|
+
|
172
|
+
class AccountList
|
173
|
+
include XML::Mapping
|
174
|
+
array_node :banking_accounts, "BankingAccount", :class => BankingAccount, :default_value => nil
|
175
|
+
array_node :credit_accounts, "CreditAccount", :class => CreditAccount, :default_value => nil
|
176
|
+
#array_node :loan_accounts, "LoanAccount", :default_value => nil
|
177
|
+
#array_node :investment_accounts, "InvestmentAccount", :default_value => nil
|
178
|
+
#array_node :rewards_accounts, "RewardsAccount", :default_value => nil
|
179
|
+
#array_node :other_accounts, "OtherAccount", :default_value => nil
|
180
|
+
end
|
181
|
+
|
182
|
+
class Account
|
183
|
+
include XML::Mapping
|
184
|
+
numeric_node :account_id, "accountId", :default_value => nil
|
185
|
+
text_node :status, "status", :default_value => nil
|
186
|
+
text_node :account_number, "accountNumber", :default_value => nil
|
187
|
+
text_node :account_number_real, "accountNumberReal", :default_value => nil
|
188
|
+
text_node :account_nickname, "accountNickname", :default_value => nil
|
189
|
+
numeric_node :display_position, "displayPosition", :default_value => nil
|
190
|
+
numeric_node :institution_id, "institutionId", :default_value => nil
|
191
|
+
text_node :description, "description", :default_value => nil
|
192
|
+
text_node :registered_user_name, "registeredUserName", :default_value => nil
|
193
|
+
numeric_node :balance_amount, "balanceAmount", :default_value => nil
|
194
|
+
date_time_node :balance_date, "balanceDate", :default_value => nil
|
195
|
+
numeric_node :balance_previous_amount, "balancePreviousAmount", :default_value => nil
|
196
|
+
date_time_node :last_transaction_date, "lastTxnDate", :default_value => nil
|
197
|
+
date_time_node :aggregation_success_date, "aggrSuccessDate", :default_value => nil
|
198
|
+
date_time_node :aggregation_attempt_date, "aggrAttemptDate", :default_value => nil
|
199
|
+
text_node :currency_code, "currencyCode", :default_value => nil
|
200
|
+
text_node :bank_id, "bankId", :default_value => nil
|
201
|
+
numeric_node :institution_login_id, "institutionLongId", :default_value => nil
|
202
|
+
end
|
203
|
+
|
204
|
+
class BankingAccount < Account
|
205
|
+
include XML::Mapping
|
206
|
+
text_node :banking_account_type, "bankingAccountType", :default_value => nil
|
207
|
+
date_time_node :posted_date, "postedDate", :default_value => nil
|
208
|
+
numeric_node :available_balance_amount, "availableBalanceAmount", :default_value => nil
|
209
|
+
date_time_node :origination_date, "originationDate", :default_value => nil
|
210
|
+
date_time_node :open_date, "openDate", :default_value => nil
|
211
|
+
numeric_node :period_interest_rate, "periodInterestRate", :default_value => nil
|
212
|
+
numeric_node :period_deposit_amount, "periodDepositAmount", :default_value => nil
|
213
|
+
numeric_node :period_interest_amount, "periodInterestAmount", :default_value => nil
|
214
|
+
numeric_node :interest_amount_ytd, "interestAmountYtd", :default_value => nil
|
215
|
+
numeric_node :interest_prior_amount_ytd, "interestPriorAmountYtd", :default_value => nil
|
216
|
+
date_time_node :maturity_date, "maturityDate", :default_value => nil
|
217
|
+
numeric_node :maturity_amount, "maturityAmount", :default_value => nil
|
218
|
+
end
|
219
|
+
|
220
|
+
class CreditAccount < Account
|
221
|
+
include XML::Mapping
|
222
|
+
text_node :credit_account_type, "creditAccountType", :default_value => nil
|
223
|
+
text_node :detailed_description, "detailedDescription", :default_value => nil
|
224
|
+
numeric_node :interest_rate, "interestRate", :default_value => nil
|
225
|
+
numeric_node :credit_available_amount, "creditAvailableAmount", :default_value => nil
|
226
|
+
numeric_node :credit_max_amount, "creditMaxAmount", :default_value => nil
|
227
|
+
numeric_node :cash_advance_max_amount, "cashAdvanceMaxAmount", :default_value => nil
|
228
|
+
numeric_node :cash_advance_balance, "cashAdvanceBalance", :default_value => nil
|
229
|
+
numeric_node :cash_advance_interest_rate, "cashAdvanceInterestRate", :default_value => nil
|
230
|
+
numeric_node :current_balance, "currentBalance", :default_value => nil
|
231
|
+
numeric_node :payment_min_amount, "paymentMinAmount", :default_value => nil
|
232
|
+
date_time_node :payment_due_date, "paymentDueDate", :default_value => nil
|
233
|
+
numeric_node :previous_balance, "previousBalance", :default_value => nil
|
234
|
+
date_time_node :statement_end_date, "statementEndDate", :default_value => nil
|
235
|
+
numeric_node :statement_purchase_amount, "statementPurchaseAmount", :default_value => nil
|
236
|
+
numeric_node :statement_finance_amount, "statementFinanceAmount", :default_value => nil
|
237
|
+
numeric_node :past_due_amount, "pastDueAmount", :default_value => nil
|
238
|
+
numeric_node :last_payment_amount, "lastPaymentAmount", :default_value => nil
|
239
|
+
date_time_node :last_payment_date, "lastPaymentDate", :default_value => nil
|
240
|
+
numeric_node :statement_close_balance, "statementCloseBalance", :default_value => nil
|
241
|
+
numeric_node :statement_last_fee_amount, "statementLastFeeAmount", :default_value => nil
|
242
|
+
end
|
243
|
+
|
244
|
+
class Common
|
245
|
+
include XML::Mapping
|
246
|
+
text_node :normalized_payee_name, "normalizedPayeeName", :default_value => nil
|
247
|
+
end
|
248
|
+
|
249
|
+
class Context
|
250
|
+
include XML::Mapping
|
251
|
+
text_node :source, "source", :default_value => nil
|
252
|
+
text_node :category_name, "categoryName", :default_value => nil
|
253
|
+
end
|
254
|
+
|
255
|
+
class Categorization
|
256
|
+
include XML::Mapping
|
257
|
+
object_node :common, "common", :class => Common, :default_value => nil
|
258
|
+
object_node :context, "context", :class => Context, :default_value => nil
|
259
|
+
end
|
260
|
+
|
261
|
+
class Transaction
|
262
|
+
include XML::Mapping
|
263
|
+
numeric_node :id, "id", :default_value => nil
|
264
|
+
text_node :currency_type, "currencyType", :default_value => nil
|
265
|
+
text_node :institution_transaction_id, "institutionTransactionId", :default_value => nil
|
266
|
+
text_node :correct_institution_transaction_id, "correctInstitutionTransactionId", :default_value => nil
|
267
|
+
text_node :correct_action, "correctAction", :default_value => nil
|
268
|
+
text_node :server_transaction_id, "serverTransactionId", :default_value => nil
|
269
|
+
text_node :check_number, "checkNumber", :default_value => nil
|
270
|
+
text_node :ref_number, "refNumber", :default_value => nil
|
271
|
+
text_node :confirmation_number, "confirmationNumber", :default_value => nil
|
272
|
+
text_node :payee_id, "payeeId", :default_value => nil
|
273
|
+
text_node :payee_name, "payeeName", :default_value => nil
|
274
|
+
text_node :normalized_payee_name, "normalizedPayeeName", :default_value => nil
|
275
|
+
text_node :memo, "memo", :default_value => nil
|
276
|
+
text_node :category, "category", :default_value => nil
|
277
|
+
text_node :type, "type", :default_value => nil
|
278
|
+
text_node :value_type, "valueType", :default_value => nil
|
279
|
+
text_node :category_name, "categoryName", :default_value => nil
|
280
|
+
text_node :ofx_category_name, "ofxCategoryName", :default_value => nil
|
281
|
+
numeric_node :currency_rate, "currencyRate", :default_value => nil
|
282
|
+
boolean_node :original_currency, "originalCurrency", "true", "false", :default_value => nil
|
283
|
+
date_time_node :posted_date, "postedDate", :default_value => nil
|
284
|
+
date_time_node :user_date, "userDate", :default_value => nil
|
285
|
+
date_time_node :available_date, "availableDate", :default_value => nil
|
286
|
+
numeric_node :amount, "amount", :default_value => nil
|
287
|
+
numeric_node :running_balance_amount, "runningBalanceAmount", :default_value => nil
|
288
|
+
numeric_node :sic, "sic", :default_value => nil
|
289
|
+
boolean_node :pending, "pending", "true", "false", :default_value => nil
|
290
|
+
object_node :categorization, "categorization", :class => Categorization, :default_value => nil
|
291
|
+
end
|
292
|
+
|
293
|
+
class BankingTransaction < Transaction
|
294
|
+
include XML::Mapping
|
295
|
+
use_mapping :_default
|
296
|
+
end
|
297
|
+
|
298
|
+
class CreditCardTransaction < Transaction
|
299
|
+
include XML::Mapping
|
300
|
+
use_mapping :_default
|
301
|
+
end
|
302
|
+
|
303
|
+
class InvestmentBankingTransaction < Transaction
|
304
|
+
include XML::Mapping
|
305
|
+
text_node :banking_transaction_type, "bankingTransactionType", :default_value => nil
|
306
|
+
text_node :subaccount_fund_type, "subaccountFundType", :default_value => nil
|
307
|
+
text_node :banking_401k_source_type, "banking401KSourceType", :default_value => nil
|
308
|
+
end
|
309
|
+
|
310
|
+
class LoanTransaction < Transaction
|
311
|
+
include XML::Mapping
|
312
|
+
numeric_node :principal_amount, "principalAmount", :default_value => nil
|
313
|
+
numeric_node :interest_amount, "interestAmount", :default_value => nil
|
314
|
+
numeric_node :escrow_total_amount, "escrowTotalAmount", :default_value => nil
|
315
|
+
numeric_node :escrow_tax_amount, "escrowTaxAmount", :default_value => nil
|
316
|
+
numeric_node :escrow_insurance_amount, "escrowInsuranceAmount", :default_value => nil
|
317
|
+
numeric_node :escrow_pmi_amount, "escrowPmiAmount", :default_value => nil
|
318
|
+
numeric_node :escrow_fees_amount, "escrowFeesAmount", :default_value => nil
|
319
|
+
numeric_node :escrow_other_amount, "escrowOtherAmount", :default_value => nil
|
320
|
+
end
|
321
|
+
|
322
|
+
# TODO - map InvestmentTransaction
|
323
|
+
class InvestmentTransaction < Transaction
|
324
|
+
include XML::Mapping
|
325
|
+
text_node :reversal_institution_transaction_id, "reversalInstitutionTransactionId", :default_value => nil
|
326
|
+
text_node :description, "description", :default_value => nil
|
327
|
+
text_node :buy_type, "buyType", :default_value => nil
|
328
|
+
text_node :income_type, "incomeType", :default_value => nil
|
329
|
+
text_node :inv_401k_source, "inv401ksource", :default_value => nil
|
330
|
+
text_node :loan_id, "loadId", :default_value => nil
|
331
|
+
text_node :options_action_type, "optionsActionType", :default_value => nil
|
332
|
+
text_node :options_buy_type, "optionsBuyType", :default_value => nil
|
333
|
+
text_node :options_sell_type, "optionsSellType", :default_value => nil
|
334
|
+
text_node :position_type, "positionType", :default_value => nil
|
335
|
+
text_node :related_institution_trade_id, "relatedInstitutionTradeId", :default_value => nil
|
336
|
+
text_node :related_options_trans_type, "relatedOptionsTransType", :default_value => nil
|
337
|
+
text_node :secured_type, "securedType", :default_value => nil
|
338
|
+
text_node :sell_reason, "sellReason", :default_value => nil
|
339
|
+
text_node :sell_type, "sellType", :default_value => nil
|
340
|
+
text_node :subaccount_from_type, "subaccountFromType", :default_value => nil
|
341
|
+
text_node :subaccount_fund_type, "subaccountFundType", :default_value => nil
|
342
|
+
text_node :subaccount_security_type, "subaccountSecurityType", :default_value => nil
|
343
|
+
text_node :subaccount_to_type, "subaccountToType", :default_value => nil
|
344
|
+
text_node :transfer_action, "transferAction", :default_value => nil
|
345
|
+
text_node :unit_type, "unitType", :default_value => nil
|
346
|
+
text_node :cusip, "cusip", :default_value => nil
|
347
|
+
text_node :symbol, "symbol", :default_value => nil
|
348
|
+
text_node :unit_action, "unitAction", :default_value => nil
|
349
|
+
text_node :options_security, "optionsSecurity", :default_value => nil
|
350
|
+
date_time_node :trade_date, "tradeDate", :default_value => nil
|
351
|
+
date_time_node :settle_date, "settleDate", :default_value => nil
|
352
|
+
numeric_node :accrued_interest_amount, "accruedInterestAmount", :default_value => nil
|
353
|
+
numeric_node :average_cost_basis_amount, "averageCostBasisAmount", :default_value => nil
|
354
|
+
numeric_node :commission_amount, "commissionAmount", :default_value => nil
|
355
|
+
numeric_node :denominator, "denominator", :default_value => nil
|
356
|
+
date_time_node :payroll_date, "payrollDate", :default_value => nil
|
357
|
+
date_time_node :purchase_date, "purchaseDate", :default_value => nil
|
358
|
+
numeric_node :gain_amount, "gainAmount", :default_value => nil
|
359
|
+
numeric_node :fees_amount, "feesAmount", :default_value => nil
|
360
|
+
numeric_node :fractional_units_cash_amount, "fractionalUnitsCashAmount", :default_value => nil
|
361
|
+
numeric_node :load_amount, "loadAmount", :default_value => nil
|
362
|
+
numeric_node :loan_interest_amount, "loadInterestAmount", :default_value => nil
|
363
|
+
numeric_node :loan_principal_amount, "loanPrincipalAmount", :default_value => nil
|
364
|
+
numeric_node :markdown_amount, "markdownAmount", :default_value => nil
|
365
|
+
numeric_node :markup_amount, "markupAmount", :default_value => nil
|
366
|
+
numeric_node :new_units, "newUnits", :default_value => nil
|
367
|
+
numeric_node :numerator, "numerator", :default_value => nil
|
368
|
+
numeric_node :old_units, "oldUnits", :default_value => nil
|
369
|
+
numeric_node :penatly_amount, "penaltyAmount", :default_value => nil
|
370
|
+
boolean_node :prior_year_contribution, "priorYearContribution", :default_value => nil
|
371
|
+
numeric_node :shares_per_contract, "sharesPerContract", :default_value => nil
|
372
|
+
numeric_node :state_withholding, "stateWithholding", :default_value => nil
|
373
|
+
numeric_node :total_amount, "totalAmount", :default_value => nil
|
374
|
+
numeric_node :taxes_amount, "taxesAmount", :default_value => nil
|
375
|
+
boolean_node :tax_exmpty, "taxExmpty", :default_value => nil
|
376
|
+
numeric_node :unit_price, "unitPrice", :default_value => nil
|
377
|
+
numeric_node :units, "units", :default_value => nil
|
378
|
+
numeric_node :withholding_amount, "withholdingAmount", :default_value => nil
|
379
|
+
numeric_node :options_shares_per_contract, "optionsSharesPerContract", :default_value => nil
|
380
|
+
end
|
381
|
+
|
382
|
+
class RewardsTransaction < Transaction
|
383
|
+
include XML::Mapping
|
384
|
+
use_mapping :_default
|
385
|
+
end
|
386
|
+
|
387
|
+
class TransactionList
|
388
|
+
include XML::Mapping
|
389
|
+
array_node :banking_transactions, "BankingTransaction", :class => BankingTransaction, :default_value => nil
|
390
|
+
array_node :credit_card_transactions, "CreditCardTransaction", :class => CreditCardTransaction, :default_value => nil
|
391
|
+
array_node :investment_banking_transactions, "InvestmentBankingTransaction", :class => InvestmentBankingTransaction, :default_value => nil
|
392
|
+
array_node :loan_transactions, "LoanTransaction", :class => LoanTransaction, :default_value => nil
|
393
|
+
array_node :investment_transactions, "InvestmentTransaction", :class => InvestmentTransaction, :default_value => nil
|
394
|
+
array_node :rewards_transactions, "RewardsTransaction", :class => RewardsTransaction, :default_value => nil
|
395
|
+
end
|
396
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'base64'
|
4
|
+
require 'securerandom'
|
5
|
+
require 'active_support'
|
6
|
+
require 'net/https'
|
7
|
+
require 'cgi'
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
module IntuitIdsAggcat
|
11
|
+
|
12
|
+
module Client
|
13
|
+
|
14
|
+
class Saml
|
15
|
+
@token_timeout = 600
|
16
|
+
class << self
|
17
|
+
|
18
|
+
def get_saml_assertion_xml issuer_id, username = "default", private_key_path, private_key_string, private_key_password, instant
|
19
|
+
id = "_#{SecureRandom.uuid.gsub!(/-/, '')}"
|
20
|
+
time_format = "%Y-%m-%dT%T.%LZ"
|
21
|
+
before = instant - 5*60
|
22
|
+
after = instant + @token_timeout
|
23
|
+
saml_assertion_xml = <<-EOF_XML
|
24
|
+
<?xml version="1.0" encoding="UTF-8"?><saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="#{id}" IssueInstant="#{instant.utc.strftime(time_format)}" Version="2.0"><saml2:Issuer>#{issuer_id}</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="##{id}"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>%%DIGEST%%</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>%%SIGNATURE%%</ds:SignatureValue></ds:Signature><saml2:Subject><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">#{username}</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"/></saml2:Subject><saml2:Conditions NotBefore="#{before.utc.strftime(time_format)}" NotOnOrAfter="#{after.utc.strftime(time_format)}"><saml2:AudienceRestriction><saml2:Audience>#{issuer_id}</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant="#{instant.utc.strftime(time_format)}" SessionIndex="#{id}"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement></saml2:Assertion>
|
25
|
+
EOF_XML
|
26
|
+
digestible_xml = get_digestible_xml(saml_assertion_xml)
|
27
|
+
digest = calc_digest(digestible_xml).strip
|
28
|
+
signed_info_xml = get_signed_info_xml(id, digest)
|
29
|
+
signature_value = get_signature_value(signed_info_xml, private_key_path, private_key_string, private_key_password)
|
30
|
+
saml_assertion_xml.gsub!(/%%DIGEST%%/, digest)
|
31
|
+
saml_assertion_xml.gsub!(/%%SIGNATURE%%/, signature_value)
|
32
|
+
return saml_assertion_xml
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_signature_value(signed_info_xml, private_key_path, private_key_string, private_key_password)
|
37
|
+
if !private_key_path.nil?
|
38
|
+
pkey = OpenSSL::PKey::RSA.new(File.read(private_key_path), private_key_password)
|
39
|
+
else
|
40
|
+
pkey = OpenSSL::PKey::RSA.new(private_key_string, private_key_password)
|
41
|
+
end
|
42
|
+
signed_info_xml_canon = Nokogiri::XML(signed_info_xml).canonicalize
|
43
|
+
digest = OpenSSL::Digest::SHA1.new
|
44
|
+
signature = Base64.encode64 pkey.sign(digest, signed_info_xml_canon)
|
45
|
+
signature.gsub!(/\n/,'') #remove newline
|
46
|
+
return signature
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_signed_info_xml(id, digest)
|
50
|
+
signed_info_xml = <<-EOF_XML
|
51
|
+
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="##{id}"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>#{digest.strip}</ds:DigestValue></ds:Reference></ds:SignedInfo>
|
52
|
+
EOF_XML
|
53
|
+
signed_info_xml = signed_info_xml.strip
|
54
|
+
return signed_info_xml
|
55
|
+
end
|
56
|
+
|
57
|
+
def calc_digest(digestible_xml)
|
58
|
+
doc = Nokogiri::XML(digestible_xml)
|
59
|
+
doc_canonicalized = doc.canonicalize(mode=Nokogiri::XML::XML_C14N_1_1)
|
60
|
+
digest = OpenSSL::Digest::SHA1.new.digest(doc_canonicalized)
|
61
|
+
digest_b64 = Base64.encode64(digest)
|
62
|
+
return digest_b64
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_digestible_xml(saml_assertion_xml)
|
66
|
+
doc = Nokogiri::XML(saml_assertion_xml)
|
67
|
+
doc.xpath('//ds:Signature', 'ds' => "http://www.w3.org/2000/09/xmldsig#" ).each do |node|
|
68
|
+
node.remove
|
69
|
+
end
|
70
|
+
new_xml = doc.root.to_s
|
71
|
+
doc = Nokogiri::XML(new_xml)
|
72
|
+
doc.xpath('//text()[not(normalize-space())]').remove
|
73
|
+
doc_canonical = doc.canonicalize(mode=Nokogiri::XML::XML_C14N_1_1)
|
74
|
+
return doc_canonical.to_s.strip
|
75
|
+
end
|
76
|
+
|
77
|
+
def send_saml_assertion(saml_assertion_b64, oauth_consumer_key, oauth_consumer_secret)
|
78
|
+
|
79
|
+
oauth_url="https://oauth.intuit.com/oauth/v1/get_access_token_by_saml"
|
80
|
+
|
81
|
+
uri = URI.parse(oauth_url)
|
82
|
+
if IntuitIdsAggcat.config.proxy.nil?
|
83
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
84
|
+
else
|
85
|
+
proxy_uri = URI.parse(IntuitIdsAggcat.config.proxy)
|
86
|
+
http = Net::HTTP::Proxy(proxy_uri.host,proxy_uri.port).new(uri.host, uri.port)
|
87
|
+
end
|
88
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
89
|
+
request["Content-Type"] = "application/x-www-form-urlencoded"
|
90
|
+
request["Content-Language"] = "en-US"
|
91
|
+
request["Content-Length"] = saml_assertion_b64.length
|
92
|
+
request["Authorization"] = "OAuth oauth_consumer_key=\"#{oauth_consumer_key}\""
|
93
|
+
request["Host"] = "financialdatafeed.platform.intuit.com"
|
94
|
+
request.set_form_data({"saml_assertion"=>saml_assertion_b64})
|
95
|
+
http.use_ssl = true
|
96
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
97
|
+
#http.set_debug_output($stdout)
|
98
|
+
response = http.request(request)
|
99
|
+
params = CGI::parse(response.body)
|
100
|
+
return {oauth_token_secret: params["oauth_token_secret"][0],
|
101
|
+
oauth_token: params["oauth_token"][0] }
|
102
|
+
|
103
|
+
end
|
104
|
+
def get_oauth_info issuer_id, username, oauth_consumer_key, oauth_consumer_secret, private_key_path, private_key_string, private_key_password
|
105
|
+
instant = Time.now
|
106
|
+
saml_assertion_xml = get_saml_assertion_xml issuer_id, username, private_key_path, private_key_string, private_key_password, instant
|
107
|
+
saml_assertion_b64 = Base64.strict_encode64(saml_assertion_xml)
|
108
|
+
oauth_token_info = send_saml_assertion saml_assertion_b64, oauth_consumer_key, oauth_consumer_secret
|
109
|
+
oauth_token_info[:token_expiry] = instant + @token_timeout
|
110
|
+
oauth_token_info
|
111
|
+
end
|
112
|
+
|
113
|
+
def get_tokens username, issuer_id = IntuitIdsAggcat.config.issuer_id, oauth_consumer_key = IntuitIdsAggcat.config.oauth_consumer_key, oauth_consumer_secret = IntuitIdsAggcat.config.oauth_consumer_secret, certificate_path = IntuitIdsAggcat.config.certificate_path, certificate_string = IntuitIdsAggcat.config.certificate_string, certificate_password = IntuitIdsAggcat.config.certificate_password
|
114
|
+
#if !IntuitIdsAggcat.config.oauth_token_info.nil? && !IntuitIdsAggcat.config.oauth_token_info[:oauth_token].nil? && IntuitIdsAggcat.config.oauth_token_info[:token_expiry] > (Time.now + 2)
|
115
|
+
# IntuitIdsAggcat.config.oauth_token_info
|
116
|
+
#else
|
117
|
+
oauth_token_info = get_oauth_info issuer_id, username, oauth_consumer_key, oauth_consumer_secret, certificate_path, certificate_string, certificate_password
|
118
|
+
# IntuitIdsAggcat.config(:oauth_token_info => oauth_token_info)
|
119
|
+
# oauth_token_info
|
120
|
+
#end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|