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