001    /*
002     *  PAVLOV -- Multiple Choice Study System
003     *  Copyright (C) 2000 - 2004 T.J. Willis
004     *
005     *  This program is free software; you can redistribute it and/or
006     *  modify it under the terms of the GNU General Public License
007     *  as published by the Free Software Foundation; either version 2
008     *  of the License, or (at your option) any later version.
009     *
010     *  This program is distributed in the hope that it will be useful,
011     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
012     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     *  GNU General Public License for more details.
014     *
015     *  You should have received a copy of the GNU General Public License
016     *  along with this program; if not, write to the Free Software
017     *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
018     *
019     *  $Header: /cvsroot/pavlov/net/sourceforge/pavlov/controllers/LoginController.java,v 1.4 2004/07/01 05:50:19 tj_willis Exp $
020     */
021    package net.sourceforge.pavlov.controllers;
022    
023    import java.awt.*;
024    import java.awt.event.*;
025    import java.util.*;
026    import javax.swing.*;
027    import javax.swing.event.HyperlinkEvent;
028    import javax.swing.event.HyperlinkListener;
029    import javax.swing.text.html.*;
030    import net.sourceforge.pavlov.event.*;
031    import net.sourceforge.pavlov.main.standalone.ResourceBroker;
032    import net.sourceforge.pavlov.user.*;
033    import net.sourceforge.sillyview.*;
034    import java.awt.Dimension;
035    import java.awt.Point;
036    import org.apache.log4j.*;
037    
038    /**
039     * Creates and manages model, view, and controller for the Logon system.
040     *
041     *@author     Haus
042     *@created    May 10, 2004
043     *@since      1.1
044     */
045    public class LoginController extends Widget
046    implements LogonListener, HyperlinkListener
047    {
048            //FIXED: isolate strings
049            //FIXED: implement in MVC
050            //FIXED: replace UserList with UserLoader
051            //FIXED: method should be its own class
052            //FIXED: break into smaller methods
053            //FIXME: improve javadocs
054            //FIXME: get strings from resourcebroker
055            //FIXME: provide resourcebroker to template?
056            //FIXME: the view should be passed in, not hardcoded here
057            /**
058             *  Token for communicating with velocity model
059             */
060            public final static String CHOOSE_ANOTHER_PASSWORD = "CHOOSEANOTHERPASSWORD";
061            /**
062             *  Token for communicating with velocity model
063             */
064            public final static String CREATE_NEW_USER = "CREATENEWUSER";
065            /**
066             *  Token for communicating with velocity model
067             */
068            public final static String NAME_IN_USE = "NAME_IN_USE";
069            /**
070             *  Token for communicating with velocity model
071             */
072            public final static String PASSWORD = "PASSWORD";
073            /**
074             *  Token for communicating with velocity model
075             */
076            public final static String USER_NAME = "USER_NAME";
077            /**
078             *  Token for communicating with velocity model
079             */
080            public final static String WRONG_PASSWORD = "WRONGPASSWORD";
081            /**
082             *  Token for communicating with velocity model
083             */
084            public final static String MODE = "MODE";
085            /**
086             *  Token for communicating with velocity model
087             */
088            public final static String CREATE = "CREATE";
089            
090        public static final String ERROR           = "ERROR";
091    
092        private ResourceBroker rb;
093        //private WidgetView loginView; //JFrameView loginView;
094        private Vector<LogonListener> listeners;
095        //private VelocityModel model;  FIXED: thanks FindBugs
096        private Category cat 
097            = Category.getInstance(LoginController.class.getName());
098    
099        public LoginController (WidgetView vu) throws Exception {
100            super(vu);
101            rb = ResourceBroker.getInstance();
102            //model = (VelocityModel)view.getModel();//new VelocityModel(templateFileName);
103            listeners = new Vector<LogonListener>();
104            
105            view.setToken(JPanelView.HYPERLINK_LISTENER,this);
106            view.setToken(JPanelView.TITLE,rb.getString(rb.PAVLOV_LOGIN));
107    
108    
109        }                    
110            /**
111             *  Returns true if a file exists for the given user.
112             *@return       Description of the Return Value
113             */
114            protected boolean userNameExists(String name)
115            {
116                    if (name == null) {
117                            return false;
118                    }
119                    UserFile uf = null;
120                    try {
121                            uf = new LocalUserFile(name);
122                            return (uf.exists());
123                    } catch (Exception ex) {
124                            //return false;
125                    }
126                    return false;
127            }
128    
129    
130            /**
131             *  Returns true if the user file exists, and its password
132             *  is equal to the one provided.  Returns false for usernames
133             *  less than 2 characters and passwords less than 3 characters.
134             *
135             *@param  name  Username to check
136             *@param  pass  Password provided by user
137             *@return       Whether password is correct
138             */
139            protected boolean goodPassword(String name, String pass)
140            {
141                    if (name == null || name.length() < 2) {
142                            return false;
143                    }
144                    if (pass == null || pass.length() < 3) {
145                            return false;
146                    }
147                    UserFile uf = null;
148                    User user = null;
149                    try {
150                            uf = new LocalUserFile(name);
151                            if (uf.exists()) {
152                                    user = uf.read(pass);
153                                    //wasteful
154                                    if (user == null) {
155                                            return false;
156                                    }
157                            } else {
158                                    // this falls through to the "return true" below
159                                    // FIXME: should limit the types of passwords that are
160                                    // created.  Checks above for at least 3 characters.
161                            }
162                    } catch (Exception ex) {
163                            return false;
164                    }
165                    return true;
166            }
167    
168    
169            /**
170             *  Creates a new user with the given name and password.
171             *
172             *@param  username  Description of the Parameter
173             *@param  pass      Description of the Parameter
174             *@return           Description of the Return Value
175             */
176            protected User createNewUser(String username, String pass)
177            {
178                    User newGuy = null;
179                    try {
180                            UserFile uf = new LocalUserFile(username);
181                            newGuy = new User(username, pass);
182                            newGuy.setUserFile(uf);
183                            uf.save(newGuy);
184                    } catch (Exception ex) {
185                            return null;
186                    }
187                    cat.info("CREATED NEW USER : " + username);//^
188                    return newGuy;
189            }
190    
191    
192            // close me and perform callback
193            /**
194             *  Notifies listeners that the user has successfully logged in
195             * and closes the Login view.
196             *
197             *@param  u  Description of the Parameter
198             */
199            protected void startSession(User u)
200            {
201                    notify(new LogonEvent(u));
202                    cat.info("SUCCESSFULLY LOGGED IN : " + u.getName());//^
203                    //close();
204            }
205    
206            /**
207             *  Description of the Method
208             *
209             *@param  event  Description of the Parameter
210             */
211            public void logonAttempt(LogonEvent event)
212            {
213                    String uname = event.getUserName();
214                    String pw = event.getPassword();
215                    boolean create = event.getCreateRequest();
216    
217                    HashMap<Object,Object> tmp = new HashMap<Object,Object>();
218                    tmp.put(NAME_IN_USE, null);
219                    tmp.put(CHOOSE_ANOTHER_PASSWORD, null);
220                    tmp.put(WRONG_PASSWORD, null);
221                    tmp.put(CREATE_NEW_USER, null);
222    
223                    if (create) {
224                            // Requesting to create new user
225                            // if username exists
226                            if (userNameExists(uname)) {
227                                    tmp.put(NAME_IN_USE, uname);
228                                    tmp.put(USER_NAME, "");
229                                    tmp.put(PASSWORD, "");
230                            }
231                            else if (!goodPassword(uname, pw)) {
232                                    // if password is not good
233                                    tmp.put(PASSWORD, "");
234                                    tmp.put(CHOOSE_ANOTHER_PASSWORD, "something");
235                            }
236                            else {
237                                    User u = createNewUser(uname, pw);
238                                    startSession(u);
239                                    return;
240                            }
241                    }
242                    else {
243                            // Not requesting to create new user
244                            if (userNameExists(uname)) {
245                                    if (goodPassword(uname, pw)) {
246                                            User u = getUser(uname, pw);
247                                            if (u != null) {
248                                                    startSession(u);
249                                            } else {
250                                                    tmp.put(ERROR, "something");
251                                            }
252                                    } else {
253                                            tmp.put(WRONG_PASSWORD, "something");
254                                            cat.info("Logon failed");
255                                    }
256    
257                            } else {
258                                    tmp.put(CREATE_NEW_USER, uname);
259                                    tmp.put(CREATE, "something");
260                                    tmp.put(USER_NAME, uname);
261                                    tmp.put(PASSWORD, pw);
262                            }
263                    }
264                    addTokens(tmp);
265            }
266    
267    
268    
269            /**
270             *  Attempts to load the user with the given name and password.
271             *
272             *@param  uname  Description of the Parameter
273             *@param  pass   Description of the Parameter
274             *@return        The user value
275             */
276            private User getUser(String uname, String pass)
277            {
278                    User newGuy = null;
279                    try {
280                            UserFile uf = new LocalUserFile(uname);
281                            newGuy = uf.read(pass);
282                    } catch (Exception ex) {
283                            // fall thru to return null
284                    }
285                    return newGuy;
286            }
287    
288    
289            /**
290             *  Sets the given token to the given value in the backing model.
291             *
292             *@param  n  The new token key
293             *@param  v  The new token value
294             */
295            public void setToken(String nam, String val)
296            {
297                    if (view == null) {
298                            return;
299                    }
300                    view.setToken(nam, val);
301            }
302    
303            public void addTokens(HashMap<Object,Object> map)
304            {
305                    if( view==null ) return;
306                    view.addTokens(map);
307            }
308    
309    
310            /*
311             *  Closes the JFrameView.
312             
313            public void close()
314            {
315                    if(view inherits JComponent){
316                      JComponent swingView = (JComponent)view;
317                      swingView.setVisible(false);
318                      swingView = null;
319                    }
320            }
321    */
322    
323            /**
324             *  Converts the URL command to a LogonEvent.
325             *
326             *@param  url  Description of the Parameter
327             *@return      Description of the Return Value
328             */
329            protected LogonEvent parseURL(String url)
330            {
331                    Hashtable h = URLParser.parseVariables(url);
332                    Object u = h.get(USER_NAME);
333                    Object p = h.get(PASSWORD);
334                    Object q = h.get(MODE);
335                    if (u == null) {
336                            u = "";
337                    }
338                    if (p == null) {
339                            p = "";
340                    }
341                    if (q == null) {
342                            q = "";
343                    }
344                    boolean create = q.equals("Create New User");//^
345                    return new LogonEvent(u.toString(), p.toString(), create);
346            }
347    
348    
349            /**
350             *  Catches the form submit event, and makes a login attempt
351             *  from it.
352             *
353             *@param  e  Description of the Parameter
354             */
355            public void hyperlinkUpdate(HyperlinkEvent e)
356            {
357                    java.net.URL uz = e.getURL();
358    
359                    if (e instanceof FormSubmitEvent) {
360                            FormSubmitEvent f = (FormSubmitEvent) e;
361                            String data = f.getData();
362                            LogonEvent evt = parseURL(data);
363                            logonAttempt(evt);
364                    }
365            }
366    
367    
368            /**
369             *  Notify listeners that a logonevent has occured.
370             *
371             *@param  e  Description of the Parameter
372             */
373            protected void notify(LogonEvent e)
374            {
375                       for(LogonListener l : listeners){
376                             l.logonAttempt(e);
377                       }
378            }
379    
380    
381            /**
382             *  Adds a LogonListener.
383             *
384             *@param  l  The feature to be added to the LogonListener attribute
385             */
386            public void addLogonListener(LogonListener l)
387            {
388                    listeners.add(l);
389            }
390    }