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 }