001 package hirondelle.web4j.security; 002 003 import hirondelle.web4j.model.AppException; 004 005 import javax.servlet.http.HttpServletRequest; 006 import javax.servlet.http.HttpSession; 007 008 /** 009 Perform tasks required after successful user login. 010 011 <P>See {@link hirondelle.web4j.BuildImpl} for important information on how this item is configured. 012 {@link hirondelle.web4j.BuildImpl#forLoginTasks()} returns the configured implementation of this interface. 013 There is no default implementation of this interface. You must supply one. 014 (You can always supply an implmentation that does nothing, if you wish.) 015 016 <P>This interface exists to allow an application to react to successful user logins. 017 At least one of those tasks must put an item in session scope. 018 The web4j <tt>Controller</tt> will use the presence/absence of that item to determine if the login tasks have already been performed. 019 020 <P>Example tasks : 021 <ul> 022 <li>place user preferences in session scope 023 <li>place the user id in session scope; the id is different from the user login name (see important note below). 024 It's highly recommended that such an id be placed in session scope using {@link hirondelle.web4j.action.ActionImpl#USER_ID} as its key. 025 Doing so lets your Actions easily access the id using {@link hirondelle.web4j.action.ActionImpl#getUserId()}. 026 </ul> 027 028 <h3>User Login Name Versus User Id</h3> 029 After a successful login, the container will always place the user's <i>login name</i> in session scope. 030 However, it's often convenient or desirable to have a corresponding user <i>id</i> in session scope as well. 031 In this context, the user id is a database identifier, the primary key of an underlying user record in the database (almost always an integer value). 032 Having the user id in session scope often helps to enforce <a href='http://www.web4j.com/UserGuide.jsp#DataOwnershipConstraints'>data ownership constraints</a>. 033 034 <h3>The User Id Is a Server Secret</h3> 035 The user login name and the user id must be treated very differently. 036 While the user login name can of course be displayed to the user, <b>the user id is a server-side secret, and should never be made visible to the user.</b> 037 It's nobody's business, including the user to whom it belongs. 038 You can place the user id in session scope, and your server-side code can use it, but its value can never be part of the HTTP response in any way. 039 Exposing it allows one user to access the data of another. 040 <b>Always treat the user id as a server-side secret. Failure to do so is a huge security risk.</b> 041 042 <h3>Consolidating User Preferences Into One Object</h3> 043 If there are many user preferences, and not just one, then it might make sense to place a single 044 object into session scope, which gathers together all such preferences into a single object. 045 Note, however, that the <em>default</em> implementations of 046 {@link hirondelle.web4j.request.LocaleSource} and {@link hirondelle.web4j.request.TimeZoneSource} 047 are not consistent with such a style, since they expect their data to be stored under separate 048 keys defined in {@link hirondelle.web4j.Controller}. 049 */ 050 public interface LoginTasks { 051 052 /** 053 React to a successful user log in. 054 Typically, implementations will look up data related to the user, and place it in session scope. 055 056 <P>This method is called only if all of the following are true: 057 <ul> 058 <li>a session already exists 059 <li>the user has successfully logged in 060 <li>{@link #hasAlreadyReacted(HttpSession)} returns <tt>false</tt> 061 </ul> 062 */ 063 void reactToUserLogin(HttpSession aExistingSession, HttpServletRequest aRequest) throws AppException; 064 065 /** 066 Return <tt>true</tt> only if the user login has already been processed by {@link #reactToUserLogin(HttpSession, HttpServletRequest)}. 067 Typically, implementations will simply return <tt>true</tt> only if an item of a given name is already in session scope. 068 */ 069 boolean hasAlreadyReacted(HttpSession aSession); 070 071 }