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 @jdk.Supported
  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      */
  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      */
  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 {
  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 
 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 */
 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 */
 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 }