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 }