001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2004 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or 1any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * Initial developer: Jeremie Laurent, Yann Petiot, Frederic Rinaldi
022: * --------------------------------------------------------------------------
023: * $Id: DialogCallbackHandler.java 5895 2004-12-10 08:54:21Z benoitf $
024: * --------------------------------------------------------------------------
025: */package org.objectweb.jonas.security.auth.callback;
026:
027: import java.awt.GridLayout;
028: import java.io.IOException;
029:
030: import javax.security.auth.callback.Callback;
031: import javax.security.auth.callback.CallbackHandler;
032: import javax.security.auth.callback.NameCallback;
033: import javax.security.auth.callback.PasswordCallback;
034: import javax.security.auth.callback.UnsupportedCallbackException;
035: import javax.swing.BoxLayout;
036: import javax.swing.JLabel;
037: import javax.swing.JOptionPane;
038: import javax.swing.JPanel;
039: import javax.swing.JPasswordField;
040: import javax.swing.JTextField;
041:
042: /**
043: * Uses a Swing dialog window to query the user for answers to authentication
044: * questions. This can be used by a JAAS application to instantiate a
045: * CallbackHandler
046: * @author Jeremie Laurent, Yann Petiot, Frederic Rinaldi
047: * @author Florent Benoit. Integration in the JOnAS 3.1.2 tree
048: */
049: public class DialogCallbackHandler implements CallbackHandler {
050:
051: /**
052: * The text field where the user will put its login.
053: */
054: private JTextField loginField = null;
055:
056: /**
057: * The password field where the user will put its password.
058: */
059: private JTextField passwordField = null;
060:
061: /**
062: * If the button cancel is clicked, the user won't be prompted no more.
063: */
064: private boolean cancelled = false;
065:
066: /**
067: * The title of the dialog box
068: */
069: private String title = "Login Dialog";
070:
071: /**
072: * The label for the username label
073: */
074: private String username = "Username ";
075:
076: /**
077: * The label for the password label
078: */
079: private String password = "Password ";
080:
081: /**
082: * The label for the login button
083: */
084: private String loginButton = "Login !";
085:
086: /**
087: * The label for the cancel button
088: */
089: private String cancelButton = "Cancel";
090:
091: /**
092: * Maximum length for fields
093: */
094: private static final int MAX_FIELD_LENGTH = 20;
095:
096: /**
097: * the length of the password textfield
098: */
099: private int passwordLength = MAX_FIELD_LENGTH;
100:
101: /**
102: * the length for the username textfield
103: */
104: private int usernameLength = MAX_FIELD_LENGTH;
105:
106: /**
107: * the character which will be displayed in the password textfield if
108: * echoCharOn is true
109: */
110: private char echoChar = '*';
111:
112: /**
113: * whether the echo is on or not : display the echoChar in the password
114: * textfield
115: */
116: private boolean echoCharOn = false;
117:
118: /**
119: * an array of String where are described the label of the buttons
120: */
121: private String[] connectOptionNames;
122:
123: /**
124: * The constructor to create a callback dialog with the default parent
125: * window.
126: */
127: public DialogCallbackHandler() {
128: int i = 0;
129: connectOptionNames = new String[2];
130: connectOptionNames[i] = loginButton;
131: connectOptionNames[++i] = cancelButton;
132: }
133:
134: /**
135: * The constructor to create a callback dialog with the default parent
136: * window
137: * @param title the title of the dialog box
138: */
139: public DialogCallbackHandler(String title) {
140: this ();
141: this .title = title;
142: }
143:
144: /**
145: * The constructor to create a callback dialog with the default parent
146: * window
147: * @param title the title of the dialog box
148: * @param username the label of the username label
149: * @param password the label of the password label
150: */
151: public DialogCallbackHandler(String title, String username,
152: String password) {
153: this ();
154: this .title = title;
155: this .username = username;
156: this .password = password;
157: }
158:
159: /**
160: * The constructor to create a callback dialog with the default parent
161: * window
162: * @param title the title of the dialog box
163: * @param username the label of the username label
164: * @param password the label of the password label
165: * @param loginButton the label of the login button
166: * @param cancelButton the label of the cancel button
167: * @param usernameLength the length of the username field
168: * @param passwordLength the length of the password field
169: * @param echoChar the character to display when entering the password
170: * implies that echoCharOn = true
171: */
172: public DialogCallbackHandler(String title, String username,
173: String password, String loginButton, String cancelButton,
174: int usernameLength, int passwordLength, char echoChar) {
175: this (title, username, password);
176: this .echoCharOn = true;
177: this .echoChar = echoChar;
178: this .loginButton = loginButton;
179: this .cancelButton = cancelButton;
180: this .passwordLength = passwordLength;
181: this .usernameLength = usernameLength;
182: this .echoChar = echoChar;
183: }
184:
185: /**
186: * /** This method allows to create a new instance of JDialog initialised
187: * with the parameters.
188: * @param isEchoOn the value of passwordCallback.isEchoOn() called in handle
189: */
190: private void dialogInit(boolean isEchoOn) {
191:
192: // to determine whether the echo char must be displayed or not
193: // we use a "OR" between the isEchoOn=passwordCallback.isEchoOn() and
194: // the echoCharOn=the value of the variable echoCharOn set in the
195: // OptionPaneCallbackHandler constructor.
196: echoCharOn = (isEchoOn || echoCharOn);
197: dialogInit();
198: }
199:
200: /**
201: * This method allows to create a new instance of JDialog initialised with
202: * the parameters.
203: */
204: private void dialogInit() {
205:
206: // for the login
207: JLabel userNameLabel = new JLabel(username, JLabel.RIGHT);
208: loginField = new JTextField("");
209:
210: // for the password
211: JLabel passwordLabel = new JLabel(password, JLabel.RIGHT);
212:
213: // because of the bug of Java (in SDK 1.3) it isn't possible to display
214: // password without an echo character in a password field, we have to
215: // create a JTextField or a JPasswordField depending on echoCharOn.
216: if (!echoCharOn) { // password needs to be hidden
217: passwordField = new JPasswordField(passwordLength);
218: ((JPasswordField) passwordField).setEchoChar(echoChar);
219: } else {
220: passwordField = new JTextField(passwordLength);
221: }
222:
223: // creation of a JPanel to put the other panels on
224: JPanel connectionPanel = new JPanel(false);
225: connectionPanel.setLayout(new BoxLayout(connectionPanel,
226: BoxLayout.X_AXIS));
227:
228: // to this panel we add the labels
229: JPanel namePanel = new JPanel(false);
230: namePanel.setLayout(new GridLayout(0, 1));
231: namePanel.add(userNameLabel);
232: namePanel.add(passwordLabel);
233:
234: // to this panel we add the fields
235: JPanel fieldPanel = new JPanel(false);
236: fieldPanel.setLayout(new GridLayout(0, 1));
237: fieldPanel.add(loginField);
238: fieldPanel.add(passwordField);
239:
240: // we add the 2 panels created in the first one
241: connectionPanel.add(namePanel);
242: connectionPanel.add(fieldPanel);
243:
244: // Connect or quit
245: //System.out.println("Displaying dialog...");
246: int choice = JOptionPane.showOptionDialog(null, // the default frame
247: connectionPanel, // the object to display
248: title, // the title string
249: JOptionPane.OK_CANCEL_OPTION, // the options available
250: JOptionPane.INFORMATION_MESSAGE, // the kind of message
251: null, // the icon to display
252: connectOptionNames, // the possible choices
253: loginField); // the default selection
254:
255: if (choice == JOptionPane.OK_OPTION) {
256: cancelled = false;
257: } else if (choice == JOptionPane.CANCEL_OPTION) {
258: // why is this value never got ?
259: // JOptionPane.CANCEL_OPTION=2 but choice=1
260: cancelled = true;
261: } else if (choice == JOptionPane.CLOSED_OPTION) {
262: cancelled = true;
263: } else {
264: cancelled = true; // another bug of Java
265: }
266:
267: if (cancelled) {
268: loginField.setText("Invalid");
269: passwordField.setText("Invalid");
270: }
271: }
272:
273: /**
274: * Invoke an array of Callbacks. <p>
275: * @param callbacks an array of <code>Callback</code> objects which
276: * contain the information requested by an underlying security
277: * service to be retrieved or displayed.
278: * @exception java.io.IOException if an input or output error occurs. <p>
279: * @exception UnsupportedCallbackException if the implementation of this
280: * method does not support one or more of the Callbacks specified
281: * in the <code>callbacks</code> parameter.
282: */
283: public void handle(Callback[] callbacks) throws IOException,
284: UnsupportedCallbackException {
285:
286: // if the user clicked on the cancel button the the system won't
287: // prompt him its informations
288: if (cancelled) {
289: return;
290: }
291:
292: // recreate a new JDialog with the property to display or not
293: // the password echo
294: int i = 0;
295: boolean found = false;
296: while ((i < callbacks.length) && !found) {
297: if (callbacks[i] instanceof PasswordCallback) {
298: found = true;
299: dialogInit(((PasswordCallback) callbacks[i]).isEchoOn());
300: }
301: // maybe we'll have to create a ObjectCallback object see later.
302: i++;
303: }
304: // if there's no instance of PasswordCallback in the parameter
305: // callbacks then there's a problem here !
306: // TO DO : a new dialogInit to integrate an ObjectCallback for example
307: // (for pki...)
308: // while waiting...
309: if (!found) {
310: dialogInit();
311: }
312:
313: // get the informations of the user
314: for (i = 0; i < callbacks.length; i++) {
315:
316: if (callbacks[i] instanceof NameCallback) {
317: ((NameCallback) callbacks[i]).setName(loginField
318: .getText());
319: } else if (callbacks[i] instanceof PasswordCallback) {
320: ((PasswordCallback) callbacks[i])
321: .setPassword((passwordField.getText())
322: .toCharArray());
323: } else {
324: throw new UnsupportedCallbackException(callbacks[i],
325: "Unrecognized Callback");
326: }
327: }
328: }
329: }
|