2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shale.usecases.profile;
19  
20  import java.util.Map;
21  import javax.faces.context.FacesContext;
22  import javax.servlet.http.Cookie;
23  import javax.servlet.http.HttpServletRequest;
24  import javax.servlet.http.HttpServletResponse;
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.shale.usecases.logic.LogonLogic;
28  import org.apache.shale.usecases.model.User;
29  import org.apache.shale.util.Messages;
30  import org.apache.shale.view.AbstractViewController;
31  
32  /***
33   * <p><code>ViewController</code> and action methods for the Logon dialog.</p>
34   *
35   * <p><strong>WARNING</strong> - The format of the cookie used to store
36   * "remember me" credentials is <strong>NOT</strong> secure, and should
37   * be considered demo quality.  The architecture of a production quality
38   * version of this function would be identical; more effort would need
39   * to be invested in improving security around the cookie values.</p>
40   *
41   * $Id: LogonActions.java 464373 2006-10-16 04:21:54Z rahul $
42   */
43  public class LogonActions extends AbstractViewController {
44      
45      
46      // -------------------------------------------------------- Static Variables
47  
48  
49      /***
50       * <p>Log instance for this class.</p>
51       */
52      private static final Log log = LogFactory.getLog(LogonActions.class);
53  
54  
55      /***
56       * <p>Message resources for this application.</p>
57       */
58      private static final Messages messages =
59        new Messages("org.apache.shale.usecases.view.Bundle");
60  
61  
62      // ------------------------------------------------------ Manifest Constants
63  
64  
65  
66      /***
67       * <p>Logical outcome indicating an authenticated user.</p>
68       */
69      static final String AUTHENTICATED = "authenticated";
70  
71  
72      /***
73       * <p>Logical outcome indicating the user wishes to create a new
74       * user profile.</p>
75       */
76      static final String CREATE = "create";
77  
78  
79      /***
80       * <p>Managed bean name under which the business logic bean instance
81       * for this dialog is stored.</p>
82       */
83      static final String LOGIC_BEAN = "profile$logic"; // FIXME - shared name
84  
85  
86      /***
87       * <p>Name of the HTTP cookie in which we store "remember me" credentials.</p>
88       */
89      static final String COOKIE_NAME = "remember_me";
90  
91  
92      /***
93       * <p>Logical outcome indicating an unauthenticated user.</p>
94       */
95      static final String UNAUTHENTICATED = "unauthenticated";
96  
97  
98      // --------------------------------------------------- Configured Properties
99  
100 
101     /***
102      * <p>Flag indicating that "remember me" cookies are enabled.</p>
103      */
104     private boolean rememberMe = false;
105     public boolean isRememberMe() { return this.rememberMe; }
106     public void setRememberMe(boolean rememberMe) { this.rememberMe = rememberMe; }
107 
108 
109     /***
110      * <p>Session scope attribute under which a {@link User} instance for the
111      * currently logged in user is stored.</p>
112      */
113     private String userKey = "user"; // FIXME - shared
114     public String getUserKey() { return this.userKey; }
115     public void setUserKey(String userKey) { this.userKey = userKey; }
116 
117 
118     // -------------------------------------------------- Input Field Properties
119 
120 
121     /***
122      * <p>Password entered by the user.</p>
123      */
124     private String password = null;
125     public String getPassword() { return this.password; }
126     public void setPassword(String password) { this.password = password; }
127 
128 
129     /***
130      * <p>Flag indicating that the user wishes to have a "remember me"
131      * cookie created this time.</p>
132      */
133     private boolean remember = false;
134     public boolean isRemember() { return this.remember; }
135     public void setRemember(boolean remember) { this.remember = remember; }
136 
137 
138     /***
139      * <p>Username entered by the user.</p>
140      */
141     private String username = null;
142     public String getUsername() { return this.username; }
143     public void setUsername(String username) { this.username = username; }
144 
145 
146     // ----------------------------------------------------------------- Actions
147 
148 
149     /***
150      * <p>Skip the logon dialog if an appropriate "remember me" cookie
151      * is discovered, and this facility is enabled.</p>
152      *
153      * <p>The following logical outcome values are returned:</p>
154      * <ul>
155      * <li><code>AUTHENTICATED</code> - User has been authenticated.</li>
156      * <li><code>UNAUTHENTICATED</code> - User has not been authenticated
157      *     (no cookie, "remember me" not supported).</li>
158      * </ul>
159      */
160     public String check() {
161 
162         // Is "remember me" functionality enabled?
163         if (!isRememberMe()) {
164             return UNAUTHENTICATED;
165         }
166 
167         // Locate the "remember me" cookie (if any)
168         FacesContext context = getFacesContext();
169         Map map = context.getExternalContext().getRequestCookieMap();
170         Cookie cookie = (Cookie) map.get(COOKIE_NAME);
171         if (cookie == null) {
172             return UNAUTHENTICATED;
173         }
174 
175         // Extract the user identifier of the logged-on user (if any)
176         int id = 0;
177         try {
178             id = Integer.parseInt(cookie.getValue());
179         } catch (NumberFormatException e) {
180             return UNAUTHENTICATED;
181         }
182 
183         // Locate the corresponding valid user (if any) and return it
184         LogonLogic logic = (LogonLogic) getBean(LOGIC_BEAN);
185         User user = logic.findUser(id);
186         if (user == null) {
187             return UNAUTHENTICATED;
188         }
189 
190         // Register the newly authenticated user and return that outcome
191         register(user);
192         return AUTHENTICATED;
193 
194     }
195 
196 
197     /***
198      * <p>Request creation of a new user profile.</p>
199      */
200     public String create() {
201 
202         // At this point, there is no special behavior needed
203         // prior to executing the subdialog.  If there is, it
204         // should likely be defined as an action in EditProfileActions
205         // instead of here.
206         return CREATE;
207 
208     }
209 
210 
211     /***
212      * <p>Alternate exit action for this dialog.  Remove the currently
213      * logged on user (if any), remove this instance from session scope,
214      * and return outcome <code>unauthenticated</code>.</p>
215      */
216     public String logoff() {
217 
218         unregister();
219         return UNAUTHENTICATED;
220 
221     }
222 
223 
224     /***
225      * <p>Authenticate the entered username and password.</p>
226      */
227     public String logon() {
228 
229         // Attempt a successful authentication
230         LogonLogic logic = (LogonLogic) getBean(LOGIC_BEAN);
231         User user = logic.authenticate(username, password);
232         if (user != null) {
233             if (user.isConfirmed()) {
234                 // Confirmed user, log him/her on
235                 register(user);
236                 if (isRememberMe()) {
237                     if (isRemember()) {
238                         remember(user);
239                     } else {
240                         forget(user);
241                     }
242                 }
243                 return AUTHENTICATED;
244             } else {
245                 // Unconfirmed user, tell him/her to reply to the email
246                 error(messages.getMessage("profile.unconfirmed"));
247                 return UNAUTHENTICATED;
248             }
249         }
250 
251         // On unsuccessful authentication, tell the user to try again
252         error(messages.getMessage("profile.incorrect"));
253         return null;
254 
255     }
256 
257 
258     // --------------------------------------------------------- Private Methods
259 
260 
261     /***
262      * <p>Remove any existing "remember me" cookie that was included.</p>
263      *
264      * @param user {@link User} to be forgotten
265      */
266     private void forget(User user) {
267 
268         FacesContext context = getFacesContext();
269         HttpServletRequest request =
270           (HttpServletRequest) context.getExternalContext().getRequest();
271         Cookie cookie =
272           new Cookie(COOKIE_NAME, "");
273         cookie.setDomain(request.getServerName());
274         cookie.setMaxAge(0); // Delete immediately
275         cookie.setPath(request.getContextPath());
276         HttpServletResponse response =
277           (HttpServletResponse) context.getExternalContext().getResponse();
278         response.addCookie(cookie);
279 
280     }
281 
282 
283     /***
284      * <p>Store the specified {@link User} in session scope, and take whatever
285      * other actions are necessary to mark the user as being logged on.</p>
286      *
287      * @param user {@link User} who is to be logged on
288      */
289     private void register(User user) {
290 
291         // Store the user instance in session scope
292         FacesContext context = getFacesContext();
293         context.getExternalContext().getSessionMap().
294           put(getUserKey(), user);
295     
296     }
297 
298 
299     /***
300      * <p>Add a "remember me" cookie to the current response.</p>
301      *
302      * @param user {@link User} whose identity is to be persisted
303      */
304     private void remember(User user) {
305 
306         FacesContext context = getFacesContext();
307         HttpServletRequest request =
308           (HttpServletRequest) context.getExternalContext().getRequest();
309         Cookie cookie =
310           new Cookie(COOKIE_NAME, "" + user.getId()); // FIXME - more secure mechanism needed
311         // cookie.setDomain(request.getServerName());
312         cookie.setMaxAge(60 * 60 * 24 * 365); // One year
313         cookie.setPath(request.getContextPath());
314         HttpServletResponse response =
315           (HttpServletResponse) context.getExternalContext().getResponse();
316         response.addCookie(cookie);
317 
318     }
319 
320 
321     /***
322      * <p>Remove registration of the currently logged in user, as needed.</p>
323      */
324     private void unregister() {
325 
326         // Remove user instance from session scope
327         getFacesContext().getExternalContext().getSessionMap().
328           remove(getUserKey());
329 
330     }
331 
332 
333 }