Re: 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
|

Re: 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...

taher
For the record I did not review and approve, I had concerns and they
are noted in the JIRA
On Fri, Oct 26, 2018 at 12:32 PM <[hidden email]> wrote:

>
> 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>
>
>