Odyssey
SavvyMoney.i
1 <?php
2 
3 /*
4  * SSO flow
5  * smo_config to set parameters
6  * smo_getToken to get access token
7  * smo_embcurl to make curl calls to SavvyMoney
8  * redirect to URI - iframe or form post? Still deciding
9  */
10 
11 /**
12  * Configure details for connection to SavvyMoney and logging, etc
13  * at HomeCU
14  *
15  * @param resource $dbh database handle
16  * @param string $accountToUse member account number
17  * @param string $email member email saved at HomeCU
18  * @param array $parms to hold config settings based on trusted detail
19  * @throws Exception
20  */
21 function smo_config($dbh, $accountToUse, $email='', &$parms) {
22  $authparms = array();
23  $platform = HCU_array_key_value('platform', $parms);
24  if (HCU_array_key_value('beta', $parms)) {
25  $authparms['authId'] = HCU_array_key_value('betaAuthId', $parms);
26  $authparms['Key'] = HCU_array_key_value('betaAuthKey', $parms);
27  $authparms['Domain'] = HCU_array_key_value('betaAuthDomain', $parms);
28  $authparms['partnerId'] = HCU_array_key_value('betaPartnerId', $parms);
29  $authparms['encKey'] = HCU_array_key_value('betaEncKey', $parms);
30  $authparms['apiURL'] = HCU_array_key_value('betaAPIurl', $parms);
31  $authparms['redirURL'] = (in_array ($platform, ['APP','ADA'] ) ? HCU_array_key_value('betaMBLurl', $parms) : HCU_array_key_value('betaSSOurl', $parms));
32 // $authparms['redirURL'] = HCU_array_key_value('betaSSOurl', $parms);
33 // $authparms['mblreURL'] = HCU_array_key_value('betaMBLurl', $parms);
34  } else {
35  $authparms['authId'] = HCU_array_key_value('prodAuthId', $parms);
36  $authparms['Key'] = HCU_array_key_value('prodAuthKey', $parms);
37  $authparms['Domain'] = HCU_array_key_value('prodAuthDomain', $parms);
38  $authparms['partnerId'] = HCU_array_key_value('prodPartnerId', $parms);
39  $authparms['encKey'] = HCU_array_key_value('prodEncKey', $parms);
40  $authparms['apiURL'] = HCU_array_key_value('prodAPIurl', $parms);
41  $authparms['redirURL'] = (in_array ($platform, ['APP','ADA'] ) ? HCU_array_key_value('prodMBLurl', $parms) : HCU_array_key_value('prodSSOurl', $parms));
42 // $authparms['redirURL'] = HCU_array_key_value('prodSSOurl', $parms);
43 // $authparms['mblreURL'] = HCU_array_key_value('prodMBLurl', $parms);
44  }
45 
46  if (HCU_array_key_value('PadMbrSize', $parms) > 0) {
47  $authparms['memberId'] = substr(str_repeat('0', $parms['PadMbrSize']) . $accountToUse, (-1 * $parms['PadMbrSize']), $parms['PadMbrSize']);
48  } else {
49  # default no padding
50  $authparms['memberId'] = $accountToUse;
51  }
52  if (!empty($email)) {
53  $authparms['email'] = $email;
54  }
55 
56  $reqparms = array('authId'=>1,
57  'Key'=>1,
58  'Domain'=>1,
59  'partnerId'=>1,
60  'encKey'=>1,
61  'memberId' => 1,
62  'apiURL' => 1,
63  'redirURL' => 1
64  );
65  $missing = array_diff_key($reqparms,$authparms);
66  if (sizeof($missing)) {
67  throw new Exception("Missing Parameters (" . join(", ",array_keys($missing)) . " )", 100);
68  }
69  $parms['authparms'] = $authparms;
70 }
71 
72 /**
73  * Get access token from SavvyMoney
74  *
75  * @param array $parms trusted detail and hcu config settings
76  * @return array results of curl call to SavvyMoney
77  */
78 function smo_getAuthorization( $parms ) {
79  $reqparms = array('apiURL' => 1);
80  $missing = array_diff_key($reqparms,$parms['authparms']);
81  if (sizeof($missing)) {
82  throw new Exception("Missing Parameters (" . join(", ",array_keys($missing)) . " )", 100);
83  }
84  $request = smo_request($parms);
85  $reqURL = "{$parms['authparms']['apiURL']}/auth";
86  $parms["environment"]["logPoint"] = "smo_getAuthToken";
87  $token = smo_embcurl($parms, $reqURL, 'POST', ["Content-Type:application/json"], $request) ;
88  return array('request' => $request, 'token' => $token);
89 }
90 /**
91  * Get access token from SavvyMoney
92  *
93  * @param array $parms trusted detail and hcu config settings
94  * @return array results of curl call to SavvyMoney
95  */
96 function smo_getRedirect( $parms ) {
97  $reqparms = array('apiURL' => 1, 'redirURL' => 1, 'smoToken' => 1);
98  $missing = array_diff_key($reqparms,$parms['authparms']);
99  if (sizeof($missing)) {
100  throw new Exception("Missing Parameters (" . join(", ",array_keys($missing)) . " )", 100);
101  }
102  # if desktop / mobile responsive use redirURL; if app use mblreURL
103  $request = json_encode(array('authCode' => $parms['authparms']['smoToken'], 'appUrl' => "{$parms['authparms']['redirURL']}"));
104  $reqURL = "{$parms['authparms']['apiURL']}/redirect";
105  $parms["environment"]["logPoint"] = "smo_getRedirect";
106  $redirection = smo_embcurl($parms, $reqURL, 'POST', ["Content-Type:application/json"], $request) ;
107  return array('request' => $request, 'redirect' => $redirection);
108 }
109 /**
110  * Build json request to get access token from SavvyMoney
111  *
112  * @param array $parms trusted detail settings in $parms['authparms']
113  * @return json
114  */
115 function smo_request( $parms ) {
116  $reqparms = array('partnerId' => 1,
117  'encKey' => 1, 'memberId' => 1,
118  'authId' => 1,
119  'Key' => 1,
120  'Domain' => 1);
121  $missing = array_diff_key($reqparms,$parms['authparms']);
122  if (sizeof($missing)) {
123  throw new Exception("Missing Parameters (" . join(", ",array_keys($missing)) . " )", 100);
124  }
125 
126  $enc_partnerId = encrypt_smo_openssl($parms['authparms']['partnerId'], $parms['authparms']['encKey']);
127  $enc_partnerMemberId = encrypt_smo_openssl($parms['authparms']['memberId'], $parms['authparms']['encKey']); # uses 'accountToUse'
128  # testing remove for prod
129  $enc_partnerMemberId = encrypt_smo_openssl($parms['MIR']['data']['accountnumber'], $parms['authparms']['encKey']); # uses 'accountToUse'
130 
131  $attributes = array(
132  ['key' => 'partnerId',
133  'value' => $enc_partnerId,
134  'encrypted' => true],
135  ['key' => 'partnerMemberId',
136  'value' => $enc_partnerMemberId,
137  'encrypted' => true]);
138 
139  if (HCU_array_key_value('email', $parms['authparms']) ) {
140  $enc_email = encrypt_smo_openssl($parms['authparms']['email'], $parms['authparms']['encKey']);
141  $attributes[] =
142  ['key' => 'email',
143  'value' => $enc_email,
144  'encrypted' => true];
145  }
146 
147  if (HCU_array_key_value('firstname', $parms['MIR']['data']) ) {
148  $enc_attrib = encrypt_smo_openssl($parms['MIR']['data']['firstname'], $parms['authparms']['encKey']);
149  $attributes[] =
150  ['key' => 'firstName',
151  'value' => $enc_attrib,
152  'encrypted' => true];
153  }
154 
155  if (HCU_array_key_value('lastname', $parms['MIR']['data']) ) {
156  $enc_attrib = encrypt_smo_openssl($parms['MIR']['data']['lastname'], $parms['authparms']['encKey']);
157  $attributes[] =
158  ['key' => 'lastName',
159  'value' => $enc_attrib,
160  'encrypted' => true];
161  }
162 
163  if (HCU_array_key_value('address1', $parms['MIR']['data']) ) {
164  $enc_attrib = encrypt_smo_openssl($parms['MIR']['data']['address1'], $parms['authparms']['encKey']);
165  $attributes[] =
166  ['key' => 'address1',
167  'value' => $enc_attrib,
168  'encrypted' => true];
169  }
170 
171  if (HCU_array_key_value('city', $parms['MIR']['data']) ) {
172  $enc_attrib = encrypt_smo_openssl($parms['MIR']['data']['city'], $parms['authparms']['encKey']);
173  $attributes[] =
174  ['key' => 'city',
175  'value' => $enc_attrib,
176  'encrypted' => true];
177  }
178 
179  if (HCU_array_key_value('state', $parms['MIR']['data']) ) {
180  $enc_attrib = encrypt_smo_openssl($parms['MIR']['data']['state'], $parms['authparms']['encKey']);
181  $attributes[] =
182  ['key' => 'state',
183  'value' => $enc_attrib,
184  'encrypted' => true];
185  }
186 
187  if (HCU_array_key_value('zip', $parms['MIR']['data']) ) {
188  $enc_attrib = encrypt_smo_openssl($parms['MIR']['data']['zip'], $parms['authparms']['encKey']);
189  $attributes[] =
190  ['key' => 'zip',
191  'value' => $enc_attrib,
192  'encrypted' => true];
193  }
194 
195  if (HCU_array_key_value('dob', $parms['MIR']['data']) ) {
196  $enc_attrib = encrypt_smo_openssl($parms['MIR']['data']['dob'], $parms['authparms']['encKey']);
197  $attributes[] =
198  ['key' => 'dob',
199  'value' => $enc_attrib,
200  'encrypted' => true];
201  }
202 
203  if (HCU_array_key_value('ssn', $parms['MIR']['data']) ) {
204  $enc_attrib = encrypt_smo_openssl($parms['MIR']['data']['ssn'], $parms['authparms']['encKey']);
205  $attributes[] =
206  ['key' => 'ssn',
207  'value' => $enc_attrib,
208  'encrypted' => true];
209  }
210 
211 
212 
213 
214  $request = json_encode(array('authId' => $parms['authparms']['authId'],
215  'authKey' => $parms['authparms']['Key'],
216  'domain' => $parms['authparms']['Domain'],
217  'attributes' => $attributes) );
218  return $request;
219 
220 }
221 
222 
223 /**
224  *
225  * @param array $parms trusted detail settings and hcu config settings
226  * @param string $reqURL URL for connection
227  * @param string $reqMethod connection method - defaults to GET
228  * @param array $reqHeaders http headers to be included on curl call
229  * @param string $reqData payload data to be included on curl call
230  * @return array response from curl call, or error if necessary
231  */
232 function smo_embcurl($parms, $reqURL, $reqMethod, $reqHeaders, $reqData = '') {
233  $curlopts = array(
234  CURLOPT_RETURNTRANSFER => 1,
235  CURLOPT_SSL_VERIFYPEER => 0,
236  CURLOPT_SSL_VERIFYHOST => 0,
237  CURLOPT_HEADER => FALSE,
238  CURLOPT_URL => "$reqURL");
239 
240  $ch = @curl_init();
241  @curl_setopt_array($ch, $curlopts);
242  if ($reqMethod != 'GET') {
243  @curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $reqMethod);
244  }
245  if (strlen($reqData) > 0) {
246  @curl_setopt($ch, CURLOPT_POSTFIELDS, $reqData);
247  }
248  @curl_setopt($ch, CURLOPT_HTTPHEADER, $reqHeaders);
249 
250  $response = @curl_exec($ch);
251  if ($parms["logging"] == "enabled") {
252  $logParms = $parms["environment"]; // get the environment info passed in
253  $logParms["token"] = ''; // the id used across all communications in session
254  $logParms["txnId"] = time(); // the id for this transaction
255  $logParms["request"] = "curl "; // the request
256  if ($reqMethod != 'GET') {
257  $logParms["request"] .= "-X $reqMethod ";
258  }
259  if (is_array($reqHeaders)) {
260  foreach ($reqHeaders as $hdr) {
261  $logParms["request"] .= "-H '$hdr' ";
262  }
263  }
264  if (strlen($reqData) > 0) {
265  $logParms["request"] .= "-d '$reqData' "; // the request
266  }
267  $logParms["request"] .= "'$reqURL' "; // the request
268 
269  $logParms["request"] .= "\n{$parms['platform']}";
270 
271  $logParms["reply"] = print_r(curl_getinfo($ch),true);
272  $logParms["reply"] .= "\n$response"; // the response
273 
274  LogSSOActivity($logParms);
275  }
276  $respHTTP = curl_getinfo($ch, CURLINFO_HTTP_CODE);
277  if ($respHTTP >= 400 && $respHTTP < 600) {
278  # HTTP Response 4xx client error or 5xx server error
279  $respArr = array("error" => array("status" => "hcuH" . $respHTTP, "message" => "Connection Failed HTTP Error"));
280  } elseif (curl_errno($ch)) {
281  $respArr = array("error" => array("status" => "hcuC" . curl_errno($ch), "message" => "Curl Error"));
282  } elseif (!isset($response) || $response == '') {
283  $respArr = array("error" => array("status" => "hcuE" . curl_errno($ch), "message" => "Empty Response"));
284  } else {
285  $respArr = json_decode($response, TRUE);
286  if (HCU_array_key_value('hasErrors', $respArr) ) {
287  $respArr['error'] = array("status" => "dmiE", "message" => HCU_array_key_value('errorMessage',$respArr));
288  }
289  }
290 
291  @curl_close($ch);
292  return $respArr;
293 }
294 
295 /**
296  * Format / verify provided MIR data as required for calls to SavvyMoney
297  * Note that SavvyMoney only requires member number and email, member will be
298  * prompted to enter other values if they are not passed.
299  *
300  * @param array $MIR Member info if available
301  * @param string $Ml email address
302  * @param array $reqMIR list of required values from MIR
303  * @param string $datefmt desired format for date values
304  * @param boolean $noEmpty are empty responses acceptable?
305  * @return array member info formatted as needed for SavvyMoney
306  * @throws Exception
307  */
308 function smo_populateMIR($MIR, $Ml, $reqMIR, $datefmt = 'mdY', $noEmpty = false) {
309  try {
310 /*
311 //$mirFields = Array(
312 // "accountnumber",
313 // "firstname",
314 // "middlename",
315 // "lastname",
316 // "email",
317 // "homephone",
318 // "workphone",
319 // "cellphone",
320 // "fax",
321 // "ssn",
322 // "address1",
323 // "address2",
324 // "city",
325 // "state",
326 // "zip",
327 // "cc",
328 // "dob",
329 // "class"
330 // );
331 
332 */
333 
334  date_default_timezone_set('America/Denver');
335  if ( HCU_array_key_value('dob', $MIR) && ($st=strtotime($MIR['dob'])) && $st > strtotime('-100 year') && $st < time()) {
336  $MIR['dob'] = date($datefmt, $st);
337  } else {
338  $MIR['dob'] = '';
339  }
340 
341  $rmlist = array(' ', '-');
342  $MIR['ssn'] = str_replace($rmlist, '', HCU_array_key_value('ssn', $MIR) );
343  if (!ctype_digit($MIR['ssn']) || strlen($MIR['ssn']) <> 9) {
344  unset($MIR['ssn']);
345  }
346 
347  $MIR['zip'] = str_replace($rmlist, '', HCU_array_key_value('zip', $MIR) );
348  if (strlen($MIR['zip']) < 5) {
349  unset($MIR['zip']);
350  } else {
351  $MIR['zip'] = substr($MIR['zip'],0,5); # 5 digits only
352  }
353 
354  $rmlist = array("#", "&", "/", "%", ",", ":", "=", "?", "'");
355 
356  $Ml = str_replace($rmlist, "", $Ml);
357  if (validateEmail($Ml)) {
358  $MIR['email'] = $Ml;
359  } else {
360  $MIR['email'] = str_replace($rmlist, "", HCU_array_key_value('email', $MIR) );
361  if (!validateEmail($MIR['email'])) {
362  unset($MIR['email']);
363  }
364  }
365 
366  $MIR['firstname'] = str_replace($rmlist, "", HCU_array_key_value('firstname', $MIR) );
367  $MIR['lastname'] = str_replace($rmlist, "", HCU_array_key_value('lastname', $MIR) );
368  $MIR['address1'] = str_replace($rmlist, "", HCU_array_key_value('address1', $MIR) );
369  $MIR['address2'] = str_replace($rmlist, "", HCU_array_key_value('address2', $MIR) );
370  $MIR['city'] = str_replace($rmlist, "", HCU_array_key_value('city', $MIR) );
371  $MIR['state'] = str_replace($rmlist, "", HCU_array_key_value('state', $MIR) );
372  if (strlen($MIR['state']) <> 2) {
373  unset($MIR['state']);
374  }
375  $MIR['accountnumber'] = str_replace($rmlist, "", $MIR['accountnumber']);
376  # default country code to US. Assume CU will specify for other countries
377  if (!HCU_array_key_value('cc', $MIR) ) {
378  $MIR['cc'] = 'US';
379  }
380 
381  if ($noEmpty) {
382  if (!HCU_array_key_value('email',$MIR)) {
383  unset($MIR['email']);
384  }
385  if (!HCU_array_key_value('firstname',$MIR)) {
386  unset($MIR['firstname']);
387  }
388  if (!HCU_array_key_value('lastname',$MIR)) {
389  unset($MIR['lastname']);
390  }
391  if (!HCU_array_key_value('address1',$MIR)) {
392  unset($MIR['address1']);
393  }
394  if (!HCU_array_key_value('address2',$MIR)) {
395  unset($MIR['address2']);
396  }
397  if (!HCU_array_key_value('city',$MIR)) {
398  unset($MIR['city']);
399  }
400  if (!HCU_array_key_value('state',$MIR)) {
401  unset($MIR['state']);
402  }
403  if (!HCU_array_key_value('zip',$MIR)) {
404  unset($MIR['zip']);
405  }
406  if (!HCU_array_key_value('accountnumber',$MIR)) {
407  unset($MIR['accountnumber']);
408  }
409  if (!HCU_array_key_value('dob',$MIR)) {
410  unset($MIR['dob']);
411  }
412  if (!HCU_array_key_value('ssn',$MIR)) {
413  unset($MIR['ssn']);
414  }
415  }
416 
417  $missing = array_diff_key($reqMIR, $MIR);
418  if (sizeof($missing)) {
419  throw new Exception("Invalid Member Info (" . join(", ", array_keys($missing)) . ")");
420  }
421  $return['status']['response'] = true;
422  $return['status']['message'] = 'Success';
423  $return['data'] = $MIR;
424  } catch (Exception $e) {
425  $return['status']['response'] = false;
426  $return['status']['message'] = $e->getMessage();
427  $return['data'] = array();
428  }
429  return $return;
430 }
431 
432 
433 /**
434  * Get MIR data for member, or create minimal MIR w/account and email only
435  * @param array $HB_ENV
436  * @param string $accountToUse
437  * @return array
438  * @throws Exception
439  */
440 function smo_getMIR($HB_ENV, $accountToUse, $useBeta=false) {
441  try {
442  //$mirFields = Array(
443 // "accountnumber",
444 // "firstname",
445 // "middlename",
446 // "lastname",
447 // "email",
448 // "homephone",
449 // "workphone",
450 // "cellphone",
451 // "fax",
452 // "ssn",
453 // "address1",
454 // "address2",
455 // "city",
456 // "state",
457 // "zip",
458 // "cc",
459 // "dob",
460 // "class"
461 // );
462 
463 
464  if ($HB_ENV['live']) {
465  /*
466  * just because they are live doesn't guarantee I can get a MIR
467  * consider trusted detail parameter for 'UseMIR' ?
468  */
469  $MIR = GetMemberInfo($HB_ENV, array("member" => $accountToUse));
470  $MIRcode = HCU_array_key_value('code', $MIR);
471  if ( $MIRcode !== "000") {
472  throw new Exception("Invalid MIR {$MIRcode}");
473  }
474  } else {
475  $MIR = array('data' => array('accountnumber' => $accountToUse,
476  'email' => $HB_ENV['Ml'] ) );
477  }
478 #============== begin test hack
479  if ($useBeta) {
480  # If we are in testing mode, override the MIR with some of the
481  # test data from SavvyMoney. Beta site only works with beta data.
482  # note that keys to the array are member numbers from the list of
483  # of testers. 261758,542728,815796,552537 are ISUCU testers
484  # 666665 is localhost scrubcu
485  # 177701, 958777 are localhost cruisecu
486  # not sure 177701 will work right, as first attmept made before
487  # override data - may have trashed it on the far side. Or might
488  # be a timing thing.
489 
490  $testData = array(
491  '261758' => array('data' => [
492  'accountnumber' => "$accountToUse",
493  'email' => $HB_ENV['Ml'],
494  'firstname' => 'DONALD',
495  'lastname' => 'THOMAS',
496  'address1' => '9883 2131 TR N',
497  'city' => 'FOSS',
498  'state' => 'OK',
499  'zip' => '73647',
500  'ssn' => '666026470',
501  'dob' => '01/01/1982',
502  'expectedScore' => '665']),
503  '542728' => array('data' => [
504  'accountnumber' => "$accountToUse",
505  'email' => $HB_ENV['Ml'],
506  'firstname' => 'LARRY',
507  'lastname' => 'RAVETZ',
508  'address1' => '7802 21ST AV',
509  'city' => 'FLUSHING',
510  'state' => 'NY',
511  'zip' => '11370',
512  'ssn' => '666111996',
513  'dob' => '01/01/1995',
514  'expectedScore' => '732']),
515  '815796' => array('data' => [
516  'accountnumber' => "$accountToUse",
517  'email' => $HB_ENV['Ml'],
518  'firstname' => 'MARGARET',
519  'lastname' => 'DANESHMAND',
520  'address1' => '7536 21ST AV',
521  'city' => 'KENOSHA',
522  'state' => 'WI',
523  'zip' => '53143',
524  'ssn' => '666081975',
525  'dob' => '01/01/1977',
526  'expectedScore' => '776']),
527  '552537' => array('data' => [
528  'accountnumber' => "$accountToUse",
529  'email' => $HB_ENV['Ml'],
530  'firstname' => 'JAMES',
531  'lastname' => 'FOLEY',
532  'address1' => '8840 21ST ST SW',
533  'city' => 'MIRAMAR',
534  'state' => 'FL',
535  'zip' => '33025',
536  'ssn' => '666706646',
537  'dob' => '01/01/1960',
538  'expectedScore' => '557']),
539  '177701' => array('data' => [
540  'accountnumber' => "$accountToUse",
541  'email' => $HB_ENV['Ml'],
542  'firstname' => 'MARGARET',
543  'lastname' => 'DANESHMAND',
544  'address1' => '7536 21ST AV',
545  'city' => 'KENOSHA',
546  'state' => 'WI',
547  'zip' => '53143',
548  'ssn' => '666081975',
549  'dob' => '01/01/1977',
550  'expectedScore' => '776']),
551  '958777' => array('data' => [
552  'accountnumber' => "$accountToUse",
553  'email' => $HB_ENV['Ml'],
554  'firstname' => 'JAMES',
555  'lastname' => 'FOLEY',
556  'address1' => '8840 21ST ST SW',
557  'city' => 'MIRAMAR',
558  'state' => 'FL',
559  'zip' => '33025',
560  'ssn' => '666706646',
561  'dob' => '01/01/1960',
562  'expectedScore' => '557']),
563  '666665' => array('data' => [
564  'accountnumber' => "$accountToUse",
565  'email' => $HB_ENV['Ml'],
566  'firstname' => 'JAMES',
567  'lastname' => 'FOLEY',
568  'address1' => '8840 21ST ST SW',
569  'city' => 'MIRAMAR',
570  'state' => 'FL',
571  'zip' => '33025',
572  'ssn' => '666706646',
573  'dob' => '01/01/1960',
574  'expectedScore' => '557'])
575  );
576  if (HCU_array_key_exists($accountToUse, $testData)) {
577  $MIR = $testData[$accountToUse];
578  }
579  }
580 #============== end test hack
581 
582  $Ml = HCU_array_key_value('email',$HB_ENV);
583  # integration uses other values, but if missing user is prompted to
584  # key them in
585  $reqMIR = array(
586  'accountnumber' => 1,
587  'email' => 1
588  );
589 
590  $parsedMIR = smo_populateMIR($MIR['data'], $Ml, $reqMIR, 'mdY', true);
591  if (!$parsedMIR['status']['response']) {
592  throw new Exception($parsedMIR['status']['message']);
593  }
594 
595  } catch (Exception $e) {
596  $parsedMIR = array('status' => array('response' => false,
597  'message' => $e->getMessage() ), 'data' => array() );
598  }
599  return($parsedMIR);
600 }