m2u-upass-core / src / my / com / upass / gemalto / GemaltoTokenControllerImpl.java @ 74:214028f5d496
History | View | Annotate | Download (15.9 KB)
1 |
/*
|
---|---|
2 |
* Copyright (c) 2012 Penril Datability (M) Sdn Bhd All rights reserved.
|
3 |
*
|
4 |
* This software is copyrighted. Under the copyright laws, this software
|
5 |
* may not be copied, in whole or in part, without prior written consent
|
6 |
* of Penril Datability (M) Sdn Bhd or its assignees. This software is
|
7 |
* provided under the terms of a license between Penril Datability (M)
|
8 |
* Sdn Bhd and the recipient, and its use is subject to the terms of that
|
9 |
* license.
|
10 |
*/
|
11 |
package my.com.upass.gemalto; |
12 |
|
13 |
import java.util.Date; |
14 |
import java.util.HashMap; |
15 |
import ocra.Ocra; |
16 |
import my.com.upass.Constants; |
17 |
import my.com.upass.TokenBean; |
18 |
import my.com.upass.vasco.TokenController; |
19 |
|
20 |
/*
|
21 |
* <pre>
|
22 |
* PROGRAMMER: Enson Yeoh
|
23 |
* CHANGE-NO:
|
24 |
* TASK-NO:
|
25 |
* DATE CREATED: Oct 5, 2012
|
26 |
* TAG AS:
|
27 |
* REASON(S):
|
28 |
* MODIFICATION:
|
29 |
* </pre>
|
30 |
*
|
31 |
*
|
32 |
* Requirements:
|
33 |
* 1) Retrieve the tokenBean and override the existing tokenBean object.
|
34 |
* 2) Override the existing serial number with the given tokenBean.
|
35 |
* 3) Override the existing authentication mode with the given tokenBean.
|
36 |
* 4) Override the existing blob with the given tokenBean.
|
37 |
* 5) Update useCount (total number of usage of the given token)
|
38 |
* 6) Update errorCount (total number of errors attempted by the given token)
|
39 |
* 7) Update last first time (the first usage date of the given token)
|
40 |
* 8) Update last used time (the last usage date of the given token)
|
41 |
* 9) Update the tokenBean object whenever there is changes.
|
42 |
* 10) Verify token with the given password (OTP)
|
43 |
* 11) Blob synchronization.
|
44 |
* 12) Check last authentication
|
45 |
*
|
46 |
*
|
47 |
*/
|
48 |
|
49 |
public class GemaltoTokenControllerImpl implements TokenController |
50 |
{ |
51 |
private Ocra myocra = new Ocra(); |
52 |
|
53 |
private TokenBean tb;
|
54 |
private int retCode; |
55 |
private String serialNumber; |
56 |
private String authMode; |
57 |
private byte[] blob; |
58 |
private int useCount; |
59 |
private int errorCount; |
60 |
private Date lastTimeUsed; |
61 |
private Date firstTimeUsed; |
62 |
private Date lastAuthentication; |
63 |
private Date tokenExpectedDateTime; |
64 |
|
65 |
/**
|
66 |
* this will override the existing tokenBean object
|
67 |
* this will override the existing serial number, authentication mode and blob
|
68 |
*
|
69 |
* @param tokenBean
|
70 |
*/
|
71 |
public GemaltoTokenControllerImpl(TokenBean tokenBean)
|
72 |
{ |
73 |
this.tb = tokenBean;
|
74 |
setSerialNumber(); |
75 |
setAuthMode(); |
76 |
setBlob(); |
77 |
} |
78 |
|
79 |
/**
|
80 |
* this will override the existing last authentication date
|
81 |
*
|
82 |
* @param LastAuthentication
|
83 |
*/
|
84 |
public void setLastAuthentication(Date lastAuthentication) |
85 |
{ |
86 |
this.lastAuthentication = lastAuthentication;
|
87 |
} |
88 |
|
89 |
/**
|
90 |
* this will return updated last authentication date
|
91 |
*
|
92 |
* @return
|
93 |
*/
|
94 |
public Date getLastAuthentication() |
95 |
{ |
96 |
return lastAuthentication;
|
97 |
} |
98 |
|
99 |
/**
|
100 |
* this will override the existing token expected date and time
|
101 |
*
|
102 |
* @param LastAuthentication
|
103 |
*/
|
104 |
public void setTokenExpectedDateTime(Date tokenExpectedDateTime) |
105 |
{ |
106 |
this.tokenExpectedDateTime = tokenExpectedDateTime;
|
107 |
} |
108 |
|
109 |
/**
|
110 |
* this will return updated token expected date and time
|
111 |
*
|
112 |
* @return
|
113 |
*/
|
114 |
public Date getTokenExpectedDateTime() |
115 |
{ |
116 |
return tokenExpectedDateTime;
|
117 |
} |
118 |
|
119 |
/**
|
120 |
* this will override the existing tokenBean
|
121 |
*
|
122 |
*/
|
123 |
public void setObject(TokenBean tokenBean) |
124 |
{ |
125 |
this.tb = tokenBean;
|
126 |
} |
127 |
|
128 |
/**
|
129 |
* this will return the updated object (tokenBean)
|
130 |
*
|
131 |
*/
|
132 |
public TokenBean getUpdatedObject()
|
133 |
{ |
134 |
return tb;
|
135 |
} |
136 |
|
137 |
/**
|
138 |
* this will override the existing serial number
|
139 |
*
|
140 |
*/
|
141 |
private void setSerialNumber() |
142 |
{ |
143 |
this.serialNumber = tb.getVserialNumber();
|
144 |
} |
145 |
|
146 |
/**
|
147 |
* this will override the existing authentication mode
|
148 |
*
|
149 |
*/
|
150 |
private void setAuthMode() |
151 |
{ |
152 |
this.authMode = tb.getVdpAuthMode();
|
153 |
} |
154 |
|
155 |
/**
|
156 |
* this will override the existing blob
|
157 |
*
|
158 |
*/
|
159 |
private void setBlob() |
160 |
{ |
161 |
this.blob = tb.getVdpCipherText();
|
162 |
} |
163 |
|
164 |
/**
|
165 |
* this will return the updated blob
|
166 |
*
|
167 |
*/
|
168 |
public byte[] getUpdatedBlob() |
169 |
{ |
170 |
return this.blob; |
171 |
} |
172 |
|
173 |
/**
|
174 |
* this will override the existing useCount
|
175 |
*
|
176 |
*/
|
177 |
public void setUseCount() |
178 |
{ |
179 |
this.useCount = tb.getVuseCount();
|
180 |
} |
181 |
|
182 |
/**
|
183 |
* this will increase the existing useCount by 1 whenever it is invoked.
|
184 |
*
|
185 |
*/
|
186 |
public void increaseUseCount() |
187 |
{ |
188 |
this.useCount++;
|
189 |
} |
190 |
|
191 |
/**
|
192 |
* this will return the updated useCount
|
193 |
*
|
194 |
*/
|
195 |
public int getUseCount() |
196 |
{ |
197 |
return this.useCount; |
198 |
} |
199 |
|
200 |
/**
|
201 |
* this will override the existing errorCount
|
202 |
*
|
203 |
*/
|
204 |
public void setErrorCount() |
205 |
{ |
206 |
this.errorCount = tb.getVerrorCount();
|
207 |
} |
208 |
|
209 |
/**
|
210 |
* this will increase the existing errorCount by 1 whenever it is invoked.
|
211 |
*
|
212 |
*/
|
213 |
public void increaseErrorCount() |
214 |
{ |
215 |
this.errorCount++;
|
216 |
} |
217 |
|
218 |
/**
|
219 |
* this will return the updated errorCount
|
220 |
*
|
221 |
*/
|
222 |
public int getErrorCount() |
223 |
{ |
224 |
return this.errorCount; |
225 |
} |
226 |
|
227 |
/**
|
228 |
* this will override the existing first used date
|
229 |
*
|
230 |
*/
|
231 |
public void setFirstTimeUsed() |
232 |
{ |
233 |
this.firstTimeUsed = tb.getVdateFirstUsed();
|
234 |
} |
235 |
|
236 |
/**
|
237 |
* case 1: if first used date is null, then first used date will be override by current date.
|
238 |
* case 2: throw exception if first used date is after last used date.
|
239 |
*
|
240 |
* @param currentDate
|
241 |
* @throws Exception
|
242 |
*/
|
243 |
public void setFirstTimeUsed(Date currentDate) throws Exception |
244 |
{ |
245 |
if (this.firstTimeUsed == null) |
246 |
{ |
247 |
this.firstTimeUsed = currentDate;
|
248 |
} |
249 |
else if (this.firstTimeUsed.compareTo(this.lastTimeUsed) > 0) |
250 |
{ |
251 |
throw new Exception("Invalid date. First used date cannot be after last used date."); |
252 |
} |
253 |
} |
254 |
|
255 |
/**
|
256 |
* this will return the updated first used date
|
257 |
*
|
258 |
*/
|
259 |
public Date getFirstTimeUsed() |
260 |
{ |
261 |
return firstTimeUsed;
|
262 |
} |
263 |
|
264 |
/**
|
265 |
* this will override the existing last used date.
|
266 |
*
|
267 |
*/
|
268 |
public void setLastTimeUsed() |
269 |
{ |
270 |
this.lastTimeUsed = tb.getVdateFirstUsed();
|
271 |
} |
272 |
|
273 |
/**
|
274 |
* case 1: if last used date is null, then last used date will be override by current date.
|
275 |
* case 2: if last used date is before the current date, then last used date will be override by current date.
|
276 |
* case 3: throw exception if last used date is after the current date.
|
277 |
* case 4: throw exception if last used date is before first used date.
|
278 |
*
|
279 |
* @param currentDate
|
280 |
* @throws Exception
|
281 |
*/
|
282 |
public void setLastTimeUsed(Date currentDate) throws Exception |
283 |
{ |
284 |
if (this.lastTimeUsed == null) |
285 |
{ |
286 |
this.lastTimeUsed = currentDate;
|
287 |
} |
288 |
else if (this.lastTimeUsed.compareTo(currentDate) < 0) |
289 |
{ |
290 |
this.lastTimeUsed = currentDate;
|
291 |
} |
292 |
else if (this.lastTimeUsed.compareTo(currentDate) > 0) |
293 |
{ |
294 |
throw new Exception("Invalid date. Last used date cannot be after current date."); |
295 |
} |
296 |
else if (this.lastTimeUsed.compareTo(this.firstTimeUsed) < 0) |
297 |
{ |
298 |
throw new Exception("Invalid date. Last used date cannot be before first used date."); |
299 |
} |
300 |
} |
301 |
|
302 |
/**
|
303 |
* this will return the updated last used date
|
304 |
*
|
305 |
*/
|
306 |
public Date getLastTimeUsed() |
307 |
{ |
308 |
return lastTimeUsed;
|
309 |
} |
310 |
|
311 |
/**
|
312 |
* this will return the updated returned code by each invoked method
|
313 |
* it also acts as last returned error code.
|
314 |
*
|
315 |
*/
|
316 |
public int getRetCode() |
317 |
{ |
318 |
return retCode;
|
319 |
} |
320 |
|
321 |
/**
|
322 |
* this will return the updated error text based on the error code
|
323 |
*
|
324 |
*/
|
325 |
public String getLastError() |
326 |
{ |
327 |
String code = null; |
328 |
|
329 |
switch (this.retCode) |
330 |
{ |
331 |
case 0: |
332 |
code = "0";
|
333 |
case 1: |
334 |
code = "1";
|
335 |
case 2: |
336 |
code = "18";
|
337 |
case 3: |
338 |
code = "19";
|
339 |
case 4: |
340 |
code = "20";
|
341 |
case 5: |
342 |
code = "21";
|
343 |
case 6: |
344 |
code = "22";
|
345 |
case 7: |
346 |
code = "3";
|
347 |
case 8: |
348 |
code = "23";
|
349 |
case 9: |
350 |
code = "24";
|
351 |
case 10: |
352 |
code = "25";
|
353 |
case 11: |
354 |
code = "26";
|
355 |
default:
|
356 |
try
|
357 |
{ |
358 |
throw new Exception("Invalid error code."); |
359 |
} catch (Exception e) |
360 |
{ |
361 |
e.printStackTrace(); |
362 |
} |
363 |
} |
364 |
|
365 |
return (String) Constants.getErrText(code).get(code); |
366 |
} |
367 |
|
368 |
/**
|
369 |
* Verify the entered On Time Password (OTP/password) for the given token
|
370 |
*
|
371 |
*/
|
372 |
public int verifyToken(String otp, String userAlias, String pin) throws Exception |
373 |
{ |
374 |
return verifyToken(otp);
|
375 |
} |
376 |
|
377 |
/**
|
378 |
* Verify the entered On Time Password (OTP/password) for the given token
|
379 |
*
|
380 |
*/
|
381 |
|
382 |
public int verifyToken(String password) |
383 |
{ |
384 |
int[] blobLen = new int[1]; |
385 |
blobLen[0] = 500; |
386 |
|
387 |
String[] blobInString = new String[1]; |
388 |
blobInString[0] = new String(this.blob); |
389 |
|
390 |
// Time based OTP verification
|
391 |
// Authentication window need to be bigger for first OTP verification.
|
392 |
int result = myocra.comAuthBlob(0, 0, this.serialNumber, Constants.getAuthenticationMode(this.authMode), 20, 1, |
393 |
100,
|
394 |
new byte[0], 0, |
395 |
new byte[0], 0, |
396 |
new byte[0], 0, |
397 |
6, password,
|
398 |
blobInString, blobLen); |
399 |
|
400 |
this.useCount++;
|
401 |
this.firstTimeUsed = new Date(); |
402 |
this.lastTimeUsed = new Date(); |
403 |
|
404 |
if (result == 0) |
405 |
{ |
406 |
this.blob = blobInString[0].getBytes(); |
407 |
this.retCode = result;
|
408 |
updateTokenObject(); |
409 |
} |
410 |
else
|
411 |
{ |
412 |
try
|
413 |
{ |
414 |
this.errorCount++;
|
415 |
this.retCode = result;
|
416 |
updateTokenObject(); |
417 |
return errorCodeConversion(result);
|
418 |
} catch (Exception e) |
419 |
{ |
420 |
e.printStackTrace(); |
421 |
} |
422 |
} |
423 |
|
424 |
return Constants.ERR_SUCCESS;
|
425 |
} |
426 |
|
427 |
/**
|
428 |
* Check last successful authentication
|
429 |
*
|
430 |
* @return
|
431 |
*/
|
432 |
public int checkLastAuthentication() |
433 |
{ |
434 |
String[] blobInString = new String[1]; |
435 |
blobInString[0] = new String(this.blob); |
436 |
int[] LastAuthTime = new int[1]; |
437 |
int[] TokenExpectedTime = new int[1]; |
438 |
|
439 |
int result = myocra.comGetInfo(0, 0, serialNumber, Constants.getAuthenticationMode("AUTH_OCRA"), blobInString, |
440 |
blobInString[0].length(), LastAuthTime, TokenExpectedTime);
|
441 |
|
442 |
if (result == 0) |
443 |
{ |
444 |
// For first use of blob, LastAuthTimeDate returns a value of 0 or in Date format, Thu Jan 01 07:30:00 SGT
|
445 |
// 1970.
|
446 |
if (LastAuthTime[0] == 0) |
447 |
{ |
448 |
System.out.println("No Last authentication."); |
449 |
} |
450 |
else
|
451 |
{ |
452 |
this.blob = blobInString[0].getBytes(); |
453 |
this.lastAuthentication = new Date(Long.parseLong("" + LastAuthTime[0]) * 1000); |
454 |
this.tokenExpectedDateTime = new Date(Long.parseLong("" + TokenExpectedTime[0]) * 1000); |
455 |
this.retCode = result;
|
456 |
} |
457 |
} |
458 |
else
|
459 |
{ |
460 |
try
|
461 |
{ |
462 |
this.errorCount++;
|
463 |
this.retCode = result;
|
464 |
updateTokenObject(); |
465 |
return errorCodeConversion(result);
|
466 |
} catch (Exception e) |
467 |
{ |
468 |
e.printStackTrace(); |
469 |
} |
470 |
} |
471 |
|
472 |
return Constants.ERR_SUCCESS;
|
473 |
} |
474 |
|
475 |
/**
|
476 |
* In order to perform blob synchronization, 2 token verifications shall be performed .
|
477 |
* First token verification must have larger time drift windows then the second's.
|
478 |
* First token verification must be executed first before execute the second.
|
479 |
* Second token verification must use new password (OTP) and lesser time drift window.
|
480 |
* If the returned result of first verification is successful or 0, then second verification will be executed.
|
481 |
* If the returned results of both first and second verifications are successful or 0, then blobSynchronization is
|
482 |
* successful,
|
483 |
* otherwise, it is failed.
|
484 |
*
|
485 |
*
|
486 |
* @param timeDriftWindow
|
487 |
* @param password
|
488 |
* @return
|
489 |
*/
|
490 |
public int blobSynchronization(int timeDriftWindow1, String password1, int timeDriftWindow2, String password2) |
491 |
{ |
492 |
int result = blobSynchronizationTokenVerification(timeDriftWindow1, password1);
|
493 |
|
494 |
if (result == 0) |
495 |
{ |
496 |
result = blobSynchronizationTokenVerification(timeDriftWindow2, password2); |
497 |
|
498 |
if (result == 0) |
499 |
{ |
500 |
this.retCode = result;
|
501 |
updateTokenObject(); |
502 |
} |
503 |
else
|
504 |
{ |
505 |
try
|
506 |
{ |
507 |
this.errorCount++;
|
508 |
this.retCode = result;
|
509 |
updateTokenObject(); |
510 |
return errorCodeConversion(result);
|
511 |
} catch (Exception e) |
512 |
{ |
513 |
e.printStackTrace(); |
514 |
} |
515 |
} |
516 |
} |
517 |
else
|
518 |
{ |
519 |
try
|
520 |
{ |
521 |
this.retCode = result;
|
522 |
return errorCodeConversion(result);
|
523 |
} catch (Exception e) |
524 |
{ |
525 |
e.printStackTrace(); |
526 |
} |
527 |
} |
528 |
|
529 |
return Constants.ERR_SUCCESS;
|
530 |
} |
531 |
|
532 |
/**
|
533 |
* This method will be used in blobSynchronization to verify the token and blob synchronization
|
534 |
*
|
535 |
* @param timeDriftWindow
|
536 |
* @param password
|
537 |
* @return
|
538 |
*/
|
539 |
private int blobSynchronizationTokenVerification(int timeDriftWindow, String password) |
540 |
{ |
541 |
if (this.retCode == 0) |
542 |
{ |
543 |
int[] blobLen = new int[1]; |
544 |
blobLen[0] = 500; |
545 |
|
546 |
String[] blobInString = new String[1]; |
547 |
blobInString[0] = new String(this.blob); |
548 |
|
549 |
// Time based OTP verification
|
550 |
// Authentication window need to be bigger for first OTP verification.
|
551 |
int result = myocra.comAuthBlob(0, 0, this.serialNumber, Constants.getAuthenticationMode(this.authMode), |
552 |
timeDriftWindow, 1, 100, |
553 |
new byte[0], 0, |
554 |
new byte[0], 0, |
555 |
new byte[0], 0, |
556 |
6, password,
|
557 |
blobInString, blobLen); |
558 |
|
559 |
this.useCount++;
|
560 |
this.firstTimeUsed = new Date(); |
561 |
this.lastTimeUsed = new Date(); |
562 |
|
563 |
if (result == 0) |
564 |
{ |
565 |
this.blob = blobInString[0].getBytes(); |
566 |
this.retCode = result;
|
567 |
updateTokenObject(); |
568 |
} |
569 |
else
|
570 |
{ |
571 |
try
|
572 |
{ |
573 |
this.errorCount++;
|
574 |
this.retCode = result;
|
575 |
updateTokenObject(); |
576 |
return errorCodeConversion(result);
|
577 |
} catch (Exception e) |
578 |
{ |
579 |
e.printStackTrace(); |
580 |
} |
581 |
} |
582 |
|
583 |
} |
584 |
|
585 |
return Constants.ERR_SUCCESS;
|
586 |
} |
587 |
|
588 |
/**
|
589 |
* This will reset the token back to the initial state
|
590 |
* The blob will be regenerated with the backup blob which is initially generated when it is imported from the pskc
|
591 |
* file.
|
592 |
*
|
593 |
*/
|
594 |
public int resetToken() |
595 |
{ |
596 |
this.retCode = 0; |
597 |
this.blob = tb.getVbkCipherText();
|
598 |
this.useCount = 0; |
599 |
this.errorCount = 0; |
600 |
this.lastTimeUsed = null; |
601 |
this.firstTimeUsed = null; |
602 |
this.lastAuthentication = null; |
603 |
this.tokenExpectedDateTime = null; |
604 |
updateTokenObject(); |
605 |
|
606 |
return Constants.ERR_SUCCESS;
|
607 |
} |
608 |
|
609 |
public HashMap<String, String> getTokenBlobInfo() |
610 |
{ |
611 |
HashMap<String, String> map = new HashMap<String, String>(); |
612 |
|
613 |
map.put("TOKEN_MODEL", tb.getVdpModel());
|
614 |
map.put("USE_COUNT", Integer.toString(tb.getVuseCount())); |
615 |
map.put("ERROR_COUNT", Integer.toString(tb.getVerrorCount())); |
616 |
map.put("LAST_TIME_USED", String.valueOf(tb.getVdateLastUsed())); |
617 |
map.put("TIME_STEP_USED", Integer.toString(Constants.TIMESTEPUSED)); |
618 |
|
619 |
return map;
|
620 |
} |
621 |
|
622 |
/**
|
623 |
* display gemalto token information
|
624 |
* In comparion with vasco, only limited information will be displayed.
|
625 |
*
|
626 |
*/
|
627 |
public void displayTokenInfo() |
628 |
{ |
629 |
System.out.println("--Info----------------------------------------------"); |
630 |
System.out.println("TOKEN_MODEL......." + tb.getVdpModel()); |
631 |
System.out.println("USE_COUNT........." + tb.getVuseCount()); |
632 |
System.out.println("ERR_COUNT........." + tb.getVerrorCount()); |
633 |
System.out.println("LAST_TIME_USED...." + tb.getVdateLastUsed()); |
634 |
System.out.println("TIME_STEP_USED...." + Constants.TIMESTEPUSED); |
635 |
System.out.println("----------------------------------------------------"); |
636 |
} |
637 |
|
638 |
/**
|
639 |
* This will override the existing tokenBean object
|
640 |
*
|
641 |
*/
|
642 |
private void updateTokenObject() |
643 |
{ |
644 |
tb.setVuseCount(this.useCount);
|
645 |
tb.setVerrorCount(this.errorCount);
|
646 |
tb.setVdpCipherText(this.blob);
|
647 |
tb.setVdateFirstUsed(this.firstTimeUsed);
|
648 |
tb.setVdateLastUsed(this.lastTimeUsed);
|
649 |
} |
650 |
|
651 |
/*
|
652 |
* Code the gemalto returned error code to match with vasco's
|
653 |
*/
|
654 |
private int errorCodeConversion(int errorCode) throws Exception |
655 |
{ |
656 |
switch (errorCode)
|
657 |
{ |
658 |
case 0: |
659 |
return Constants.ERR_SUCCESS;
|
660 |
case 1: |
661 |
return Constants.ERR_INVALID_CREDENTIAL;
|
662 |
case 2: |
663 |
return Constants.ERR_BLOBINVALID;
|
664 |
case 3: |
665 |
return Constants.ERR_BUFFER;
|
666 |
case 4: |
667 |
return Constants.ERR_PARAM;
|
668 |
case 5: |
669 |
return Constants.ERR_SNOINVALID;
|
670 |
case 6: |
671 |
return Constants.ERR_OTPINVALID;
|
672 |
case 7: |
673 |
return Constants.ERR_REUSED_PASSWD;
|
674 |
case 8: |
675 |
return Constants.ERR_BLOBOTINIT;
|
676 |
case 9: |
677 |
return Constants.ERR_FAILED;
|
678 |
case 10: |
679 |
return Constants.ERR_REQINVALID;
|
680 |
case 11: |
681 |
return Constants.ERR_AUTH_MODE;
|
682 |
default:
|
683 |
throw new Exception("Invalid error code."); |
684 |
} |
685 |
} |
686 |
|
687 |
public int syncToken(String userAlias, String otp1, String otp2) { |
688 |
// TODO Auto-generated method stub
|
689 |
return 0; |
690 |
} |
691 |
} |