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    }