Clover Coverage Report
Coverage timestamp: Sun Mar 23 2008 08:24:39 GMT
216   487   55   30.86
62   321   0.28   3.5
7     8.71  
2    
 
 
  SAWSCmdPromptCallbackHandler       Line # 82 203 53 0.4% 0.0037453184
  MaskingThread       Line # 445 13 3 0% 0.0
 
No Tests
 
1    /*
2    * Copyright (c) 2006, University of Kent
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are met:
7    *
8    * Redistributions of source code must retain the above copyright notice, this
9    * list of conditions and the following disclaimer.
10    *
11    * Redistributions in binary form must reproduce the above copyright notice,
12    * this list of conditions and the following disclaimer in the documentation
13    * and/or other materials provided with the distribution.
14    *
15    * 1. Neither the name of the University of Kent nor the names of its
16    * contributors may be used to endorse or promote products derived from this
17    * software without specific prior written permission.
18    *
19    * 2. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20    * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21    * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22    * PURPOSE ARE DISCLAIMED.
23    *
24    * 3. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31    * POSSIBILITY OF SUCH DAMAGE.
32    *
33    * 4. YOU AGREE THAT THE EXCLUSIONS IN PARAGRAPHS 2 AND 3 ABOVE ARE REASONABLE
34    * IN THE CIRCUMSTANCES. IN PARTICULAR, YOU ACKNOWLEDGE (1) THAT THIS
35    * SOFTWARE HAS BEEN MADE AVAILABLE TO YOU FREE OF CHARGE, (2) THAT THIS
36    * SOFTWARE IS NOT "PRODUCT" QUALITY, BUT HAS BEEN PRODUCED BY A RESEARCH
37    * GROUP WHO DESIRE TO MAKE THIS SOFTWARE FREELY AVAILABLE TO PEOPLE WHO WISH
38    * TO USE IT, AND (3) THAT BECAUSE THIS SOFTWARE IS NOT OF "PRODUCT" QUALITY
39    * IT IS INEVITABLE THAT THERE WILL BE BUGS AND ERRORS, AND POSSIBLY MORE
40    * SERIOUS FAULTS, IN THIS SOFTWARE.
41    *
42    * 5. This license is governed, except to the extent that local laws
43    * necessarily apply, by the laws of England and Wales.
44    */
45   
46    package issrg.SAWS.callback;
47   
48    import issrg.SAWS.callback.gui.CreateCertificateDialog;
49    import issrg.SAWS.SAWSServer;
50    import issrg.SAWS.callback.gui.inputPassword;
51   
52    import issrg.SAWS.util.CertificateData;
53   
54    import issrg.SAWS.util.SAWSLogWriter;
55   
56    import java.awt.Component;
57   
58    import java.io.BufferedInputStream;
59    import java.io.BufferedReader;
60    import java.io.IOException;
61    import java.io.InputStream;
62    import java.io.InputStreamReader;
63    import java.io.PipedInputStream;
64    import java.io.PushbackInputStream;
65   
66    import java.util.Arrays;
67   
68    import java.util.Calendar;
69   
70    import javax.security.auth.callback.Callback;
71    import javax.security.auth.callback.CallbackHandler;
72    import javax.security.auth.callback.UnsupportedCallbackException;
73   
74    /**
75    * This class represents the callback handler that uses the command prompt
76    * to interact with the user.
77    *
78    * @author E. Silva
79    * @version 1.0, Mar. 2007
80    */
81   
 
82    public class SAWSCmdPromptCallbackHandler implements CallbackHandler {
83   
84    private static SAWSLogWriter sawsDebugLog = new SAWSLogWriter(SAWSCmdPromptCallbackHandler.class.getName());
85   
86    /**
87    * Constructor of the class.
88    */
 
89  8 toggle public SAWSCmdPromptCallbackHandler() {
90    }
91   
92   
93    /**
94    * Method that handles the callbacks sent as parameter.
95    * @param callbacks The list of callbacks to be handled.
96    * @throws UnsupportedCallbackException If one of the callbacks are not known (supported).
97    */
 
98  0 toggle public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
99  0 if (callbacks == null) {
100  0 throw new UnsupportedCallbackException(null, "ERROR: Callbacks can not be null.");
101    }
102   
103  0 for (int i = 0; i < callbacks.length; i++) {
104  0 if (callbacks[i] instanceof SAWSTextOutputCallback) {
105  0 switch (((SAWSTextOutputCallback)callbacks[i]).getMessageType()) {
106  0 case SAWSTextOutputCallback.ERROR:
107  0 System.err.println("\nERROR: " + ((SAWSTextOutputCallback)callbacks[i]).getMessage());
108  0 break;
109  0 case SAWSTextOutputCallback.INFORMATION:
110  0 System.err.println("\nINFO: " + ((SAWSTextOutputCallback)callbacks[i]).getMessage());
111  0 break;
112  0 case SAWSTextOutputCallback.WARNING:
113  0 System.err.println("\nWARNING: " + ((SAWSTextOutputCallback)callbacks[i]).getMessage());
114  0 break;
115  0 case SAWSTextOutputCallback.LONG_MESSAGE:
116  0 System.err.println("\n" + ((SAWSTextOutputCallback)callbacks[i]).getMessage());
117  0 break;
118    }
119  0 } else if (callbacks[i] instanceof SAWSPasswordCallback) {
120  0 SAWSPasswordCallback pc = (SAWSPasswordCallback)callbacks[i];
121  0 System.out.println("\n" + pc.getPrompt());
122  0 System.out.flush();
123   
124  0 try {
125  0 pc.setPassword(readPassword(System.in));
126    } catch (IOException e) {
127  0 System.err.println("\nWARNING: Fail to read the password from the command prompt.");
128  0 sawsDebugLog.write("\nWARNING: Fail to read the password from the command prompt.");
129    }
130  0 } else if (callbacks[i] instanceof CertificateDataCallback) {
131  0 CertificateDataCallback cdc = (CertificateDataCallback) callbacks[i];
132  0 CertificateData cd = this.readCertificateData(cdc);
133  0 cdc.setCertData(cd);
134  0 } else if (callbacks[i] instanceof SAWSChoiceCallback) {
135  0 SAWSChoiceCallback cc = (SAWSChoiceCallback) callbacks[i];
136   
137  0 System.out.println("\n" + cc.getPrompt() + "\n");
138  0 System.out.flush();
139   
140  0 InputStreamReader is = new InputStreamReader(System.in);
141  0 BufferedReader systemIn = new BufferedReader(is);
142   
143  0 String[] options = cc.getOptions();
144  0 int n = options.length;
145   
146  0 for (int j = 0; j < n; j = j + 1) {
147  0 System.out.println("\t[" + (j+1) + "] " + options[j]);
148    }
149  0 System.out.println("\nPlease type the number that corresponds to your choice:");
150  0 int choice = -1;
151   
152  0 boolean finished = false;
153  0 while (!finished) {
154  0 try {
155  0 choice = Integer.parseInt(systemIn.readLine());
156    } catch (IOException e) {
157  0 System.err.println("ERROR: Fail when reading the option from the command prompt.");
158  0 sawsDebugLog.write("ERROR: Fail when reading the option from the command prompt.");
159    } catch (Exception ex) {
160  0 System.err.println("\nWARNING: Invalid option. Please input a valid number for the option:");
161    }
162  0 if ((choice <= 0) || (choice > n)) {
163  0 System.err.println("\nWARNING: Invalid option. Please input a valid option:");
164    } else {
165  0 finished = true;
166    }
167    }
168   
169  0 cc.setSelectedIndex(choice - 1);
170  0 } else if (callbacks[i] instanceof SAWSTextInputCallback) {
171  0 SAWSTextInputCallback cc = (SAWSTextInputCallback) callbacks[i];
172   
173  0 System.out.println("\n" + cc.getPrompt());
174  0 System.out.flush();
175   
176  0 InputStreamReader is = new InputStreamReader(System.in);
177  0 BufferedReader systemIn = new BufferedReader(is);
178   
179  0 String value = null;
180   
181  0 try {
182  0 value = systemIn.readLine();
183    } catch (IOException ioe) {
184  0 System.err.println("ERROR: Fail when reading a value from the command prompt.");
185  0 sawsDebugLog.write("ERROR: Fail when reading a value from the command prompt.");
186    }
187  0 cc.setText(value);
188   
189    } else {
190  0 throw new UnsupportedCallbackException
191    (callbacks[i], "ERROR: Unrecognized Callback.");
192    }
193    }
194    }
195   
196    /**
197    * Method responsible for asking the user the data about the certificate
198    * being created.
199    *
200    * @param cdc The callback generated to ask data about the certificate.
201    * @return The data about the certificate
202    */
 
203  0 toggle private CertificateData readCertificateData(CertificateDataCallback cdc) {
204  0 CertificateData cd = new CertificateData();
205  0 InputStreamReader is = new InputStreamReader(System.in);
206  0 BufferedReader systemIn = new BufferedReader(is);
207  0 boolean valid = false;
208   
209  0 System.out.println("\nPlease input the following data for the certificate:");
210  0 try {
211  0 Loop1:
212  0 while (!valid) {
213   
214    // read Validity
215  0 System.out.println("\nValidity (DDMMYYYY):");
216  0 String validity = systemIn.readLine();
217  0 if (validity.length() != 8) {
218  0 System.err.println("WARNING: Please input a date in the format DDMMYYYY.");
219  0 continue Loop1;
220    }
221   
222  0 Calendar c = Calendar.getInstance();
223  0 c.setLenient(false);
224  0 try {
225  0 c.set(Calendar.YEAR, Integer.parseInt(validity.substring(4, 8)));
226  0 c.set(Calendar.MONTH, Integer.parseInt(validity.substring(2, 4)) - 1);
227  0 c.set(Calendar.DATE, Integer.parseInt(validity.substring(0, 2)));
228   
229  0 Calendar today = Calendar.getInstance();
230  0 today.set(Calendar.HOUR, 0);
231  0 today.set(Calendar.MINUTE, 0);
232  0 today.set(Calendar.SECOND, 0);
233   
234  0 Calendar temp = Calendar.getInstance();
235  0 temp.set(c.get(Calendar.YEAR), c.get(Calendar.MONTH),
236    c.get(Calendar.DATE), 0, 0, 0);
237   
238  0 long todayMili = today.getTimeInMillis();
239  0 long dateMili = temp.getTimeInMillis();
240   
241  0 if (todayMili > dateMili) {
242  0 System.err.println("WARNING: The selected date must be after to "
243    + today.get(Calendar.DATE) + "/" + (today.get(Calendar.MONTH) + 1) + "/"
244    + today.get(Calendar.YEAR) + ".");
245  0 continue Loop1;
246    }
247   
248    /*calculate the number of days from today to the specified date
249    * and set teh field validity of the class CertificateData */
250  0 int days = (int)((dateMili - todayMili) / 1000 / 60 / 60 / 24);
251  0 today.add(Calendar.DATE, days);
252   
253  0 if (today.compareTo(temp) > 0) {
254  0 days = days - 1;
255  0 } else if (today.compareTo(temp) < 0) {
256  0 days = days + 1;
257    }
258   
259  0 cd.setValidity(days);
260   
261  0 valid = true;
262   
263    } catch (NumberFormatException nfe) {
264  0 System.err.println("WARNING: The date can not contain letters, only numbers. Please type again.");
265    } catch (IllegalArgumentException iae) {
266  0 System.err.println("WARNING: " + iae.getMessage() + " is not valid. Please type the validity date again.");
267    }
268    }
269   
270  0 valid = false;
271   
272    //read Subject Name
273  0 System.out.println("\nPlease answer the following questions."
274    + "\n[Press Enter (Ret) to skip the question. At least one of the six questions must be answered.");
275   
276  0 while (!valid) {
277  0 System.out.println("\nWhat is your complete name (CN)?");
278  0 cd.setCommonName(systemIn.readLine());
279   
280  0 System.out.println("\nWhat is the name of your Organizational Unit (OU)?");
281  0 cd.setOrganizationUnitName(systemIn.readLine());
282   
283  0 System.out.println("\nWhat is the name of your Organization (O)?");
284  0 cd.setOrganizationName(systemIn.readLine());
285   
286  0 System.out.println("\nWhat is the name of your City or Locality (L)?");
287  0 cd.setLocalityName(systemIn.readLine());
288   
289  0 System.out.println("\nWhat is the name of your Province or State (S)?");
290  0 cd.setStateName(systemIn.readLine());
291   
292  0 Country:
293    while (true) {
294  0 System.out.println("\nWhat is the two-letter Country code for this unit (C)?");
295  0 String country = systemIn.readLine();
296  0 if (country != null && !country.equals("") && country.length() != 2) {
297  0 System.err.println("WARNING: The country code, if specified, must contain two letters. Please try again.");
298  0 continue Country;
299    } else {
300  0 cd.setCountryName(country);
301  0 break Country;
302    }
303    }
304   
305  0 String sn = cd.toSubjectName();
306  0 if (sn != null && !sn.equals("")) {
307  0 System.out.println("\nIs " + sn + " correct? [y/n]");
308  0 System.out.print("[no]: ");
309  0 String option = systemIn.readLine();
310  0 if (option.equalsIgnoreCase("y") || option.equalsIgnoreCase("yes")) {
311  0 valid = true;
312    }
313    } else {
314  0 System.err.println("WARNING: At least one of the questions must be answered. Please try again.");
315    }
316    }
317   
318  0 valid = false;
319  0 String alg = null;
320    //read Algorithm Name
321  0 if (cdc.getType() == CertificateDataCallback.ENCRYPTION) {
322  0 cd.setAlgorithm("RSA");
323    } else {
324  0 System.out.println("\nPlease input the name of the algorithm for this certificate: [RSA or DSA]");
325   
326  0 while (!valid) {
327  0 alg = systemIn.readLine();
328  0 if (alg != null && (alg.equalsIgnoreCase("RSA")
329    || alg.equalsIgnoreCase("DSA"))) {
330  0 cd.setAlgorithm(alg.toUpperCase());
331  0 valid = true;
332    } else {
333  0 System.out.println("\nWARNING: The supported algorithms are RSA and DSA. Please type one of these algorithms:");
334    }
335    }
336    }
337   
338  0 valid = false;
339  0 int[] keySizes = null;
340  0 alg = cd.getAlgorithm();
341   
342  0 if (alg.equalsIgnoreCase("RSA")) { // Algorithm = RSA
343  0 keySizes = new int[]{1024, 2048, 3072, 4096};
344    } else { // Algorithm = DSA
345  0 keySizes = new int[]{512, 640, 768, 896, 1024};
346    }
347  0 System.out.println("\nPlease input one of the following options for the key size:\n");
348   
349  0 Loop2:
350  0 while (!valid) {
351  0 for (int j = 0; j < keySizes.length; j = j + 1) {
352  0 System.out.println("\t[" + (j + 1) + "] " + keySizes[j]);
353    }
354  0 int choice = -1;
355  0 try {
356  0 choice = Integer.parseInt(systemIn.readLine());
357    } catch (Exception ex) {
358  0 System.err.println("\nWARNING: Invalid option. Please input a valid number for the option:\n");
359  0 continue Loop2;
360    }
361  0 if ((choice <= 0) || (choice > keySizes.length)) {
362  0 System.err.println("\nWARNING: Invalid option. Please input a valid option:\n");
363    } else {
364  0 cd.setKeySize(keySizes[choice - 1]);
365  0 valid = true;
366    }
367    }
368   
369    } catch (IOException ioe) {
370  0 System.err.println("ERROR: Fail to read key size from the command prompt.");
371  0 sawsDebugLog.write("ERROR: Fail to read key size from the command prompt.");
372    }
373   
374  0 return cd;
375    }
376   
377    /**
378    * Method for reading the password from the command line.
379    *
380    * @param in The input stream from where the password will be read.
381    * Usually 'System.in'.
382    *
383    * @return the password in a char array.
384    * @throws IOException If an error happens during the reading process.
385    */
 
386  0 toggle private char[] readPassword(InputStream in) throws IOException {
387  0 MaskingThread mt = new MaskingThread();
388  0 mt.start();
389  0 char[] lineBuffer;
390  0 char[] buf;
391   
392  0 buf = lineBuffer = new char[128];
393   
394  0 int room = buf.length;
395  0 int offset = 0;
396  0 int c;
397   
398  0 loop:
399    while (true) {
400  0 c = in.read();
401  0 switch (c) {
402  0 case -1:
403  0 case '\n':
404  0 break loop;
405  0 case '\r':
406  0 int c2 = in.read();
407  0 if ((c2 != '\n') && (c2 != -1)) {
408  0 if (!(in instanceof PushbackInputStream)) {
409  0 in = new PushbackInputStream(in);
410    }
411  0 ((PushbackInputStream)in).unread(c2);
412    } else
413  0 break loop;
414   
415  0 default:
416  0 if (--room < 0) {
417  0 buf = new char[offset + 128];
418  0 room = buf.length - offset - 1;
419  0 System.arraycopy(lineBuffer, 0, buf, 0, offset);
420  0 Arrays.fill(lineBuffer, ' ');
421  0 lineBuffer = buf;
422    }
423  0 buf[offset++] = (char) c;
424  0 break;
425    }
426    }
427  0 mt.stopMasking();
428   
429  0 if (offset == 0) {
430  0 return null;
431    }
432   
433  0 char[] ret = new char[offset];
434  0 System.arraycopy(buf, 0, ret, 0, offset);
435  0 Arrays.fill(buf, ' ');
436   
437  0 return ret;
438    }
439    }
440   
441   
442    /**
443    * Class that represents a thread to mask the password while the user types it.
444    */
 
445    class MaskingThread extends Thread {
446    private volatile boolean stop;
447    private char echochar = '*';
448   
449   
450    /**
451    * Contructor of the class MaskingThread.
452    */
 
453  0 toggle public MaskingThread() {
454  0 super("Masking");
455    }
456   
457    /**
458    * Begin masking until asked to stop.
459    */
 
460  0 toggle public void run() {
461   
462  0 int priority = Thread.currentThread().getPriority();
463  0 Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
464  0 try {
465  0 stop = true;
466  0 while(stop) {
467  0 System.out.print("\010" + echochar);
468  0 try {
469    // attempt masking at this rate
470  0 Thread.currentThread().sleep(1);
471    }catch (InterruptedException iex) {
472  0 Thread.currentThread().interrupt();
473  0 return;
474    }
475    }
476    } finally { // restore the original priority
477  0 Thread.currentThread().setPriority(priority);
478    }
479    }
480   
481    /**
482    * Instruct the thread to stop masking.
483    */
 
484  0 toggle public void stopMasking() {
485  0 this.stop = false;
486    }
487    }