KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > schlichtherle > key > passwd > swing > CreateKeyPanel


1 /*
2  * Copyright 2006 Schlichtherle IT Services
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package de.schlichtherle.key.passwd.swing;
18
19 import de.schlichtherle.swing.EnhancedPanel;
20
21 import java.awt.*;
22 import java.awt.event.*;
23 import java.io.*;
24 import java.util.*;
25 import java.util.zip.*;
26
27 import javax.swing.*;
28 import javax.swing.event.*;
29 import javax.swing.text.*;
30
31 /**
32  * This panel prompts the user for a key to create or overwrite a protected
33  * resource.
34  * It currently supports password and key file authentication, but is
35  * extensible for use with certificate based authentication, too.
36  *
37  * @author Christian Schlichtherle
38  * @since TrueZIP 6.0
39  * @version @version@
40  */

41 public class CreateKeyPanel extends EnhancedPanel {
42
43     private static final String JavaDoc CLASS_NAME
44             = "de/schlichtherle/key/passwd/swing/CreateKeyPanel".replace('/', '.'); // beware of code obfuscation!
45
private static final ResourceBundle resources
46             = ResourceBundle.getBundle(CLASS_NAME);
47
48     /** The minimum acceptable lenght of a password. */
49     private static final int MIN_PASSWD_LEN = 6;
50
51     private final Color defaultForeground;
52
53     private JComponent extraDataUI;
54
55     private Feedback feedback;
56
57     /**
58      * Creates new form CreateKeyPanel
59      */

60     public CreateKeyPanel() {
61         initComponents();
62         final DocumentListener dl = new DocumentListener() {
63             public void insertUpdate(DocumentEvent e) {
64                 setError(null);
65             }
66
67             public void removeUpdate(DocumentEvent e) {
68                 setError(null);
69             }
70
71             public void changedUpdate(DocumentEvent e) {
72                 setError(null);
73             }
74         };
75         newPasswd1.getDocument().addDocumentListener(dl);
76         newPasswd2.getDocument().addDocumentListener(dl);
77         authenticationPanel.getKeyFileDocument().addDocumentListener(dl);
78         defaultForeground = resourceID.getForeground();
79     }
80
81     private Font getBoldFont() {
82         Font font = resourceID.getFont();
83         return new Font(font.getName(), Font.BOLD, font.getSize());
84     }
85
86     /**
87      * Getter for property <code>resourceID</code>.
88      *
89      * @return Value of property <code>resourceID</code>.
90      */

91     public String JavaDoc getResourceID() {
92         return resourceID.getText();
93     }
94     
95     /**
96      * Setter for property <code>resourceID</code>.
97      *
98      * @param resourceID New value of property <code>resourceID</code>.
99      */

100     public void setResourceID(final String JavaDoc resourceID) {
101         final String JavaDoc lastResourceID = PromptingKeyProviderUI.lastResourceID;
102         if (!lastResourceID.equals(resourceID) && !"".equals(lastResourceID)) {
103             this.resourceID.setForeground(Color.RED);
104         } else {
105             this.resourceID.setForeground(defaultForeground);
106         }
107         this.resourceID.setText(resourceID);
108         PromptingKeyProviderUI.lastResourceID = resourceID;
109     }
110     
111     /**
112      * Getter for property <code>createKey</code>.
113      *
114      * @return Value of property <code>createKey</code>.
115      * This is <tt>null</tt> if the user hasn't entered two equal
116      * passwords or if the password is weak.
117      * May also be <code>null</code> if a key file is selected and
118      * accessing it results in an exception.
119      */

120     public Object JavaDoc getCreateKey() {
121         try {
122             switch (authenticationPanel.getAuthenticationMethod()) {
123                 case AuthenticationPanel.AUTH_PASSWD:
124                     final char[] newPasswd1Content = newPasswd1.getPassword();
125                     final char[] newPasswd2Content = newPasswd2.getPassword();
126                     if (Arrays.equals(newPasswd1Content, newPasswd2Content)) {
127                         Arrays.fill(newPasswd2Content, (char) 0);
128                         checkPasswdCreateKey(newPasswd1Content);
129                         setError(null);
130                         return newPasswd1Content;
131                     } else {
132                         setError(resources.getString("passwd.noMatch"));
133                         return null;
134                     }
135
136                 case AuthenticationPanel.AUTH_KEY_FILE:
137                     final String JavaDoc keyFilePathname
138                             = authenticationPanel.getKeyFilePath();
139                     if (new File(keyFilePathname).canWrite()) {
140                         setError(resources.getString("keyFile.canWrite"));
141                         return null;
142                     }
143
144                     final byte[] key;
145                     try {
146                         key = PromptingKeyProviderUI.readKeyFile(keyFilePathname);
147                     } catch (EOFException failure) {
148                         setError(resources.getString("keyFile.eofException"));
149                         return null;
150                     } catch (FileNotFoundException failure) {
151                         setError(resources.getString("keyFile.fileNotFoundException"));
152                         return null;
153                     } catch (IOException failure) {
154                         setError(resources.getString("keyFile.ioException"));
155                         return null;
156                     }
157                     checkKeyFileCreateKey(key);
158                     setError(null);
159                     return key;
160
161                 default:
162                     throw new AssertionError JavaDoc("Unsupported authentication method!");
163             }
164         } catch (WeakKeyException failure) {
165             setError(failure.getLocalizedMessage());
166             return null;
167         }
168     }
169
170     /**
171      * Clears the password fields and the error message (but doesn't touch
172      * the pathname in case a key file has been selected).
173      *
174      * @deprecated Create a new <code>CreateKeyPanel</code> instead.
175      */

176     public void resetCreateKey() {
177         resetPasswd();
178         setError(null);
179     }
180
181     /**
182      * Clears the password fields.
183      *
184      * @deprecated Create a new <code>CreateKeyPanel</code> instead.
185      */

186     public void resetPasswd() {
187         newPasswd1.setText(null);
188         newPasswd2.setText(null);
189     }
190
191     /** Check the data entropy in the new key. */
192     protected void checkKeyFileCreateKey(byte[] createKey)
193     throws WeakKeyException {
194         Deflater def = new Deflater();
195         def.setInput(createKey);
196         def.finish();
197         assert def.getTotalOut() == 0;
198         final int n = def.deflate(new byte[createKey.length * 2]);
199         assert def.getTotalOut() == n;
200         def.end();
201         if (n < 2 * 256 / 8) // see RandomAccessEncryptionSpecification
202
throw new WeakKeyException(resources, "keyFile.badEntropy");
203     }
204
205     protected void checkPasswdCreateKey(char[] createKey)
206     throws WeakKeyException {
207         if (createKey.length < MIN_PASSWD_LEN)
208             throw new WeakKeyException(resources, "passwd.tooShort", new Integer JavaDoc(MIN_PASSWD_LEN));
209     }
210
211     /**
212      * Getter for property <code>error</code>.
213      */

214     public String JavaDoc getError() {
215         final String JavaDoc error = this.error.getText();
216         return error.trim().length() > 0 ? error : null;
217     }
218     
219     /**
220      * Setter for property error.
221      *
222      * @param error New value of property error.
223      */

224     public void setError(final String JavaDoc error) {
225         // Fix layout issue with GridBagLayout:
226
// If null is set, the layout seems to ignore the widthy = 1.0
227
// constraint for the component.
228
this.error.setText(error != null ? error : " ");
229     }
230     
231     /**
232      * Getter for property <code>extraDataUI</code>.
233      *
234      * @return Value of property <code>extraDataUI</code>.
235      */

236     public JComponent getExtraDataUI() {
237         return extraDataUI;
238     }
239     
240     /**
241      * Setter for property <code>extraDataUI</code>.
242      * This component is placed below the two password fields and above the
243      * error label.
244      * It may be used to prompt the user for additional data which may form
245      * part of the key or is separately stored in the key provider.
246      * The panel is automatically revalidated.
247      *
248      * @param extraDataUI New value of property <code>extraDataUI</code>.
249      */

250     public void setExtraDataUI(final JComponent extraDataUI) {
251         if (this.extraDataUI == extraDataUI)
252             return;
253
254         if (this.extraDataUI != null) {
255             remove(this.extraDataUI);
256         }
257         if (extraDataUI != null) {
258             GridBagConstraints gridBagConstraints = new GridBagConstraints();
259             gridBagConstraints.gridx = 0;
260             gridBagConstraints.gridy = 3;
261             gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
262             gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
263             gridBagConstraints.insets = new Insets(15, 0, 0, 0);
264             add(extraDataUI, gridBagConstraints);
265         }
266         this.extraDataUI = extraDataUI;
267
268         revalidate();
269     }
270
271     /**
272      * Returns the feedback to run when this panel is shown in its ancestor
273      * window.
274      */

275     public Feedback getFeedback() {
276         return feedback;
277     }
278
279     /**
280      * Sets the feedback to run when this panel is shown in its ancestor
281      * window.
282      */

283     public void setFeedback(final Feedback feedback) {
284         this.feedback = feedback;
285     }
286     
287     /** This method is called from within the constructor to
288      * initialize the form.
289      * WARNING: Do NOT modify this code. The content of this method is
290      * always regenerated by the Form Editor.
291      */

292     // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
293
private void initComponents() {
294         java.awt.GridBagConstraints JavaDoc gridBagConstraints;
295
296         newPasswdPanel = new de.schlichtherle.swing.EnhancedPanel();
297         newPasswd1Label = new javax.swing.JLabel JavaDoc();
298         newPasswd1 = new javax.swing.JPasswordField JavaDoc();
299         newPasswd2Label = new javax.swing.JLabel JavaDoc();
300         newPasswd2 = new javax.swing.JPasswordField JavaDoc();
301         final javax.swing.JLabel JavaDoc prompt = new javax.swing.JLabel JavaDoc();
302         resourceID = new javax.swing.JTextPane JavaDoc();
303         authenticationPanel = new de.schlichtherle.key.passwd.swing.AuthenticationPanel();
304         error = new javax.swing.JLabel JavaDoc();
305
306         newPasswdPanel.setLayout(new java.awt.GridBagLayout JavaDoc());
307
308         newPasswdPanel.addPanelListener(new de.schlichtherle.swing.event.PanelListener() {
309             public void ancestorWindowShown(de.schlichtherle.swing.event.PanelEvent evt) {
310                 newPasswdPanelAncestorWindowShown(evt);
311             }
312             public void ancestorWindowHidden(de.schlichtherle.swing.event.PanelEvent evt) {
313             }
314         });
315
316         newPasswd1Label.setDisplayedMnemonic(resources.getString("newPasswd1").charAt(0));
317         newPasswd1Label.setLabelFor(newPasswd1);
318         newPasswd1Label.setText(resources.getString("newPasswd1")); // NOI18N
319
gridBagConstraints = new java.awt.GridBagConstraints JavaDoc();
320         gridBagConstraints.gridx = 0;
321         gridBagConstraints.gridy = 0;
322         gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
323         gridBagConstraints.insets = new java.awt.Insets JavaDoc(0, 0, 5, 5);
324         newPasswdPanel.add(newPasswd1Label, gridBagConstraints);
325
326         newPasswd1.setColumns(20);
327         gridBagConstraints = new java.awt.GridBagConstraints JavaDoc();
328         gridBagConstraints.gridx = 1;
329         gridBagConstraints.gridy = 0;
330         gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
331         gridBagConstraints.weightx = 1.0;
332         gridBagConstraints.insets = new java.awt.Insets JavaDoc(0, 0, 5, 0);
333         newPasswdPanel.add(newPasswd1, gridBagConstraints);
334
335         newPasswd2Label.setDisplayedMnemonic(resources.getString("newPasswd2").charAt(0));
336         newPasswd2Label.setLabelFor(newPasswd2);
337         newPasswd2Label.setText(resources.getString("newPasswd2")); // NOI18N
338
gridBagConstraints = new java.awt.GridBagConstraints JavaDoc();
339         gridBagConstraints.gridx = 0;
340         gridBagConstraints.gridy = 1;
341         gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
342         gridBagConstraints.insets = new java.awt.Insets JavaDoc(0, 0, 0, 5);
343         newPasswdPanel.add(newPasswd2Label, gridBagConstraints);
344
345         newPasswd2.setColumns(20);
346         gridBagConstraints = new java.awt.GridBagConstraints JavaDoc();
347         gridBagConstraints.gridx = 1;
348         gridBagConstraints.gridy = 1;
349         gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
350         gridBagConstraints.weightx = 1.0;
351         newPasswdPanel.add(newPasswd2, gridBagConstraints);
352
353         setLayout(new java.awt.GridBagLayout JavaDoc());
354
355         addPanelListener(new de.schlichtherle.swing.event.PanelListener() {
356             public void ancestorWindowShown(de.schlichtherle.swing.event.PanelEvent evt) {
357                 formAncestorWindowShown(evt);
358             }
359             public void ancestorWindowHidden(de.schlichtherle.swing.event.PanelEvent evt) {
360             }
361         });
362
363         prompt.setLabelFor(resourceID);
364         prompt.setText(resources.getString("prompt")); // NOI18N
365
gridBagConstraints = new java.awt.GridBagConstraints JavaDoc();
366         gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
367         gridBagConstraints.insets = new java.awt.Insets JavaDoc(0, 0, 5, 0);
368         add(prompt, gridBagConstraints);
369
370         resourceID.setBorder(javax.swing.BorderFactory.createCompoundBorder(javax.swing.BorderFactory.createEtchedBorder(), javax.swing.BorderFactory.createEmptyBorder(2, 2, 2, 2)));
371         resourceID.setEditable(false);
372         resourceID.setFont(getBoldFont());
373         resourceID.setOpaque(false);
374         gridBagConstraints = new java.awt.GridBagConstraints JavaDoc();
375         gridBagConstraints.gridx = 0;
376         gridBagConstraints.gridy = 1;
377         gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
378         gridBagConstraints.weightx = 1.0;
379         gridBagConstraints.insets = new java.awt.Insets JavaDoc(0, 0, 15, 0);
380         add(resourceID, gridBagConstraints);
381
382         authenticationPanel.setPasswdPanel(newPasswdPanel);
383         gridBagConstraints = new java.awt.GridBagConstraints JavaDoc();
384         gridBagConstraints.gridx = 0;
385         gridBagConstraints.gridy = 2;
386         gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
387         add(authenticationPanel, gridBagConstraints);
388
389         error.setForeground(new java.awt.Color JavaDoc(255, 0, 0));
390         error.setText(" ");
391         error.setName("error");
392         gridBagConstraints = new java.awt.GridBagConstraints JavaDoc();
393         gridBagConstraints.gridx = 0;
394         gridBagConstraints.gridy = 4;
395         gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
396         gridBagConstraints.weighty = 1.0;
397         gridBagConstraints.insets = new java.awt.Insets JavaDoc(15, 0, 0, 0);
398         add(error, gridBagConstraints);
399
400     }// </editor-fold>//GEN-END:initComponents
401

402     private void formAncestorWindowShown(de.schlichtherle.swing.event.PanelEvent evt) {//GEN-FIRST:event_formAncestorWindowShown
403
final Feedback feedback = getFeedback();
404         if (feedback != null) {
405             feedback.setPanel(this);
406             feedback.run();
407         }
408     }//GEN-LAST:event_formAncestorWindowShown
409

410     private void newPasswdPanelAncestorWindowShown(de.schlichtherle.swing.event.PanelEvent evt) {//GEN-FIRST:event_newPasswdPanelAncestorWindowShown
411
// These are the things I hate Swing for: All I want to do here is to
412
// set the focus to the newPasswd1 field in this panel when it shows.
413
// However, this can't be done in the constructor since the panel is
414
// not yet placed in a window which is actually showing.
415
// Right, then we use this event listener to do it. This listener
416
// method is called when the ancestor window is showing (and coding
417
// the event generation was a less than trivial task).
418
// But wait, simply setting the focus in this event listener here is
419
// not possible on Linux because the containing window (now we have
420
// one) didn't gain the focus yet.
421
// Strangely enough, this works on Windows.
422
// Even more strange, not even calling passwd.requestFocus() makes it
423
// work on Linux!
424
// So we add a window focus listener here and remove it when we
425
// receive a Focus Gained Event.
426
// But wait, then we still can't request the focus: This time it
427
// doesn't work on Windows, while it works on Linux.
428
// I still don't know the reason why, but it seems we're moving too
429
// fast, so I have to post a new event to the event queue which finally
430
// sets the focus.
431
// But wait, requesting the focus could still fail for some strange,
432
// undocumented reason - I wouldn't be surprised anymore.
433
// So we add a conditional to select the entire contents of the field
434
// only if we can really transfer the focus to it.
435
// Otherwise, users could get easily confused.
436
// If you carefully read the documentation for requestFocusInWindow()
437
// however, then you know that even if it returns true, there is still
438
// no guarantee that the focus gets actually transferred...
439
// This mess is insane (and I can hardly abstain from writing down
440
// all the other insulting scatology which comes to my mind)!
441
final Window window = evt.getAncestorWindow();
442         window.addWindowFocusListener(new WindowFocusListener() {
443             public void windowGainedFocus(WindowEvent e) {
444                 window.removeWindowFocusListener(this);
445                 EventQueue.invokeLater(new Runnable JavaDoc() {
446                     public void run() {
447                         if (newPasswd1.requestFocusInWindow()) {
448                             newPasswd1.selectAll();
449                             newPasswd2.selectAll();
450                         }
451                     }
452                 });
453             }
454
455             public void windowLostFocus(WindowEvent e) {
456             }
457         });
458     }//GEN-LAST:event_newPasswdPanelAncestorWindowShown
459

460     // Variables declaration - do not modify//GEN-BEGIN:variables
461
private de.schlichtherle.key.passwd.swing.AuthenticationPanel authenticationPanel;
462     private javax.swing.JLabel JavaDoc error;
463     private javax.swing.JPasswordField JavaDoc newPasswd1;
464     private javax.swing.JLabel JavaDoc newPasswd1Label;
465     private javax.swing.JPasswordField JavaDoc newPasswd2;
466     private javax.swing.JLabel JavaDoc newPasswd2Label;
467     private de.schlichtherle.swing.EnhancedPanel newPasswdPanel;
468     private javax.swing.JTextPane JavaDoc resourceID;
469     // End of variables declaration//GEN-END:variables
470
}
471
Popular Tags