package hirondelle.web4j.security;

import hirondelle.web4j.model.AppException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/** 
 Perform tasks required after successful user login.

 <P>See {@link hirondelle.web4j.BuildImpl} for important information on how this item is configured. 
 {@link hirondelle.web4j.BuildImpl#forLoginTasks()} returns the configured implementation of this interface. 
 There is no default implementation of this interface. You must supply one. 
 (You can always supply an implmentation that does nothing, if you wish.) 

 <P>This interface exists to allow an application to react to successful user logins.
 At least one of those tasks must put an item in session scope. 
 The web4j <tt>Controller</tt> will use the presence/absence of that item to determine if the login tasks have already been performed.
  
 <P>Example tasks :
 <ul>
   <li>place user preferences in session scope
   <li>place the user id in session scope; the id is different from the user login name (see important note below).
   It's highly recommended that such an id be placed in session scope using {@link hirondelle.web4j.action.ActionImpl#USER_ID} as its key.
   Doing so lets your Actions easily access the id using {@link hirondelle.web4j.action.ActionImpl#getUserId()}.
 </ul>
 
    <h3>User Login Name Versus User Id</h3>
 After a successful login, the container will always place the user's <i>login name</i> in session scope. 
   However, it's often convenient or desirable to have a corresponding user <i>id</i> in session scope as well.
    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).  
    Having the user id in session scope often helps to enforce <a href='http://www.web4j.com/UserGuide.jsp#DataOwnershipConstraints'>data ownership constraints</a>.
     
   <h3>The User Id Is a Server Secret</h3>
  The user login name and the user id must be treated very differently.
   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>
   It's nobody's business, including the user to whom it belongs.  
   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.
   Exposing it allows one user to access the data of another.
   <b>Always treat the user id as a server-side secret. Failure to do so is a huge security risk.</b>
   
   <h3>Consolidating User Preferences Into One Object</h3>
   If there are many user preferences, and not just one, then it might make sense to place a single  
   object into session scope, which gathers together all such preferences into a single object.
   Note, however, that the <em>default</em> implementations of 
   {@link hirondelle.web4j.request.LocaleSource} and {@link hirondelle.web4j.request.TimeZoneSource}
   are not consistent with such a style, since they expect their data to be stored under separate 
   keys defined in {@link hirondelle.web4j.Controller}. 
*/
public interface LoginTasks {

  /**
   React to a successful user log in. 
   Typically, implementations will look up data related to the user, and place it in session scope.
   
   <P>This method is called only if all of the following are true:
   <ul>
    <li>a session already exists
    <li>the user has successfully logged in
    <li>{@link #hasAlreadyReacted(HttpSession)} returns <tt>false</tt>
   </ul> 
  */
  void reactToUserLogin(HttpSession aExistingSession, HttpServletRequest aRequest) throws AppException;

  /** 
   Return <tt>true</tt> only if the user login has already been processed by {@link #reactToUserLogin(HttpSession, HttpServletRequest)}.
   Typically, implementations will simply return <tt>true</tt> only if an item of a given name is already in session scope.
  */
  boolean hasAlreadyReacted(HttpSession aSession);
 
}
