1 /* 2 * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.security.auth.callback; 27 28 /* JAAS imports */ 29 import javax.security.auth.callback.Callback; 30 import javax.security.auth.callback.CallbackHandler; 31 import javax.security.auth.callback.ConfirmationCallback; 32 import javax.security.auth.callback.NameCallback; 33 import javax.security.auth.callback.PasswordCallback; 34 import javax.security.auth.callback.TextOutputCallback; 35 import javax.security.auth.callback.UnsupportedCallbackException; 36 37 /* Java imports */ 38 import java.awt.Component; 39 import java.util.ArrayList; 40 import java.util.Iterator; 41 import java.util.List; 42 import javax.swing.Box; 43 import javax.swing.JLabel; 44 import javax.swing.JOptionPane; 45 import javax.swing.JPasswordField; 46 import javax.swing.JTextField; 47 48 /** 49 * <p> 50 * Uses a Swing dialog window to query the user for answers to 51 * authentication questions. 52 * This can be used by a JAAS application to instantiate a 53 * CallbackHandler 54 * @see javax.security.auth.callback 55 * @deprecated This class will be removed in a future release. 56 */ 57 @Deprecated 58 public class DialogCallbackHandler implements CallbackHandler { 59 60 /* -- Fields -- */ 61 62 /* The parent window, or null if using the default parent */ 63 private Component parentComponent; 64 private static final int JPasswordFieldLen = 8 ; 65 private static final int JTextFieldLen = 8 ; 66 67 /* -- Methods -- */ 68 69 /** 70 * Creates a callback dialog with the default parent window. 71 */ 72 public DialogCallbackHandler() { } 73 74 /** 75 * Creates a callback dialog and specify the parent window. 76 * 77 * @param parentComponent the parent window -- specify <code>null</code> 78 * for the default parent 79 */ 80 public DialogCallbackHandler(Component parentComponent) { 81 this.parentComponent = parentComponent; 82 } 83 84 /* 85 * An interface for recording actions to carry out if the user 86 * clicks OK for the dialog. 87 */ 88 private static interface Action { 89 void perform(); 90 } 91 92 /** 93 * Handles the specified set of callbacks. 94 * 95 * @param callbacks the callbacks to handle 96 * @throws UnsupportedCallbackException if the callback is not an 97 * instance of NameCallback or PasswordCallback 98 */ 99 100 public void handle(Callback[] callbacks) 101 throws UnsupportedCallbackException 102 { 103 /* Collect messages to display in the dialog */ 104 final List<Object> messages = new ArrayList<>(3); 105 106 /* Collection actions to perform if the user clicks OK */ 107 final List<Action> okActions = new ArrayList<>(2); 108 109 ConfirmationInfo confirmation = new ConfirmationInfo(); 110 111 for (int i = 0; i < callbacks.length; i++) { 112 if (callbacks[i] instanceof TextOutputCallback) { 113 TextOutputCallback tc = (TextOutputCallback) callbacks[i]; 114 115 switch (tc.getMessageType()) { 116 case TextOutputCallback.INFORMATION: 117 confirmation.messageType = JOptionPane.INFORMATION_MESSAGE; 118 break; 119 case TextOutputCallback.WARNING: 120 confirmation.messageType = JOptionPane.WARNING_MESSAGE; 121 break; 122 case TextOutputCallback.ERROR: 123 confirmation.messageType = JOptionPane.ERROR_MESSAGE; 124 break; 125 default: 126 throw new UnsupportedCallbackException( 127 callbacks[i], "Unrecognized message type"); 128 } 129 130 messages.add(tc.getMessage()); 131 132 } else if (callbacks[i] instanceof NameCallback) { 133 final NameCallback nc = (NameCallback) callbacks[i]; 134 135 JLabel prompt = new JLabel(nc.getPrompt()); 136 137 final JTextField name = new JTextField(JTextFieldLen); 138 String defaultName = nc.getDefaultName(); 139 if (defaultName != null) { 140 name.setText(defaultName); 141 } 142 143 /* 144 * Put the prompt and name in a horizontal box, 145 * and add that to the set of messages. 146 */ 147 Box namePanel = Box.createHorizontalBox(); 148 namePanel.add(prompt); 149 namePanel.add(name); 150 messages.add(namePanel); 151 152 /* Store the name back into the callback if OK */ 153 okActions.add(new Action() { 154 public void perform() { 155 nc.setName(name.getText()); 156 } 157 }); 158 159 } else if (callbacks[i] instanceof PasswordCallback) { 160 final PasswordCallback pc = (PasswordCallback) callbacks[i]; 161 162 JLabel prompt = new JLabel(pc.getPrompt()); 163 164 final JPasswordField password = 165 new JPasswordField(JPasswordFieldLen); 166 if (!pc.isEchoOn()) { 167 password.setEchoChar('*'); 168 } 169 170 Box passwordPanel = Box.createHorizontalBox(); 171 passwordPanel.add(prompt); 172 passwordPanel.add(password); 173 messages.add(passwordPanel); 174 175 okActions.add(new Action() { 176 public void perform() { 177 pc.setPassword(password.getPassword()); 178 } 179 }); 180 181 } else if (callbacks[i] instanceof ConfirmationCallback) { 182 ConfirmationCallback cc = (ConfirmationCallback)callbacks[i]; 183 184 confirmation.setCallback(cc); 185 if (cc.getPrompt() != null) { 186 messages.add(cc.getPrompt()); 187 } 188 189 } else { 190 throw new UnsupportedCallbackException( 191 callbacks[i], "Unrecognized Callback"); 192 } 193 } 194 195 /* Display the dialog */ 196 int result = JOptionPane.showOptionDialog( 197 parentComponent, 198 messages.toArray(), 199 "Confirmation", /* title */ 200 confirmation.optionType, 201 confirmation.messageType, 202 null, /* icon */ 203 confirmation.options, /* options */ 204 confirmation.initialValue); /* initialValue */ 205 206 /* Perform the OK actions */ 207 if (result == JOptionPane.OK_OPTION 208 || result == JOptionPane.YES_OPTION) 209 { 210 Iterator<Action> iterator = okActions.iterator(); 211 while (iterator.hasNext()) { 212 iterator.next().perform(); 213 } 214 } 215 confirmation.handleResult(result); 216 } 217 218 /* 219 * Provides assistance with translating between JAAS and Swing 220 * confirmation dialogs. 221 */ 222 private static class ConfirmationInfo { 223 224 private int[] translations; 225 226 int optionType = JOptionPane.OK_CANCEL_OPTION; 227 Object[] options = null; 228 Object initialValue = null; 229 230 int messageType = JOptionPane.QUESTION_MESSAGE; 231 232 private ConfirmationCallback callback; 233 234 /* Set the confirmation callback handler */ 235 void setCallback(ConfirmationCallback callback) 236 throws UnsupportedCallbackException 237 { 238 this.callback = callback; 239 240 int confirmationOptionType = callback.getOptionType(); 241 switch (confirmationOptionType) { 242 case ConfirmationCallback.YES_NO_OPTION: 243 optionType = JOptionPane.YES_NO_OPTION; 244 translations = new int[] { 245 JOptionPane.YES_OPTION, ConfirmationCallback.YES, 246 JOptionPane.NO_OPTION, ConfirmationCallback.NO, 247 JOptionPane.CLOSED_OPTION, ConfirmationCallback.NO 248 }; 249 break; 250 case ConfirmationCallback.YES_NO_CANCEL_OPTION: 251 optionType = JOptionPane.YES_NO_CANCEL_OPTION; 252 translations = new int[] { 253 JOptionPane.YES_OPTION, ConfirmationCallback.YES, 254 JOptionPane.NO_OPTION, ConfirmationCallback.NO, 255 JOptionPane.CANCEL_OPTION, ConfirmationCallback.CANCEL, 256 JOptionPane.CLOSED_OPTION, ConfirmationCallback.CANCEL 257 }; 258 break; 259 case ConfirmationCallback.OK_CANCEL_OPTION: 260 optionType = JOptionPane.OK_CANCEL_OPTION; 261 translations = new int[] { 262 JOptionPane.OK_OPTION, ConfirmationCallback.OK, 263 JOptionPane.CANCEL_OPTION, ConfirmationCallback.CANCEL, 264 JOptionPane.CLOSED_OPTION, ConfirmationCallback.CANCEL 265 }; 266 break; 267 case ConfirmationCallback.UNSPECIFIED_OPTION: 268 options = callback.getOptions(); 269 /* 270 * There's no way to know if the default option means 271 * to cancel the login, but there isn't a better way 272 * to guess this. 273 */ 274 translations = new int[] { 275 JOptionPane.CLOSED_OPTION, callback.getDefaultOption() 276 }; 277 break; 278 default: 279 throw new UnsupportedCallbackException( 280 callback, 281 "Unrecognized option type: " + confirmationOptionType); 282 } 283 284 int confirmationMessageType = callback.getMessageType(); 285 switch (confirmationMessageType) { 286 case ConfirmationCallback.WARNING: 287 messageType = JOptionPane.WARNING_MESSAGE; 288 break; 289 case ConfirmationCallback.ERROR: 290 messageType = JOptionPane.ERROR_MESSAGE; 291 break; 292 case ConfirmationCallback.INFORMATION: 293 messageType = JOptionPane.INFORMATION_MESSAGE; 294 break; 295 default: 296 throw new UnsupportedCallbackException( 297 callback, 298 "Unrecognized message type: " + confirmationMessageType); 299 } 300 } 301 302 303 /* Process the result returned by the Swing dialog */ 304 void handleResult(int result) { 305 if (callback == null) { 306 return; 307 } 308 309 for (int i = 0; i < translations.length; i += 2) { 310 if (translations[i] == result) { 311 result = translations[i + 1]; 312 break; 313 } 314 } 315 callback.setSelectedIndex(result); 316 } 317 } 318 }