1 /* 2 * Copyright (c) 2000, 2013, 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 @jdk.Exported(false) 58 @Deprecated 59 public class DialogCallbackHandler implements CallbackHandler { 60 61 /* -- Fields -- */ 62 63 /* The parent window, or null if using the default parent */ 64 private Component parentComponent; 65 private static final int JPasswordFieldLen = 8 ; 66 private static final int JTextFieldLen = 8 ; 67 68 /* -- Methods -- */ 69 70 /** 71 * Creates a callback dialog with the default parent window. 72 */ DialogCallbackHandler()73 public DialogCallbackHandler() { } 74 75 /** 76 * Creates a callback dialog and specify the parent window. 77 * 78 * @param parentComponent the parent window -- specify <code>null</code> 79 * for the default parent 80 */ DialogCallbackHandler(Component parentComponent)81 public DialogCallbackHandler(Component parentComponent) { 82 this.parentComponent = parentComponent; 83 } 84 85 /* 86 * An interface for recording actions to carry out if the user 87 * clicks OK for the dialog. 88 */ 89 private static interface Action { perform()90 void perform(); 91 } 92 93 /** 94 * Handles the specified set of callbacks. 95 * 96 * @param callbacks the callbacks to handle 97 * @throws UnsupportedCallbackException if the callback is not an 98 * instance of NameCallback or PasswordCallback 99 */ 100 handle(Callback[] callbacks)101 public void handle(Callback[] callbacks) 102 throws UnsupportedCallbackException 103 { 104 /* Collect messages to display in the dialog */ 105 final List<Object> messages = new ArrayList<>(3); 106 107 /* Collection actions to perform if the user clicks OK */ 108 final List<Action> okActions = new ArrayList<>(2); 109 110 ConfirmationInfo confirmation = new ConfirmationInfo(); 111 112 for (int i = 0; i < callbacks.length; i++) { 113 if (callbacks[i] instanceof TextOutputCallback) { 114 TextOutputCallback tc = (TextOutputCallback) callbacks[i]; 115 116 switch (tc.getMessageType()) { 117 case TextOutputCallback.INFORMATION: 118 confirmation.messageType = JOptionPane.INFORMATION_MESSAGE; 119 break; 120 case TextOutputCallback.WARNING: 121 confirmation.messageType = JOptionPane.WARNING_MESSAGE; 122 break; 123 case TextOutputCallback.ERROR: 124 confirmation.messageType = JOptionPane.ERROR_MESSAGE; 125 break; 126 default: 127 throw new UnsupportedCallbackException( 128 callbacks[i], "Unrecognized message type"); 129 } 130 131 messages.add(tc.getMessage()); 132 133 } else if (callbacks[i] instanceof NameCallback) { 134 final NameCallback nc = (NameCallback) callbacks[i]; 135 136 JLabel prompt = new JLabel(nc.getPrompt()); 137 138 final JTextField name = new JTextField(JTextFieldLen); 139 String defaultName = nc.getDefaultName(); 140 if (defaultName != null) { 141 name.setText(defaultName); 142 } 143 144 /* 145 * Put the prompt and name in a horizontal box, 146 * and add that to the set of messages. 147 */ 148 Box namePanel = Box.createHorizontalBox(); 149 namePanel.add(prompt); 150 namePanel.add(name); 151 messages.add(namePanel); 152 153 /* Store the name back into the callback if OK */ 154 okActions.add(new Action() { 155 public void perform() { 156 nc.setName(name.getText()); 157 } 158 }); 159 160 } else if (callbacks[i] instanceof PasswordCallback) { 161 final PasswordCallback pc = (PasswordCallback) callbacks[i]; 162 163 JLabel prompt = new JLabel(pc.getPrompt()); 164 165 final JPasswordField password = 166 new JPasswordField(JPasswordFieldLen); 167 if (!pc.isEchoOn()) { 168 password.setEchoChar('*'); 169 } 170 171 Box passwordPanel = Box.createHorizontalBox(); 172 passwordPanel.add(prompt); 173 passwordPanel.add(password); 174 messages.add(passwordPanel); 175 176 okActions.add(new Action() { 177 public void perform() { 178 pc.setPassword(password.getPassword()); 179 } 180 }); 181 182 } else if (callbacks[i] instanceof ConfirmationCallback) { 183 ConfirmationCallback cc = (ConfirmationCallback)callbacks[i]; 184 185 confirmation.setCallback(cc); 186 if (cc.getPrompt() != null) { 187 messages.add(cc.getPrompt()); 188 } 189 190 } else { 191 throw new UnsupportedCallbackException( 192 callbacks[i], "Unrecognized Callback"); 193 } 194 } 195 196 /* Display the dialog */ 197 int result = JOptionPane.showOptionDialog( 198 parentComponent, 199 messages.toArray(), 200 "Confirmation", /* title */ 201 confirmation.optionType, 202 confirmation.messageType, 203 null, /* icon */ 204 confirmation.options, /* options */ 205 confirmation.initialValue); /* initialValue */ 206 207 /* Perform the OK actions */ 208 if (result == JOptionPane.OK_OPTION 209 || result == JOptionPane.YES_OPTION) 210 { 211 Iterator<Action> iterator = okActions.iterator(); 212 while (iterator.hasNext()) { 213 iterator.next().perform(); 214 } 215 } 216 confirmation.handleResult(result); 217 } 218 219 /* 220 * Provides assistance with translating between JAAS and Swing 221 * confirmation dialogs. 222 */ 223 private static class ConfirmationInfo { 224 225 private int[] translations; 226 227 int optionType = JOptionPane.OK_CANCEL_OPTION; 228 Object[] options = null; 229 Object initialValue = null; 230 231 int messageType = JOptionPane.QUESTION_MESSAGE; 232 233 private ConfirmationCallback callback; 234 235 /* Set the confirmation callback handler */ setCallback(ConfirmationCallback callback)236 void setCallback(ConfirmationCallback callback) 237 throws UnsupportedCallbackException 238 { 239 this.callback = callback; 240 241 int confirmationOptionType = callback.getOptionType(); 242 switch (confirmationOptionType) { 243 case ConfirmationCallback.YES_NO_OPTION: 244 optionType = JOptionPane.YES_NO_OPTION; 245 translations = new int[] { 246 JOptionPane.YES_OPTION, ConfirmationCallback.YES, 247 JOptionPane.NO_OPTION, ConfirmationCallback.NO, 248 JOptionPane.CLOSED_OPTION, ConfirmationCallback.NO 249 }; 250 break; 251 case ConfirmationCallback.YES_NO_CANCEL_OPTION: 252 optionType = JOptionPane.YES_NO_CANCEL_OPTION; 253 translations = new int[] { 254 JOptionPane.YES_OPTION, ConfirmationCallback.YES, 255 JOptionPane.NO_OPTION, ConfirmationCallback.NO, 256 JOptionPane.CANCEL_OPTION, ConfirmationCallback.CANCEL, 257 JOptionPane.CLOSED_OPTION, ConfirmationCallback.CANCEL 258 }; 259 break; 260 case ConfirmationCallback.OK_CANCEL_OPTION: 261 optionType = JOptionPane.OK_CANCEL_OPTION; 262 translations = new int[] { 263 JOptionPane.OK_OPTION, ConfirmationCallback.OK, 264 JOptionPane.CANCEL_OPTION, ConfirmationCallback.CANCEL, 265 JOptionPane.CLOSED_OPTION, ConfirmationCallback.CANCEL 266 }; 267 break; 268 case ConfirmationCallback.UNSPECIFIED_OPTION: 269 options = callback.getOptions(); 270 /* 271 * There's no way to know if the default option means 272 * to cancel the login, but there isn't a better way 273 * to guess this. 274 */ 275 translations = new int[] { 276 JOptionPane.CLOSED_OPTION, callback.getDefaultOption() 277 }; 278 break; 279 default: 280 throw new UnsupportedCallbackException( 281 callback, 282 "Unrecognized option type: " + confirmationOptionType); 283 } 284 285 int confirmationMessageType = callback.getMessageType(); 286 switch (confirmationMessageType) { 287 case ConfirmationCallback.WARNING: 288 messageType = JOptionPane.WARNING_MESSAGE; 289 break; 290 case ConfirmationCallback.ERROR: 291 messageType = JOptionPane.ERROR_MESSAGE; 292 break; 293 case ConfirmationCallback.INFORMATION: 294 messageType = JOptionPane.INFORMATION_MESSAGE; 295 break; 296 default: 297 throw new UnsupportedCallbackException( 298 callback, 299 "Unrecognized message type: " + confirmationMessageType); 300 } 301 } 302 303 304 /* Process the result returned by the Swing dialog */ handleResult(int result)305 void handleResult(int result) { 306 if (callback == null) { 307 return; 308 } 309 310 for (int i = 0; i < translations.length; i += 2) { 311 if (translations[i] == result) { 312 result = translations[i + 1]; 313 break; 314 } 315 } 316 callback.setSelectedIndex(result); 317 } 318 } 319 } 320