details:   https://code.openbravo.com/erp/devel/pi/rev/b59cceedafd3
changeset: 30637:b59cceedafd3
user:      Martin Taal <martin.taal <at> openbravo.com>
date:      Mon Nov 14 12:22:05 2016 +0100
summary:   Fixes issue 34486: Support stateless requests
Various code changes to prevent http session creation in some cases and set the 
correct attribute in the http request object
to track that a request is stateless.

Summary of changes:
- JsonUtils: prevent creation of a session when generating error message
- AuthenticationManager: define the stateless parameter and annotation, some 
common utility methods, prevent setting dbsession record when stateless 
request, and prevent creating session when clearing the session
- DefaultAuthenticationManager: when stateless use the webservice login approach
- HttpSecureAppServlet: small change to prevent accidental creation of http 
session, move common code to method, use it to check license restrictions when 
doing stateless request
- BaseWebServiceServlet: set the stateless request attribute if this is a 
stateless request
- WebServiceServlet: moved code to parent class for re-use and checking if a 
webservice is stateless

diffstat:

 
modules/org.openbravo.service.json/src/org/openbravo/service/json/JsonUtils.java
 |  29 +++-
 src/org/openbravo/authentication/AuthenticationManager.java                    
  |  65 +++++++++-
 src/org/openbravo/authentication/basic/DefaultAuthenticationManager.java       
  |   4 +
 src/org/openbravo/base/secureApp/HttpSecureAppServlet.java                     
  |  44 ++++--
 src/org/openbravo/service/web/BaseWebServiceServlet.java                       
  |  25 +++
 src/org/openbravo/service/web/WebServiceServlet.java                           
  |  17 +--
 6 files changed, 145 insertions(+), 39 deletions(-)

diffs (truncated from 416 to 300 lines):

diff -r 285226a2a73b -r b59cceedafd3 
modules/org.openbravo.service.json/src/org/openbravo/service/json/JsonUtils.java
--- 
a/modules/org.openbravo.service.json/src/org/openbravo/service/json/JsonUtils.java
  Mon Nov 14 10:30:16 2016 +0100
+++ 
b/modules/org.openbravo.service.json/src/org/openbravo/service/json/JsonUtils.java
  Mon Nov 14 12:22:05 2016 +0100
@@ -31,6 +31,7 @@
 import org.codehaus.jettison.json.JSONException;
 import org.codehaus.jettison.json.JSONObject;
 import org.hibernate.QueryTimeoutException;
+import org.openbravo.authentication.AuthenticationManager;
 import org.openbravo.base.exception.OBException;
 import org.openbravo.base.exception.OBSecurityException;
 import org.openbravo.base.model.Entity;
@@ -216,9 +217,19 @@
         log.error(e.getMessage(), e);
       }
 
-      final VariablesSecureApp vars = 
RequestContext.get().getVariablesSecureApp();
-      final OBError obError = Utility.translateError(new 
DalConnectionProvider(), vars, OBContext
-          .getOBContext().getLanguage().getLanguage(), 
localThrowable.getMessage());
+      OBError obError;
+      VariablesSecureApp vars = null;
+
+      // in case of stateless then prevent creation of a http session when an 
error is reported
+      if 
(AuthenticationManager.isStatelessRequest(RequestContext.get().getRequest())) {
+        obError = new OBError();
+        obError.setType("Error");
+        obError.setMessage(throwable.getMessage());
+      } else {
+        vars = RequestContext.get().getVariablesSecureApp();
+        obError = Utility.translateError(new DalConnectionProvider(), vars, 
OBContext
+            .getOBContext().getLanguage().getLanguage(), 
localThrowable.getMessage());
+      }
 
       if (localThrowable instanceof OBSecurityException) {
         final JSONObject error = new JSONObject();
@@ -230,10 +241,14 @@
           || (localThrowable.getCause() instanceof PSQLException && 
PG_QUERY_CANCELED
               .equals(((PSQLException) 
localThrowable.getCause()).getSQLState()))) {
         final JSONObject error = new JSONObject();
-        error.put(
-            "message",
-            Utility.messageBD(new DalConnectionProvider(false), 
"OBUIAPP_QueryTimeOut",
-                vars.getLanguage()));
+        if (vars != null) {
+          error.put(
+              "message",
+              Utility.messageBD(new DalConnectionProvider(false), 
"OBUIAPP_QueryTimeOut",
+                  vars.getLanguage()));
+        } else {
+          error.put("message", "OBUIAPP_QueryTimeOut");
+        }
         error.put("messageType", obError.getType());
         error.put("title", obError.getTitle());
         jsonResponse.put(JsonConstants.RESPONSE_ERROR, error);
diff -r 285226a2a73b -r b59cceedafd3 
src/org/openbravo/authentication/AuthenticationManager.java
--- a/src/org/openbravo/authentication/AuthenticationManager.java       Mon Nov 
14 10:30:16 2016 +0100
+++ b/src/org/openbravo/authentication/AuthenticationManager.java       Mon Nov 
14 12:22:05 2016 +0100
@@ -16,6 +16,10 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -54,6 +58,7 @@
   private static final Logger log4j = 
Logger.getLogger(AuthenticationManager.class);
   private static final String DEFAULT_AUTH_CLASS = 
"org.openbravo.authentication.basic.DefaultAuthenticationManager";
 
+  public static final String STATELESS_REQUEST_PARAMETER = "stateless";
   private static final String SUCCESS_SESSION_WEB_SERVICE = "WS";
   private static final String REJECTED_SESSION_WEB_SERVICE = "WSR";
   private static final String SUCCESS_SESSION_CONNECTOR = "WSC";
@@ -65,6 +70,29 @@
   protected String username = "";
 
   /**
+   * Is used to determine if the request is a stateless request. A stateless 
request does not create
+   * a httpsession. This also means that no preferences or other information 
is present. Stateless
+   * requests should normally be used only for relatively simple logic.
+   * 
+   * A request is stateless if it has a parameter stateless=true or an 
attribute stateless with the
+   * string value "true".
+   * 
+   * @param request
+   * @return true if this is a stateless request
+   */
+  public static boolean isStatelessRequest(HttpServletRequest request) {
+    return "true".equals(request.getParameter(STATELESS_REQUEST_PARAMETER))
+        || "true".equals(request.getAttribute(STATELESS_REQUEST_PARAMETER));
+  }
+
+  /**
+   * Returns true if the passed class has the Stateless annotation
+   */
+  public static boolean isStatelessService(Class<?> clz) {
+    return null != clz.getAnnotation(Stateless.class);
+  }
+
+  /**
    * Returns an instance of AuthenticationManager subclass, based on the 
authentication.class
    * property in Openbravo.properties
    */
@@ -142,6 +170,10 @@
 
     final String userId = doAuthenticate(request, response);
 
+    if (AuthenticationManager.isStatelessRequest(request)) {
+      return userId;
+    }
+
     final VariablesSecureApp vars = new VariablesSecureApp(request, false);
     if (StringUtils.isEmpty(vars.getSessionValue("#AD_SESSION_ID"))) {
       setDBSession(request, userId, SUCCESS_SESSION_STANDARD, true);
@@ -186,7 +218,10 @@
       throws AuthenticationException {
     final String userId = doWebServiceAuthenticate(request);
 
-    final String dbSessionId = setDBSession(request, userId, 
SUCCESS_SESSION_WEB_SERVICE, false);
+    String dbSessionId = null;
+    if (!AuthenticationManager.isStatelessRequest(request)) {
+      dbSessionId = setDBSession(request, userId, SUCCESS_SESSION_WEB_SERVICE, 
false);
+    }
 
     return webServicePostAuthenticate(userId, dbSessionId);
   }
@@ -227,15 +262,21 @@
       log4j.warn("Number of webservice calls exceeded today.");
       return userId;
     case EXCEEDED_MAX_WS_CALLS:
-      updateDBSession(dbSessionId, false, REJECTED_SESSION_WEB_SERVICE);
+      if (dbSessionId != null) {
+        updateDBSession(dbSessionId, false, REJECTED_SESSION_WEB_SERVICE);
+      }
       log4j.warn("Cannot use WS, exceeded number of calls");
       throw new AuthenticationException("Exceeded maximum number of allowed 
calls to web services.");
     case EXPIRED:
-      updateDBSession(dbSessionId, false, REJECTED_SESSION_WEB_SERVICE);
+      if (dbSessionId != null) {
+        updateDBSession(dbSessionId, false, REJECTED_SESSION_WEB_SERVICE);
+      }
       log4j.warn("Cannot use WS, license expired");
       throw new AuthenticationException("Exceeded maximum number of allowed 
calls to web services.");
     case EXPIRED_MODULES:
-      updateDBSession(dbSessionId, false, REJECTED_SESSION_WEB_SERVICE);
+      if (dbSessionId != null) {
+        updateDBSession(dbSessionId, false, REJECTED_SESSION_WEB_SERVICE);
+      }
       log4j.warn("Cannot use WS, expired modules");
       throw new AuthenticationException("There are expired modules");
     }
@@ -310,8 +351,10 @@
   public final void logout(HttpServletRequest request, HttpServletResponse 
response)
       throws ServletException, IOException {
 
-    VariablesBase vars = new VariablesBase(request);
-    vars.clearSession(true);
+    if (request.getSession(false) != null) {
+      VariablesBase vars = new VariablesBase(request);
+      vars.clearSession(true);
+    }
 
     doLogout(request, response);
   }
@@ -452,4 +495,14 @@
     }
   }
 
+  /**
+   * To annotate a certain webservice/service as being stateless, i.e. not 
creating or keeping a
+   * http session on the server
+   * 
+   * @author mtaal
+   */
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target(ElementType.TYPE)
+  public static @interface Stateless {
+  }
 }
diff -r 285226a2a73b -r b59cceedafd3 
src/org/openbravo/authentication/basic/DefaultAuthenticationManager.java
--- a/src/org/openbravo/authentication/basic/DefaultAuthenticationManager.java  
Mon Nov 14 10:30:16 2016 +0100
+++ b/src/org/openbravo/authentication/basic/DefaultAuthenticationManager.java  
Mon Nov 14 12:22:05 2016 +0100
@@ -57,6 +57,10 @@
   protected String doAuthenticate(HttpServletRequest request, 
HttpServletResponse response)
       throws AuthenticationException, ServletException, IOException {
 
+    if (request.getSession(false) == null && 
AuthenticationManager.isStatelessRequest(request)) {
+      return webServiceAuthenticate(request);
+    }
+
     final VariablesSecureApp vars = new VariablesSecureApp(request, false);
     final Boolean resetPassword = 
Boolean.parseBoolean(vars.getStringParameter("resetPassword"));
     final String sUserId;
diff -r 285226a2a73b -r b59cceedafd3 
src/org/openbravo/base/secureApp/HttpSecureAppServlet.java
--- a/src/org/openbravo/base/secureApp/HttpSecureAppServlet.java        Mon Nov 
14 10:30:16 2016 +0100
+++ b/src/org/openbravo/base/secureApp/HttpSecureAppServlet.java        Mon Nov 
14 12:22:05 2016 +0100
@@ -32,10 +32,9 @@
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
-import net.sf.jasperreports.engine.JRDataSource;
-
 import org.codehaus.jettison.json.JSONObject;
 import org.hibernate.criterion.Restrictions;
+import org.openbravo.authentication.AuthenticationException;
 import org.openbravo.authentication.AuthenticationManager;
 import org.openbravo.base.HttpBaseServlet;
 import org.openbravo.base.HttpBaseUtils;
@@ -72,6 +71,8 @@
 import org.openbravo.utils.Replace;
 import org.openbravo.xmlEngine.XmlDocument;
 
+import net.sf.jasperreports.engine.JRDataSource;
+
 public class HttpSecureAppServlet extends HttpBaseServlet {
   private static final long serialVersionUID = 1L;
   protected boolean boolHist = true;
@@ -194,7 +195,8 @@
       OBContext.setAdminMode();
 
       strUserAuth = m_AuthManager.authenticate(request, response);
-      if (strUserAuth == null && 
"Y".equals(request.getSession().getAttribute("forceLogin"))) {
+      if (strUserAuth == null && request.getSession(false) != null
+          && "Y".equals(request.getSession().getAttribute("forceLogin"))) {
         strUserAuth = "0";
         variables.loggingIn = "Y";
       }
@@ -204,6 +206,15 @@
         return;
       }
 
+      // if stateless then stop here, the remaining logic uses the httpsession
+      if (AuthenticationManager.isStatelessRequest(request)) {
+        if (areThereLicenseRestrictions(null)) {
+          throw new AuthenticationException("No valid license");
+        }
+        super.serviceInitialized(request, response);
+        return;
+      }
+
       variables = new Variables(request); // Rebuild variable, auth-mgr could 
set the role
 
       boolean loggedOK = false;
@@ -214,7 +225,8 @@
         // log in process is completed, check whether the session in db is 
still active
         loggedOK = SeguridadData.loggedOK(this, variables.getDBSession());
         if (!loggedOK) {
-          if ("Y".equals(request.getSession().getAttribute("forceLogin"))) {
+          if (request.getSession(false) != null
+              && "Y".equals(request.getSession().getAttribute("forceLogin"))) {
             variables.loggingIn = "Y";
             loggedOK = true;
           } else {
@@ -241,18 +253,10 @@
           final VariablesSecureApp vars = new VariablesSecureApp(request, 
false);
           boolean onlySystemAdminAvailable = "Y".equals(vars
               .getSessionValue("onlySystemAdminRoleShouldBeAvailableInErp"));
-          LicenseRestriction limitation = 
ActivationKey.getInstance().checkOPSLimitations(
-              variables.getDBSession());
           // We check if there is a Openbravo Professional Subscription 
restriction in the license,
           // or if the last rebuild didn't go well. If any of these are true, 
then the user is
           // allowed to login only as system administrator
-          if (limitation == LicenseRestriction.OPS_INSTANCE_NOT_ACTIVE
-              || limitation == 
LicenseRestriction.NUMBER_OF_CONCURRENT_USERS_REACHED
-              || limitation == LicenseRestriction.MODULE_EXPIRED
-              || limitation == LicenseRestriction.NOT_MATCHED_INSTANCE
-              || limitation == LicenseRestriction.HB_NOT_ACTIVE
-              || limitation == LicenseRestriction.ON_DEMAND_OFF_PLATFORM
-              || limitation == LicenseRestriction.POS_TERMINALS_EXCEEDED || 
!correctSystemStatus
+          if (areThereLicenseRestrictions(variables.getDBSession()) || 
!correctSystemStatus
               || onlySystemAdminAvailable) {
             // it is only allowed to log as system administrator
             strRole = DefaultOptionsData.getDefaultSystemRole(this, 
strUserAuth);
@@ -480,6 +484,20 @@
     }
   }
 
+  // We check if there is a Openbravo Professional Subscription restriction in 
the license,
+  // or if the last rebuild didn't go well. If any of these are true, then the 
user is
+  // allowed to login only as system administrator
+  private boolean areThereLicenseRestrictions(String sessionId) {
+    LicenseRestriction limitation = 
ActivationKey.getInstance().checkOPSLimitations(sessionId);
+    return limitation == LicenseRestriction.OPS_INSTANCE_NOT_ACTIVE
+        || limitation == LicenseRestriction.NUMBER_OF_CONCURRENT_USERS_REACHED
+        || limitation == LicenseRestriction.MODULE_EXPIRED
+        || limitation == LicenseRestriction.NOT_MATCHED_INSTANCE
+        || limitation == LicenseRestriction.HB_NOT_ACTIVE
+        || limitation == LicenseRestriction.ON_DEMAND_OFF_PLATFORM
+        || limitation == LicenseRestriction.POS_TERMINALS_EXCEEDED;
+  }
+
   /**
    * Cheks access passing all the parameters
    * 
diff -r 285226a2a73b -r b59cceedafd3 
src/org/openbravo/service/web/BaseWebServiceServlet.java
--- a/src/org/openbravo/service/web/BaseWebServiceServlet.java  Mon Nov 14 
10:30:16 2016 +0100
+++ b/src/org/openbravo/service/web/BaseWebServiceServlet.java  Mon Nov 14 
12:22:05 2016 +0100
@@ -31,8 +31,10 @@

------------------------------------------------------------------------------
Developer Access Program for Intel Xeon Phi Processors
Access to Intel Xeon Phi processor-based developer platforms.
With one year of Intel Parallel Studio XE.
Training and support from Colfax.
Order your platform today. http://sdm.link/xeonphi
_______________________________________________
Openbravo-commits mailing list
Openbravo-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openbravo-commits

Reply via email to