001/*
002 * Copyright (c) 2007-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2015-08-24 22:46:34 +0000 (Mon, 24 Aug 2015) $' 
007 * '$Revision: 33632 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.gui;
031
032import java.awt.event.ActionEvent;
033
034import javax.swing.Action;
035import javax.swing.ImageIcon;
036import javax.swing.KeyStroke;
037import javax.swing.SwingWorker;
038
039import org.apache.commons.logging.Log;
040import org.apache.commons.logging.LogFactory;
041import org.kepler.authentication.AuthenticationException;
042import org.kepler.authentication.AuthenticationListener;
043import org.kepler.authentication.AuthenticationManager;
044import org.kepler.authentication.ProxyEntity;
045import org.kepler.authentication.gui.DomainSelectionGUI;
046import org.kepler.util.StaticResources;
047
048import diva.gui.GUIUtilities;
049import ptolemy.actor.gui.TableauFrame;
050import ptolemy.util.MessageHandler;
051import ptolemy.vergil.toolbox.FigureAction;
052
053/**
054 * This action displays the dialog to login using the
055 * <code>AuthenticationManager</code> First the user is prompted for the
056 * appropriate domain name to use for authentication. Then the
057 * AuthenticationManager is used to validate the user in that domain.
058 * 
059 * @author Ben Leinfelder
060 * @since 11/19/2007
061 */
062public class AuthenticateAction extends FigureAction {
063
064        private static final Log log = LogFactory.getLog(AuthenticateAction.class);
065
066        // ////////////////////////////////////////////////////////////////////////////
067        // LOCALIZABLE RESOURCES - NOTE that these default values are later
068        // overridden by values from the uiDisplayText resourcebundle file
069        // ////////////////////////////////////////////////////////////////////////////
070
071        private static String DISPLAY_NAME = StaticResources.getDisplayString(
072                        "actions.actor.displayName", "Login");
073        private static String TOOLTIP = StaticResources.getDisplayString(
074                        "actions.actor.tooltip", "Use Authentication Manager to login.");
075        private static ImageIcon LARGE_ICON = null;
076        private static KeyStroke ACCELERATOR_KEY = null;
077
078        private TableauFrame parent;
079        private TabbedDialog actorDialog;
080
081        protected String domainName = null;
082
083        private int maxLoginAttempt = 1;
084        private AuthenticationListener authListener = null;
085
086        /**
087         * Constructor
088         * 
089         * @param parent
090         *            the "frame" (derived from ptolemy.gui.Top) where the menu is
091         *            being added.
092         */
093        public AuthenticateAction(TableauFrame parent) {
094                super("");
095                if (parent == null) {
096                        IllegalArgumentException iae = new IllegalArgumentException(
097                                        "AuthenticateAction constructor received NULL argument for TableauFrame");
098                        iae.fillInStackTrace();
099                        throw iae;
100                }
101                this.parent = parent;
102
103                this.putValue(Action.NAME, DISPLAY_NAME);
104                this.putValue(GUIUtilities.LARGE_ICON, LARGE_ICON);
105                this.putValue("tooltip", TOOLTIP);
106                this.putValue(GUIUtilities.ACCELERATOR_KEY, ACCELERATOR_KEY);
107        }
108
109        /**
110         * Constructor
111         * 
112         * @param parent
113         *            the "frame" (derived from ptolemy.gui.Top) where the menu is
114         *            being added.
115         * @param authListener
116         *            listener of the authentication process
117         */
118        public AuthenticateAction(TableauFrame parent,
119                        AuthenticationListener authListener) {
120                this(parent);
121                this.authListener = authListener;
122        }
123
124        /**
125         * Invoked when an action occurs.
126         * 
127         * @param e
128         *            ActionEvent
129         */
130        public void actionPerformed(ActionEvent e) {
131                // must call this first...
132                super.actionPerformed(e);
133                doAction();
134        }
135        
136        /*
137         * Do the real action. Every subclass should implement this method.
138         */
139        protected void doAction() {
140            log.debug("starting domain prompt worker");
141            SwingWorker domainWorker = new SwingWorker<Void, Void>() {
142                /**
143                 * Collect the domain, which will then prompt for username/password.
144                 */
145                public Void doInBackground() {
146                    // Display the prompt window.
147                    promptForDomain();
148                    // Check if we get a selected domain.
149                    if (waitForDomain()) {
150                        // Try the authentication.
151                        fireAuthentication();
152                    }
153                    cancel(true);
154                    return null;
155                }
156            };
157
158            domainWorker.execute();
159        }
160
161        /**
162         * Get the selected domain name.
163         * 
164         * @return the name of domain
165         */
166        public String getDomainName() {
167                return domainName;
168        }
169
170        /** ************* DOMAIN ********** */
171        private boolean promptForDomain() {
172                log.debug("getting domain info - user input...");
173                // DomainSelectionGUI.fire();
174                DomainSelectionGUI.createAndShowGUI();
175                return true;
176        }
177
178        private boolean waitForDomain() {
179
180                log.debug("waiting for gui...");
181                while (DomainSelectionGUI.getDomain() == null) {
182                        // log.debug("waiting for gui...");
183                        // wait for the input to be made and the 'ok' button to be pressed
184                        try {
185                                Thread.sleep(1000);
186                        } catch (InterruptedException ie) {
187                                ie.printStackTrace();
188                        }
189                }
190
191                log.debug("done waiting for gui...domain="
192                                + DomainSelectionGUI.getDomain());
193                if (DomainSelectionGUI.getDomain().equals(DomainSelectionGUI.DOMAIN_BREAK)) {
194                        // user canceled the action
195                        if (authListener != null) {
196                                authListener.authenticationComplete(
197                                                AuthenticationListener.CANCEL, null, null);
198                        }
199                        return false;
200                }
201                // set the domain name so it is available for the worker
202                this.domainName = DomainSelectionGUI.getDomain();
203
204                // reset
205                DomainSelectionGUI.resetFields();
206
207                return true;
208        }
209
210        /** ************* AUTHENTICATION ********** */
211        private String login() {
212                String credential = null;
213                ProxyEntity proxy = null;
214                try {
215                        // first peek at it to see if we are already authenticated
216                        proxy = AuthenticationManager.getManager().peekProxy(
217                                        this.domainName);
218
219                        if (proxy != null) {
220                                credential = proxy.getCredential();
221                                String userName = proxy.getUserName();
222                                log.debug("authentication userName=" + userName);
223                                log.debug("authentication credential=" + credential);
224                                log.debug("user is already authenticated for domain: "
225                                                + this.domainName);
226
227                                // prompt to logout
228                                boolean logoutFirst = MessageHandler.yesNoQuestion(userName
229                                                + "  is already authenticated in domain: "
230                                                + this.domainName + "\nLogout?");
231
232                                if (logoutFirst) {
233                                        log.info("revoking authenticated proxy for credential="
234                                                        + credential);
235                                        AuthenticationManager.getManager().revokeProxy(proxy);
236                                        // return null;
237                                } else {
238                                        log.info("continuing using existing authentication, credential="
239                                                        + credential);
240                                        // return credential;
241                                }
242                        }
243                } catch (AuthenticationException ae) {
244                        MessageHandler.error("Authentication error encountered", ae);
245                        log.error("The authentication exception is ", ae);
246                        ae.printStackTrace();
247                }
248
249                // give them a few chances to do it right
250                for (int i = 0; i < maxLoginAttempt; i++) {
251                        try {
252                                // now try the authentication - no more peeking
253                                proxy = AuthenticationManager.getManager().getProxy(
254                                                this.domainName);
255                                credential = proxy.getCredential();
256                                if (authListener != null) {
257                                        authListener.authenticationComplete(
258                                                        AuthenticationListener.SUCCESS, credential,
259                                                        this.domainName);
260                                }
261                                break; // good!
262                        } catch (AuthenticationException ae) {
263                                if (ae.getType() == AuthenticationException.USER_CANCEL) {
264                                        log.info("user cancelled the authentication");
265                                        if (authListener != null) {
266                                                authListener.authenticationComplete(
267                                                                AuthenticationListener.CANCEL, null, null);
268                                        }
269                                        break; // we're done here, now
270                                } else {
271                                        if (authListener != null) {
272                                                authListener.authenticationComplete(
273                                                                AuthenticationListener.FAILURE, credential,
274                                                                this.domainName);
275                                        }
276                                        MessageHandler.error("Error authenticating", ae);
277                                        log.error("The authentication exception is ", ae);
278                                        ae.printStackTrace();
279                                        // loop will continue for a few tries
280                                }
281                        }
282                }
283                return credential;
284        }
285
286        protected void fireAuthentication() {
287                log.debug("starting to authenticate with domain=" + this.domainName);
288                SwingWorker authWorker = new SwingWorker<Void, Void>() {
289                        
290                        // Display the login window.
291                        public Void doInBackground() {
292                                login();
293                                cancel(true);
294                                return null;
295                        }
296                };
297
298                authWorker.execute();
299        }
300
301}