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