svn commit: r1844880 - in /ofbiz: ofbiz-framework/trunk/ ofbiz-framework/trunk/framework/common/src/main/java/org/apache/ofbiz/common/ ofbiz-framework/trunk/framework/common/webcommon/WEB-INF/ ofbiz-framework/trunk/framework/security/config/ ofbiz-fram...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1844880 - in /ofbiz: ofbiz-framework/trunk/ ofbiz-framework/trunk/framework/common/src/main/java/org/apache/ofbiz/common/ ofbiz-framework/trunk/framework/common/webcommon/WEB-INF/ ofbiz-framework/trunk/framework/security/config/ ofbiz-fram...

jleroux@apache.org
Author: jleroux
Date: Fri Oct 26 09:32:46 2018
New Revision: 1844880

URL: http://svn.apache.org/viewvc?rev=1844880&view=rev
Log:
Implemented: Navigate from a domain to another with automated signed in
authentication
(OFBIZ-10307)

This uses a JWT Token authentication to get from one domain, where you are
signed in, to another domain where you get signed in automatically.
Something like ExternalLoginKey or Tomcat SSO, but not on the same domain.

In the example component, the FormWidgetExamples screen contains 2 new fields
in the LinksExampleForm which demonstrate the use from a local instance to the
trunk demo instance.

A simple documentation is available in
  framework\webapp\src\docs\asciidoc\_include\wa-cross-domains-SSO.adoc

Thanks: Taher for review

Modified:
    ofbiz/ofbiz-framework/trunk/build.gradle
    ofbiz/ofbiz-framework/trunk/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java
    ofbiz/ofbiz-framework/trunk/framework/common/webcommon/WEB-INF/common-controller.xml
    ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties
    ofbiz/ofbiz-framework/trunk/framework/webapp/src/docs/asciidoc/_include/wa-cross-domains-SSO.adoc
    ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java
    ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
    ofbiz/ofbiz-framework/trunk/themes/common-theme/webapp/common/js/util/OfbizUtil.js
    ofbiz/ofbiz-plugins/trunk/example/config/ExampleUiLabels.xml
    ofbiz/ofbiz-plugins/trunk/example/widget/example/FormWidgetExampleForms.xml

Modified: ofbiz/ofbiz-framework/trunk/build.gradle
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/build.gradle?rev=1844880&r1=1844879&r2=1844880&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/build.gradle (original)
+++ ofbiz/ofbiz-framework/trunk/build.gradle Fri Oct 26 09:32:46 2018
@@ -162,6 +162,7 @@ dependencies {
     compile 'oro:oro:2.0.8'
     compile 'wsdl4j:wsdl4j:1.6.3'
     compile 'org.jsoup:jsoup:1.11.2'
+    compile 'io.jsonwebtoken:jjwt:0.9.0'
 
     // ofbiz unit-test compile libs
     testCompile 'org.mockito:mockito-core:2.13.0'

Modified: ofbiz/ofbiz-framework/trunk/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java?rev=1844880&r1=1844879&r2=1844880&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java (original)
+++ ofbiz/ofbiz-framework/trunk/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java Fri Oct 26 09:32:46 2018
@@ -51,6 +51,8 @@ import org.apache.ofbiz.entity.Delegator
 import org.apache.ofbiz.entity.GenericEntityException;
 import org.apache.ofbiz.entity.GenericValue;
 import org.apache.ofbiz.entity.util.EntityUtilProperties;
+import org.apache.ofbiz.webapp.control.JWTManager;
+import org.apache.ofbiz.webapp.control.LoginWorker;
 import org.apache.ofbiz.widget.model.ThemeFactory;
 import org.apache.ofbiz.widget.renderer.VisualTheme;
 
@@ -379,4 +381,20 @@ public class CommonEvents {
         return "success";
     }
 
+    public static String loadJWT(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
+        Delegator delegator = (Delegator) request.getAttribute("delegator");
+        Map<String, String> types = new HashMap<>();
+        String webAppName = UtilHttp.getApplicationName(request);
+        String securedUserLoginId = LoginWorker.getSecuredUserLoginId(request, webAppName);
+        if (securedUserLoginId != null) {
+            types.put("userLoginId", securedUserLoginId);
+            int ttlSeconds =  (int) Long.parseLong(EntityUtilProperties.getPropertyValue("security", "security.jwt.token.expireTime", "10", delegator));
+            String token = JWTManager.createJwt(delegator, types, ttlSeconds);
+            writeJSONtoResponse(JSON.from(token), request, response);
+        } else {
+            Debug.logWarning("No securedUserLoginId cookie was found for this application", module);
+        }
+        return "success";
+    }
+    
 }

Modified: ofbiz/ofbiz-framework/trunk/framework/common/webcommon/WEB-INF/common-controller.xml
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/common/webcommon/WEB-INF/common-controller.xml?rev=1844880&r1=1844879&r2=1844880&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/common/webcommon/WEB-INF/common-controller.xml (original)
+++ ofbiz/ofbiz-framework/trunk/framework/common/webcommon/WEB-INF/common-controller.xml Fri Oct 26 09:32:46 2018
@@ -31,6 +31,7 @@ under the License.
         <event name="checkRequestHeaderLogin" type="java" path="org.apache.ofbiz.webapp.control.LoginWorker" invoke="checkRequestHeaderLogin"/>
         <event name="checkServletRequestRemoteUserLogin" type="java" path="org.apache.ofbiz.webapp.control.LoginWorker" invoke="checkServletRequestRemoteUserLogin"/>
         <event name="checkExternalLoginKey" type="java" path="org.apache.ofbiz.webapp.control.ExternalLoginKeysManager" invoke="checkExternalLoginKey"/>
+        <event name="checkJWTLogin" type="java" path="org.apache.ofbiz.webapp.control.ExternalLoginKeysManager" invoke="checkJWTLogin"/>
         <event name="checkProtectedView" type="java" path="org.apache.ofbiz.webapp.control.ProtectViewWorker" invoke="checkProtectedView"/>
         <event name="extensionConnectLogin" type="java" path="org.apache.ofbiz.webapp.control.LoginWorker" invoke="extensionConnectLogin"/>
     </preprocessor>
@@ -269,6 +270,14 @@ under the License.
         <response name="success" type="none" />
         <response name="error" type="none" />
     </request-map>
+
+    <!-- Common JavaScript loadJWT Request, to receive JwtToken within regular JS Code -->
+    <request-map uri="loadJWT">
+        <security https="true" auth="false"/>
+        <event type="java" path="org.apache.ofbiz.common.CommonEvents" invoke="loadJWT"/>
+        <response name="success" type="none" />
+        <response name="error" type="none" />
+    </request-map>
 
     <!-- Check if an UomConversion exists -->
     <request-map uri="checkUomConversion">

Modified: ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties?rev=1844880&r1=1844879&r2=1844880&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties (original)
+++ ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties Fri Oct 26 09:32:46 2018
@@ -139,3 +139,6 @@ security.login.externalLoginKey.enabled=
 
 # -- Security key used to encrypt and decrypt the autogenerated password in forgot password functionality.
 login.secret_key_string=Secret Key
+
+# -- Time To Live of the token send to the external server in seconds, 10 seconds seems plenty enough OOTB. Custom projects might want set a lower value.
+security.jwt.token.expireTime=10

Modified: ofbiz/ofbiz-framework/trunk/framework/webapp/src/docs/asciidoc/_include/wa-cross-domains-SSO.adoc
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/webapp/src/docs/asciidoc/_include/wa-cross-domains-SSO.adoc?rev=1844880&r1=1844879&r2=1844880&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/webapp/src/docs/asciidoc/_include/wa-cross-domains-SSO.adoc (original)
+++ ofbiz/ofbiz-framework/trunk/framework/webapp/src/docs/asciidoc/_include/wa-cross-domains-SSO.adoc Fri Oct 26 09:32:46 2018
@@ -55,6 +55,9 @@ The mechanism is simple.
 
 . The checkJWTLogin preprocessor, similar to the checkExternalLoginKey, intercepts the JWT, checks it and if all is OK signs the user on. That's it !
 
+In the example component, the FormWidgetExamples screen contains 2 new fields in the LinksExampleForm which demonstrate the use from a local instance to the trunk demo instance.
+
+
 If you are interested in more details you may refer to  https://issues.apache.org/jira/browse/OFBIZ-10307
 
 

Modified: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java?rev=1844880&r1=1844879&r2=1844880&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java (original)
+++ ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java Fri Oct 26 09:32:46 2018
@@ -18,10 +18,13 @@
  */
 package org.apache.ofbiz.webapp.control;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 
+import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
@@ -29,8 +32,11 @@ import javax.servlet.http.HttpSession;
 import org.apache.ofbiz.base.util.Debug;
 import org.apache.ofbiz.entity.Delegator;
 import org.apache.ofbiz.entity.DelegatorFactory;
+import org.apache.ofbiz.entity.GenericEntityException;
 import org.apache.ofbiz.entity.GenericValue;
+import org.apache.ofbiz.entity.util.EntityQuery;
 import org.apache.ofbiz.service.LocalDispatcher;
+import org.apache.ofbiz.service.ModelService;
 import org.apache.ofbiz.webapp.WebAppUtil;
 
 /**
@@ -96,9 +102,10 @@ public class ExternalLoginKeysManager {
 
     /**
      * OFBiz controller event that performs the user authentication using the authentication token.
-     * The methods is designed to be used in a chain of controller preprocessor event: it always return &amp;success&amp;
+     * The method is designed to be used in a chain of controller preprocessor event: it always return "success"
      * even when the authentication token is missing or the authentication fails in order to move the processing to the
      * next event in the chain.
+
      *
      * @param request - the http request object
      * @param response - the http response object
@@ -126,6 +133,9 @@ public class ExternalLoginKeysManager {
             GenericValue currentUserLogin = (GenericValue) session.getAttribute("userLogin");
             if (currentUserLogin != null) {
                 if (currentUserLogin.getString("userLoginId").equals(userLogin.getString("userLoginId"))) {
+                    // Create a secured cookie the client cookie with the correct userLoginId
+                    LoginWorker.createSecuredLoginIdCookie(request, response);
+                    
                     // same user, just make sure the autoUserLogin is set to the same and that the client cookie has the correct userLoginId
                     LoginWorker.autoLoginSet(request, response);
                     return "success";
@@ -150,5 +160,138 @@ public class ExternalLoginKeysManager {
     private static boolean isAjax(HttpServletRequest request) {
        return "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
     }
+
+    /**
+    * OFBiz controller preprocessor event
+    * The method is designed to be used in a chain of controller preprocessor event: it always return "success"
+    * even when the Authorization token is missing or the Authorization fails.
+    * This in order to move the processing to the next event in the chain.
+    *
+    * This works in a similar same way than externalLoginKey but between 2 servers on 2 different domains,
+    * not 2 webapps on the same server.
+    *  
+    * The Single Sign On (SSO) is ensured by a JWT token,
+    * then all is handled as normal by a session on the reached server.
+    *  
+    * The servers may or may not share a database but the 2 loginUserIds must be the same.
+    *
+    * In case of a multitenancy usage, the tenant is verified.
+    * @param request The HTTPRequest object for the current request
+    * @param response The HTTPResponse object for the current request
+    * @return String "success"
+    */
+    public static String checkJWTLogin(HttpServletRequest request, HttpServletResponse response) {
+        Delegator delegator = (Delegator) request.getAttribute("delegator");
+
+        Map<String, Object> result = null;
+        String authorizationHeader = request.getHeader("Authorization");
+        if (authorizationHeader == null) {
+            // No Authorization header, no need to continue, most likely case.
+            return "success";
+        }
+
+        result = jwtValidation(delegator, authorizationHeader);
+        if (result.containsKey(ModelService.ERROR_MESSAGE)) {
+            // The JWT is wrong somehow, stop the process, details are in log
+            return "success";
+        }
+
+        GenericValue userLogin = getUserlogin(delegator, result);
+        if (userLogin == null) {
+            // No UserLogin GenericValue could be retrieved, stop the process, details are in log
+            return "success";
+        }
+
+        checkTenant(request, response, delegator, userLogin);
+
+        if (!storeUserlogin(userLogin)) {
+            // We could not store the UserLogin GenericValue (very unlikely), stop the process, details are in log
+            return "success";
+        }
+
+        LoginWorker.doBasicLogin(userLogin, request);
+        return "success";
+    }
+
+    /**
+     * Checks it's the right tenant in case username and password are the same in different tenants
+     * If not, sets the necessary session attributes
+     * @param request The HTTPRequest object for the current request
+     * @param response The HTTPResponse object for the current request
+     * @param delegator The current delegator
+     * @param userLogin The GenericValue object of userLogin to check
+     */
+    private static void checkTenant(HttpServletRequest request, HttpServletResponse response, Delegator delegator,
+            GenericValue userLogin) {
+        //
+        //
+
+        LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
+        String oldDelegatorName = delegator.getDelegatorName();
+        ServletContext servletContext = request.getSession().getServletContext();
+        if (!oldDelegatorName.equals(userLogin.getDelegator().getDelegatorName())) {
+            delegator = DelegatorFactory.getDelegator(userLogin.getDelegator().getDelegatorName());
+            dispatcher = WebAppUtil.makeWebappDispatcher(servletContext, delegator);
+            LoginWorker.setWebContextObjects(request, response, delegator, dispatcher);
+        }
+    }
+
+    /**
+     * Stores the userLogin in DB. If it fails log an error message
+     * @param userLogin The userLogin GenericValue to store
+     * @return boolean True if it works, log an error message if it fails
+     */
+    private static boolean storeUserlogin(GenericValue userLogin) {
+        String enabled = userLogin.getString("enabled");
+        if (enabled == null || "Y".equals(enabled)) {
+            userLogin.set("hasLoggedOut", "N");
+            try {
+                userLogin.store();
+            } catch (GenericEntityException e) {
+                Debug.logError(e, "Cannot store UserLogin information: " + e.getMessage(), module);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Gets the userLogin from the userLoginId in the result of the JWT validation
+     * If it fails, log a warning or error message  
+     * @param delegator The current delegator
+     * @param jwtMap Map of name, value pairs composing the result of the JWT validation
+     * @return userLogin The userLogin GenericValue extracted from DB
+     */
+    private static GenericValue getUserlogin(Delegator delegator, Map<String, Object> jwtMap) {
+        String userLoginId = (String) jwtMap.get("userLoginId");
+        GenericValue userLogin = null;
+        try {
+            userLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", userLoginId).queryOne();
+            if (userLogin == null) {
+                Debug.logWarning("*** There was a problem with the JWT token. Could not find userLogin " + userLoginId, module);
+            }
+        } catch (GenericEntityException e) {
+            Debug.logError(e, "Cannot get UserLogin information: " + e.getMessage(), module);
+        }
+        return userLogin;
+    }
+
+    /**
+     * Validate the token usingJWTManager::validateToken
+     * If it fails, returns a ModelService.ERROR_MESSAGE in the result
+     * @param delegator The current delegator
+     * @param authorizationHeader The JWT which normally contains the userLoginId
+     * @param result  Map of name, value pairs composing the result
+     */
+    private static Map<String, Object> jwtValidation(Delegator delegator, String authorizationHeader) {
+        Map<String, Object> result;
+        List<String> types = Arrays.asList("userLoginId");
+        result = JWTManager.validateToken(delegator, authorizationHeader, types);
+        if (result.containsKey(ModelService.ERROR_MESSAGE)) {
+            // Something unexpected happened here  
+            Debug.logWarning("*** There was a problem with the JWT, not signin in the user login ", module);
+        }        
+        return result;
+    }
     
 }

Modified: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java?rev=1844880&r1=1844879&r2=1844880&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java (original)
+++ ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java Fri Oct 26 09:32:46 2018
@@ -29,7 +29,6 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.ServiceLoader;
 import java.util.regex.Matcher;
@@ -61,7 +60,6 @@ import org.apache.ofbiz.base.util.UtilVa
 import org.apache.ofbiz.entity.Delegator;
 import org.apache.ofbiz.entity.DelegatorFactory;
 import org.apache.ofbiz.entity.EntityCryptoException;
-import org.apache.ofbiz.entity.GenericEntity;
 import org.apache.ofbiz.entity.GenericEntityException;
 import org.apache.ofbiz.entity.GenericValue;
 import org.apache.ofbiz.entity.condition.EntityCondition;
@@ -580,7 +578,7 @@ public class LoginWorker {
                 Debug.logError(e, "Error setting user preference", module);
             }
             // start with a clean state, in case the user has quit the session w/o login out
-            autoLogoutCleanCookies(userLogin, request, response);
+            autoLogoutCleanCookies(request, response);
             
             // finally do the main login routine to set everything else up in the session, etc
             return doMainLogin(request, response, userLogin, userLoginSession);
@@ -792,6 +790,9 @@ public class LoginWorker {
         RequestHandler rh = RequestHandler.getRequestHandler(request.getSession().getServletContext());
         rh.runAfterLoginEvents(request, response);
 
+        // Create a secured cookie the client cookie with the correct userLoginId
+        createSecuredLoginIdCookie(request, response);
+
         // make sure the autoUserLogin is set to the same and that the client cookie has the correct userLoginId
         return autoLoginSet(request, response);
     }
@@ -849,7 +850,7 @@ public class LoginWorker {
 
         doBasicLogout(userLogin, request, response);
         
-        autoLogoutCleanCookies(userLogin, request, response);
+        autoLogoutCleanCookies(request, response);
         if (request.getAttribute("_AUTO_LOGIN_LOGOUT_") == null) {
             return autoLoginCheck(request, response);
         }
@@ -930,24 +931,38 @@ public class LoginWorker {
             autoLoginCookie.setSecure(true);
             autoLoginCookie.setHttpOnly(true);
             response.addCookie(autoLoginCookie);
+            
             return autoLoginCheck(delegator, session, userLogin.getString("userLoginId"));
         } else {
             return "success";
         }
     }
 
+    public static void createSecuredLoginIdCookie(HttpServletRequest request, HttpServletResponse response) {
+        Delegator delegator = (Delegator) request.getAttribute("delegator");
+        HttpSession session = request.getSession();
+        GenericValue userLogin = (GenericValue) session.getAttribute("userLogin");
+        String domain = EntityUtilProperties.getPropertyValue("url", "cookie.domain", delegator);
+        if (userLogin != null) {
+            String webappName = UtilHttp.getApplicationName(request);
+            Cookie securedLoginIdCookie = new Cookie(getSecuredLoginIdCookieName(webappName), userLogin.getString("userLoginId"));
+            securedLoginIdCookie.setMaxAge(60 * 60 * 24 * 365);
+            securedLoginIdCookie.setDomain(domain);
+            securedLoginIdCookie.setPath("/");
+            securedLoginIdCookie.setSecure(true);
+            securedLoginIdCookie.setHttpOnly(true);
+            response.addCookie(securedLoginIdCookie);
+        }
+    }
+
     protected static String getAutoLoginCookieName(HttpServletRequest request) {
         return UtilHttp.getApplicationName(request) + ".autoUserLoginId";
     }
 
-    protected static String getAutoLoginCookieName(String webappName) {
-        return webappName + ".autoUserLoginId";
+    protected static String getSecuredLoginIdCookieName(String webappName) {
+        return webappName + ".securedLoginId";
     }
     
-    /**
-    * @deprecated Moved to {@link org.apache.ofbiz.webapp.control.LoginWorker#getAutoUserLoginId(HttpServletRequest request, String webappName) String}
-    */
-   @Deprecated
     public static String getAutoUserLoginId(HttpServletRequest request) {
         String autoUserLoginId = null;
         Cookie[] cookies = request.getCookies();
@@ -965,22 +980,22 @@ public class LoginWorker {
         return autoUserLoginId;
     }
     
-    public static String getAutoUserLoginId(HttpServletRequest request, String webappName) {
-        String autoUserLoginId = null;
+    public static String getSecuredUserLoginId(HttpServletRequest request, String webappName) {
+        String securedUserLoginId = null;
         Cookie[] cookies = request.getCookies();
         if (Debug.verboseOn()) {
             Debug.logVerbose("Cookies: " + Arrays.toString(cookies), module);
         }
-        if (cookies != null) {
+        if (cookies != null && webappName !=null) {
             for (Cookie cookie: cookies) {
-                String cookieName = (webappName != null) ? getAutoLoginCookieName(webappName) : getAutoLoginCookieName(request);
+                String cookieName = getSecuredLoginIdCookieName(webappName);
                 if (cookie.getName().equals(cookieName)) {
-                    autoUserLoginId = cookie.getValue();
+                    securedUserLoginId = cookie.getValue();
                     break;
                 }
             }
         }
-        return autoUserLoginId;
+        return securedUserLoginId;
     }
 
 
@@ -988,7 +1003,7 @@ public class LoginWorker {
         Delegator delegator = (Delegator) request.getAttribute("delegator");
         HttpSession session = request.getSession();
 
-        return autoLoginCheck(delegator, session, getAutoUserLoginId(request, null));
+        return autoLoginCheck(delegator, session, getAutoUserLoginId(request));
     }
 
     private static String autoLoginCheck(Delegator delegator, HttpSession session, String autoUserLoginId) {
@@ -1043,15 +1058,15 @@ public class LoginWorker {
         return "success";
     }
     
-    // Removes all the autoLoginCookies but if the webapp requires keeping it
-    public static String autoLogoutCleanCookies(GenericValue userLogin, HttpServletRequest request, HttpServletResponse response) {
+    // Removes all autoLoginCookies but if the webapp requires keeping it
+    public static String autoLogoutCleanCookies(HttpServletRequest request, HttpServletResponse response) {
         HttpSession session = request.getSession();
 
         Cookie[] cookies = request.getCookies();
         if (Debug.verboseOn()) {
             Debug.logVerbose("Cookies: " + Arrays.toString(cookies), module);
         }
-        if (cookies != null && userLogin != null) {
+        if (cookies != null) {
             for (Cookie autoLoginCookie: cookies) {
                 String autoLoginName = autoLoginCookie.getName().replace(".autoUserLoginId", "");
                 WebappInfo webappInfo = ComponentConfig.getWebappInfo("default-server", autoLoginName);
@@ -1068,9 +1083,30 @@ public class LoginWorker {
         session.removeAttribute("autoName");
 
         request.setAttribute("_AUTO_LOGIN_LOGOUT_", Boolean.TRUE);
+        clearSecuredUserLoginIdCookies(request, response);
         return "success";
     }
 
+    // Removes all securedLoginIdCookies
+    public static void clearSecuredUserLoginIdCookies(HttpServletRequest request, HttpServletResponse response) {
+
+        Cookie[] cookies = request.getCookies();
+        if (Debug.verboseOn()) {
+            Debug.logVerbose("Cookies: " + Arrays.toString(cookies), module);
+        }
+        if (cookies != null) {
+            for (Cookie securedLoginIdCookie: cookies) {
+                String securedLoginIdName = securedLoginIdCookie.getName().replace(".securedLoginId", "");
+                WebappInfo webappInfo = ComponentConfig.getWebappInfo("default-server", securedLoginIdName);
+                if (webappInfo != null) {
+                    securedLoginIdCookie.setMaxAge(0);
+                    securedLoginIdCookie.setPath("/");
+                    response.addCookie(securedLoginIdCookie);
+                }
+            }
+        }
+    }
+
     public static boolean isUserLoggedIn(HttpServletRequest request) {
         HttpSession session = request.getSession();
         GenericValue currentUserLogin = (GenericValue) session.getAttribute("userLogin");
@@ -1176,6 +1212,7 @@ public class LoginWorker {
 
         return "success";
     }
+    
     // preprocessor method to login a user w/ client certificate see security.properties to configure the pattern of CN
     public static String check509CertLogin(HttpServletRequest request, HttpServletResponse response) {
         Delegator delegator = (Delegator) request.getAttribute("delegator");
@@ -1439,7 +1476,7 @@ public class LoginWorker {
     /**
      * Return true if userLogin has not been disabled
      * @param userLogin
-     * @return
+     * @return boolean
      */
     public static boolean isUserLoginActive(GenericValue userLogin) {
         return !"N".equals(userLogin.getString("enabled")) && UtilValidate.isEmpty(userLogin.getString("disabledBy"));

Modified: ofbiz/ofbiz-framework/trunk/themes/common-theme/webapp/common/js/util/OfbizUtil.js
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/themes/common-theme/webapp/common/js/util/OfbizUtil.js?rev=1844880&r1=1844879&r2=1844880&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/themes/common-theme/webapp/common/js/util/OfbizUtil.js (original)
+++ ofbiz/ofbiz-framework/trunk/themes/common-theme/webapp/common/js/util/OfbizUtil.js Fri Oct 26 09:32:46 2018
@@ -1206,3 +1206,36 @@ function submitPagination(obj, url) {
         }
     }
 }
+function loadJWT(webAppName) {
+    var JwtToken = "";
+    jQuery.ajax({
+        url: "loadJWT",
+        type: "POST",
+        async: false,
+        dataType: "text",
+        success: function(response) {
+            JwtToken = response;
+        },
+        error: function(textStatus, errorThrown){
+            alert('Failure, errorThrown: ' + errorThrown);
+        }
+    });
+    return JwtToken;
+}
+
+function sendJWT(webAppName, targetUrl) {
+    var redirectUrl = targetUrl;
+    var jwtToken = loadJWT(webAppName);
+    if (jwtToken != null && jwtToken != "") {
+        jQuery.ajax({
+            url: targetUrl,
+            async: false,
+            type: 'POST',
+            xhrFields: {withCredentials: true},
+            headers: {"Authorization" : jwtToken},
+            success: function(){
+                window.location.assign(redirectUrl);
+            }
+        });
+    }
+}

Modified: ofbiz/ofbiz-plugins/trunk/example/config/ExampleUiLabels.xml
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-plugins/trunk/example/config/ExampleUiLabels.xml?rev=1844880&r1=1844879&r2=1844880&view=diff
==============================================================================
--- ofbiz/ofbiz-plugins/trunk/example/config/ExampleUiLabels.xml (original)
+++ ofbiz/ofbiz-plugins/trunk/example/config/ExampleUiLabels.xml Fri Oct 26 09:32:46 2018
@@ -1204,6 +1204,18 @@
         <value xml:lang="en">Set PDF Protected By Password</value>
         <value xml:lang="zh">设置有密码保护的PDF</value>
     </property>
+    <property key="password_not_equal_confirm_password">
+        <value xml:lang="en">Password did not match confirm password.</value>
+        <value xml:lang="zh">密码与验证密码不一致。</value>
+    </property>
+    <property key="SignedInAuthToAnotherDomain">
+        <value xml:lang="en">Navigate to another domain with automated signed in authentication</value>
+        <value xml:lang="fr">Naviguer vers un autre domaine avec authentification automatique</value>
+    </property>
+    <property key="TargetURL">
+        <value xml:lang="en">Target URL</value>
+        <value xml:lang="fr">URL cible</value>
+    </property>
     <property key="YouChangedTheSelectBoxValue">
         <value xml:lang="de">Sie haben den Wert in der Select Box geändert.</value>
         <value xml:lang="en">You have changed the value in the select box</value>
@@ -1211,8 +1223,4 @@
         <value xml:lang="zh">你修改了选择框中的值</value>
         <value xml:lang="zh-TW">你修改了選擇框中的值</value>
     </property>
-    <property key="password_not_equal_confirm_password">
-        <value xml:lang="en">Password did not match confirm password.</value>
-        <value xml:lang="zh">密码与验证密码不一致。</value>
-    </property>
 </resource>
\ No newline at end of file

Modified: ofbiz/ofbiz-plugins/trunk/example/widget/example/FormWidgetExampleForms.xml
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-plugins/trunk/example/widget/example/FormWidgetExampleForms.xml?rev=1844880&r1=1844879&r2=1844880&view=diff
==============================================================================
--- ofbiz/ofbiz-plugins/trunk/example/widget/example/FormWidgetExampleForms.xml (original)
+++ ofbiz/ofbiz-plugins/trunk/example/widget/example/FormWidgetExampleForms.xml Fri Oct 26 09:32:46 2018
@@ -424,6 +424,9 @@ under the License.
         <!-- ************************ -->
         <!-- ***   Layered-modal  *** -->
         <!-- ************************ -->
+        <actions>
+            <set field="targetUrl" value="javascript:sendJWT('${webappName}', 'https://demo-trunk.ofbiz.apache.org/content/control/main')"/>
+        </actions>
         <field name="emptyField0" title=" "><display/></field>
         <field name="newExample" title=" " widget-area-style="smallSubmit" position="1">
             <hyperlink description="${uiLabelMap.ExampleNewExample} (Layered-modal)" target="EditExampleLayer" also-hidden="false" link-type="layered-modal"/>
@@ -431,8 +434,11 @@ under the License.
         <field name="deleteLink" title="${uiLabelMap.FormFieldTitle_confirmButton} ${uiLabelMap.ExampleExample}" widget-style="buttontext">
             <hyperlink description="${uiLabelMap.CommonDelete}" target="FormWidgetExamples" also-hidden="false" confirmation-message="Are you sure you want to perform this action?"/>
         </field>
-    </form>
-
+        <field name="targetUrlButton" title="${uiLabelMap.SignedInAuthToAnotherDomain}" widget-style="buttontext">
+            <hyperlink also-hidden="false" target-type="plain" description="${uiLabelMap.TargetURL}" target="${targetUrl}"/>
+        </field>
+     </form>
+
     <form name="MaskFieldExampleForm" type="single">
         <field name="maskField" title="${uiLabelMap.ExampleField}"><text mask='a*-999-a999'/></field>
     </form>