diff --git applications/party/template/party/profileblocks/UserLogin.ftl applications/party/template/party/profileblocks/UserLogin.ftl
index bee922f209..b1a197916b 100644
--- applications/party/template/party/profileblocks/UserLogin.ftl
+++ applications/party/template/party/profileblocks/UserLogin.ftl
@@ -53,6 +53,9 @@ under the License.
                 <#if security.hasEntityPermission("SECURITY", "_VIEW", session)>
                   <a href="<@ofbizUrl>ProfileEditUserLoginSecurityGroups?partyId=${party.partyId}&amp;userLoginId=${userUserLogin.userLoginId}</@ofbizUrl>">${uiLabelMap.SecurityGroups}</a>
                 </#if>
+                <#if security.hasEntityPermission("IMPERSONATE", "_ADMIN", session)>
+                    <a href="<@ofbizUrl>impersonateLogin?userLoginIdToImpersonate=${userUserLogin.userLoginId}</@ofbizUrl>">${uiLabelMap.CommonImpersonate}</a>
+                </#if>
               </td>
             </tr>
           </#list>
diff --git applications/party/template/party/profileblocks/Visits.ftl applications/party/template/party/profileblocks/Visits.ftl
index 3f2486bc03..54f49fb5f8 100644
--- applications/party/template/party/profileblocks/Visits.ftl
+++ applications/party/template/party/profileblocks/Visits.ftl
@@ -31,6 +31,7 @@ under the License.
           <tr class="header-row">
             <td>${uiLabelMap.PartyVisitId}</td>
             <td>${uiLabelMap.PartyUserLogin}</td>
+            <td>${uiLabelMap.CommonImpersonateUserLogin}</td>
             <td>${uiLabelMap.PartyNewUser}</td>
             <td>${uiLabelMap.PartyWebApp}</td>
             <td>${uiLabelMap.PartyClientIP}</td>
@@ -39,11 +40,16 @@ under the License.
           </tr>
           <#list visits as visitObj>
             <#if (visitObj_index > 4)><#break></#if>
+            <#assign userLoginHistory = EntityQuery.use(delegator).from("UserLoginHistory").where('visitId',visitObj.visitId!).queryFirst()!>
+            <#if userLoginHistory??>
+                <#assign impersonateUserLoginId = userLoginHistory.originUserLoginId!>
+            </#if>
               <tr>
                 <td class="button-col">
                   <a href="<@ofbizUrl>visitdetail?visitId=${visitObj.visitId!}</@ofbizUrl>">${visitObj.visitId!}</a>
                 </td>
                 <td>${visitObj.userLoginId!}</td>
+                <td>${impersonateUserLoginId!}</td>
                 <td>${visitObj.userCreated!}</td>
                 <td>${visitObj.webappName!}</td>
                 <td>${visitObj.clientIpAddress!}</td>
diff --git applications/party/widget/partymgr/PartyMenus.xml applications/party/widget/partymgr/PartyMenus.xml
index 603a13ec14..c45ca6b77b 100644
--- applications/party/widget/partymgr/PartyMenus.xml
+++ applications/party/widget/partymgr/PartyMenus.xml
@@ -772,5 +772,11 @@
             </link>
         </menu-item>
     </menu>
-    
+    <menu name="listAllVisits">
+        <menu-item name="listAll" title="${uiLabelMap.CommonListAll}">
+            <link target="findVisits">
+                <parameter param-name="partyId" from-field="parameters.partyId"/>
+            </link>
+        </menu-item>
+    </menu>
 </menus>
diff --git applications/party/widget/partymgr/PartyVisitForms.xml applications/party/widget/partymgr/PartyVisitForms.xml
index c4120db184..a6f9d234fc 100644
--- applications/party/widget/partymgr/PartyVisitForms.xml
+++ applications/party/widget/partymgr/PartyVisitForms.xml
@@ -41,7 +41,6 @@ under the License.
         odd-row-style="alternate-row" header-row-style="header-row-2" default-table-style="basic-table hover-bar">
         <actions>
             <set field="parameters.sortField" from-field="parameters.sortField" default-value="-visitId"/>
-
             <service service-name="performFind" result-map="result" result-map-list="listIt">
                 <field-map field-name="inputFields" from-field="parameters"/>
                 <field-map field-name="entityName" value="Visit"/>
@@ -51,7 +50,15 @@ under the License.
                 <field-map field-name="filterByDate" from-field="parameters.activeOnly"/>
             </service>
         </actions>
-        
+        <row-actions>
+            <entity-condition entity-name="UserLoginHistory" list="userLoginHistoryList">
+                <condition-list>
+                    <condition-expr field-name="visitId" from-field="visitId"/>
+                </condition-list>
+                <select-field field-name="userLoginId"/>
+            </entity-condition>
+            <set field="impersonateUserLoginId" from-field="userLoginHistoryList[0].originUserLoginId" type="String"/>
+        </row-actions>
         <field name="visitId" widget-style="buttontext" sort-field="true">
             <hyperlink description="${visitId}" target="visitdetail">
                 <parameter param-name="visitId"/>
@@ -64,6 +71,7 @@ under the License.
             </hyperlink>
         </field>
         <field name="userLoginId" title="${uiLabelMap.CommonUserLoginId}" sort-field="true"><display/></field>
+        <field name="impersonateUserLoginId" title="${uiLabelMap.CommonImpersonateUserLogin}"><display/></field>
         <field name="userCreated" title="${uiLabelMap.PartyNewUser}" sort-field="true"><display/></field>
         <field name="webappName" title="${uiLabelMap.PartyWebApp}" sort-field="true"><display/></field>
         <field name="clientIpAddress" title="${uiLabelMap.PartyClientIP}" sort-field="true"><display/></field>
diff --git framework/common/config/CommonUiLabels.xml framework/common/config/CommonUiLabels.xml
index fcc5fd8c17..149a0725db 100644
--- framework/common/config/CommonUiLabels.xml
+++ framework/common/config/CommonUiLabels.xml
@@ -5533,6 +5533,22 @@
         <value xml:lang="zh">图片</value>
         <value xml:lang="zh-TW">圖片</value>
     </property>
+    <property key="CommonImpersonate">
+        <value xml:lang="en">Impersonate</value>
+        <value xml:lang="fr">Incarner</value>
+    </property>
+    <property key="CommonImpersonateUserLogin">
+        <value xml:lang="en">User impersonated</value>
+        <value xml:lang="fr">Utilisateur incarné</value>
+    </property>
+    <property key="CommonImpersonateTitle">
+        <value xml:lang="en">Impersonation in process</value>
+        <value xml:lang="fr">Incarnation en cours</value>
+    </property>
+    <property key="CommonImpersonateStop">
+        <value xml:lang="en">Stop impersonation</value>
+        <value xml:lang="fr">Arrêter l'incarnation</value>
+    </property>
     <property key="CommonImport">
         <value xml:lang="en">Import</value>
         <value xml:lang="zh">导入</value>
@@ -8239,6 +8255,13 @@
         <value xml:lang="zh">机构图标</value>
         <value xml:lang="zh-TW">機構商標</value>
     </property>
+    <property key="CommonOriginUserLoginId">
+        <value xml:lang="de">Herkunft Benutzeranmeldung ID</value>
+        <value xml:lang="en">Origin User Login ID</value>
+        <value xml:lang="es">Código de usuario de origen</value>
+        <value xml:lang="fr">Identifiant de connexion d'origine</value>
+        <value xml:lang="it">Codice utente di origine</value>
+    </property>
     <property key="CommonOther">
         <value xml:lang="ar">أخرى</value>
         <value xml:lang="cs">Jiný(á)</value>
diff --git framework/common/config/SecurityextUiLabels.xml framework/common/config/SecurityextUiLabels.xml
index 7de0db2def..0f27a62e7c 100644
--- framework/common/config/SecurityextUiLabels.xml
+++ framework/common/config/SecurityextUiLabels.xml
@@ -107,6 +107,14 @@
         <value xml:lang="zh">登录时发生下列错误：${errorMessage}</value>
         <value xml:lang="zh-TW">登入時發生錯誤: ${errorMessage}.</value>
     </property>
+    <property key="loginevents.impersonate_yourself">
+        <value xml:lang="en">You can't impersonate yourself ... What are you trying to do ?</value>
+        <value xml:lang="fr">Vous ne pouvez pas vous incarner vous même ... Qu'essayez-vous donc de faire ?</value>
+    </property>
+    <property key="loginevents.impersonate_needsFullAdmin">
+        <value xml:lang="en">You need to be in FULLADMIN security group to impersonate another login at that permission level</value>
+        <value xml:lang="fr">Vous devez être dans le groupe de sécurité FULLADMIN pour incarner un autre identifiant avec ce niveau de permission</value>
+    </property>
     <property key="loginevents.new_password_createdandsent_check_email">
         <value xml:lang="de">Ein neues Passwort wurde erzeugt und Ihnen per E-Mail zugeschickt. Überprüfen Sie bitte Ihren E-Mail-Eingang.</value>
         <value xml:lang="en">A new password has been created and sent to you. Please check your Email.</value>
@@ -245,6 +253,10 @@
         <value xml:lang="en">Problem getting User Login Security Question record.</value>
         <value xml:lang="fr">Problème durant la lecture de votre question de sécurité</value>
     </property>
+    <property key="loginevents.origin_username_is_present">
+        <value xml:lang="en">You already have an impersonation in process. Please leave it before continue</value>
+        <value xml:lang="fr">Vous avez déjà une incarnation en cours, veuillez mettre fin à celle-ci avant de continuer</value>
+    </property>
     <property key="loginevents.unable_to_login_tenant">
         <value xml:lang="en">You cannot login to this tenant</value>
         <value xml:lang="es">No puede conectarse con esta organización</value>
diff --git framework/common/data/CommonSecurityGroupDemoData.xml framework/common/data/CommonSecurityGroupDemoData.xml
index 62b91d67ef..0f91c425c5 100644
--- framework/common/data/CommonSecurityGroupDemoData.xml
+++ framework/common/data/CommonSecurityGroupDemoData.xml
@@ -40,4 +40,9 @@
 
     <!-- Temporal expression security -->
     <SecurityGroupPermission fromDate="2001-05-13 12:00:00.0" groupId="FULLADMIN" permissionId="TEMPEXPR_ADMIN"/>
+
+    <!-- Impersonation security -->
+    <SecurityGroupPermission fromDate="2001-05-13 12:00:00.0" groupId="FULLADMIN" permissionId="IMPERSONATE_ADMIN"/>
+    <SecurityGroupPermission fromDate="2001-05-13 12:00:00.0" groupId="IMPERSONATION" permissionId="IMPERSONATE_ADMIN"/>
+    <SecurityGroupPermission fromDate="2001-05-13 12:00:00.0" groupId="IMPERSONATION" permissionId="SECURITY_VIEW"/>
 </entity-engine-xml>
diff --git framework/common/data/CommonSecurityPermissionSeedData.xml framework/common/data/CommonSecurityPermissionSeedData.xml
index 5ea573fcfd..0d69d81bc4 100644
--- framework/common/data/CommonSecurityPermissionSeedData.xml
+++ framework/common/data/CommonSecurityPermissionSeedData.xml
@@ -36,12 +36,15 @@
 
     <!-- Temporal expression security -->
     <SecurityPermission description="Temporal expression admin" permissionId="TEMPEXPR_ADMIN"/>
-    
+    <!-- Impersonation security -->
+    <SecurityPermission description="Admin Impersonation operation" permissionId="IMPERSONATE_ADMIN"/>
+
     <!-- exception for SUPER user and group shoul be loaded as seed-->
     <SecurityGroupPermission fromDate="2001-05-13 12:00:00.0" groupId="SUPER" permissionId="COMMON_ADMIN"/>
     <SecurityGroupPermission fromDate="2001-05-13 12:00:00.0" groupId="SUPER" permissionId="PORTALPAGE_ADMIN"/>
     <SecurityGroupPermission fromDate="2001-05-13 12:00:00.0" groupId="SUPER" permissionId="VISUALTHEME_ADMIN"/>
     <SecurityGroupPermission fromDate="2001-05-13 12:00:00.0" groupId="SUPER" permissionId="USERPREF_ADMIN"/>
     <SecurityGroupPermission fromDate="2001-05-13 12:00:00.0" groupId="SUPER" permissionId="TEMPEXPR_ADMIN"/>
-    
+    <SecurityGroupPermission fromDate="2001-05-13 12:00:00.0" groupId="SUPER" permissionId="IMPERSONATE_ADMIN"/>
+
 </entity-engine-xml>
diff --git framework/common/servicedef/services.xml framework/common/servicedef/services.xml
index 348bebaba9..083f81d5d5 100644
--- framework/common/servicedef/services.xml
+++ framework/common/servicedef/services.xml
@@ -381,6 +381,18 @@ under the License.
         <implements service="authenticationInterface"/>
         <attribute name="request" mode="IN" type="javax.servlet.http.HttpServletRequest" optional="true"/>
     </service>
+    <service name="userImpersonate" engine="java" location="org.apache.ofbiz.common.login.LoginServices" invoke="userImpersonate" auth="true">
+        <description>Used to Automatically Authenticate a username/password; create a UserLogin object</description>
+        <required-permissions join-type="AND">
+            <check-permission permission="IMPERSONATE" action="ADMIN"/>
+        </required-permissions>
+        <implements service="authenticationInterface"/>
+        <attribute name="userLoginIdToImpersonate" type="String" mode="IN"/>
+        <attribute name="visitId" type="String" mode="IN" optional="true"/>
+        <attribute name="userLogin" type="org.apache.ofbiz.entity.GenericValue" mode="OUT"/>
+        <attribute name="userLoginSession" type="java.util.Map" mode="OUT" optional="true"/>
+        <attribute name="originUserLogin" type="org.apache.ofbiz.entity.GenericValue" mode="OUT"/>
+    </service>
     <service name="createUserLogin" engine="java" auth="false"
         location="org.apache.ofbiz.common.login.LoginServices" invoke="createUserLogin">
         <description>Create a UserLogin</description>
diff --git framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java
index 43e50d95b1..00d23f5710 100644
--- framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java
+++ framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java
@@ -435,6 +435,91 @@ public class LoginServices {
         return result;
     }
 
+    /**
+     * Login service to authenticate no external auth username without password, storing history
+     *
+     * @return Map of results including (userLogin) GenericValue object
+     */
+    public static Map<String, Object> userImpersonate(DispatchContext ctx, Map<String, ?> context) {
+        Locale locale = (Locale) context.get("locale");
+        Delegator delegator = ctx.getDelegator();
+
+        Map<String, Object> result = ServiceUtil.returnSuccess();
+
+        String userLoginIdToImpersonate = (String) context.get("userLoginIdToImpersonate");
+        GenericValue originUserLogin = (GenericValue) context.get("userLogin");
+
+        // get the visitId for the history entity
+        String visitId = (String) context.get("visitId");
+
+        if (UtilValidate.isEmpty(userLoginIdToImpersonate)) {
+            return ServiceUtil.returnError(UtilProperties.getMessage(resource, "loginservices.username_missing", locale));
+        } else {
+
+            if ("true".equalsIgnoreCase(EntityUtilProperties.getPropertyValue("security", "username.lowercase", delegator))) {
+                userLoginIdToImpersonate = userLoginIdToImpersonate.toLowerCase();
+            }
+
+            GenericValue userLogin;
+
+            try {
+                userLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", userLoginIdToImpersonate).queryOne();
+            } catch (GenericEntityException e) {
+                Debug.logError(e, module);
+                return ServiceUtil.returnError(e.getMessage());
+            }
+
+            if (userLogin != null &&
+                    originUserLogin.getString("userLoginId").equals(userLogin.getString("userLoginId"))) {
+                return ServiceUtil.returnError(UtilProperties.getMessage(resource, "loginevents.impersonate_yourself", locale));
+            }
+
+            if (userLogin != null) {
+                // Impersonate only active logins
+                if ((UtilValidate.isEmpty(userLogin.getString("enabled"))
+                        || "Y".equals(userLogin.getString("enabled")))
+                        && UtilValidate.isEmpty(userLogin.getString("disabledBy"))) {
+
+                    Map<String, Object> userLoginSessionMap = LoginWorker.getUserLoginSession(userLogin);
+
+                    // grab the hasLoggedOut flag
+                    boolean hasLoggedOut = userLogin.get("hasLoggedOut") != null && "Y".equalsIgnoreCase(userLogin.getString("hasLoggedOut"));
+
+                    // return the UserLoginSession Map
+                    if (userLoginSessionMap != null) {
+                        result.put("userLoginSession", userLoginSessionMap);
+                    }
+
+                    result.put("userLogin", userLogin);
+                    result.put("originUserLogin", originUserLogin);
+                    try {
+                        // update the hasLoggedOut flag
+                        if (hasLoggedOut) {
+                            userLogin.set("hasLoggedOut", "N");
+                            userLogin.store();
+                        }
+
+                        if ("true".equals(EntityUtilProperties.getPropertyValue("security", "store.login.history", delegator))) {
+                            Map<String, Object> ulhCreateMap = UtilMisc.toMap("userLoginId", userLoginIdToImpersonate, "visitId", visitId,
+                                    "fromDate", UtilDateTime.nowTimestamp(), "successfulLogin", "Y");
+                            ulhCreateMap.put("partyId", userLogin.get("partyId"));
+                            ulhCreateMap.put("originUserLoginId", originUserLogin.get("userLoginId"));
+                            delegator.create("UserLoginHistory", ulhCreateMap);
+                        }
+                    } catch (GenericEntityException e) {
+                        Debug.logError(e, module);
+                        return ServiceUtil.returnError(e.getMessage());
+                    }
+                } else {
+                    Map<String, Object> messageMap = UtilMisc.toMap("username", userLoginIdToImpersonate);
+                    return ServiceUtil.returnError(UtilProperties.getMessage(resource, "loginservices.account_for_user_login_id_disabled", messageMap, locale));
+                }
+            }
+        }
+
+        return result;
+    }
+
     public static void createUserLoginPasswordHistory(Delegator delegator,String userLoginId, String currentPassword) throws GenericEntityException{
         int passwordChangeHistoryLimit = 0;
         try {
diff --git framework/common/webcommon/WEB-INF/common-controller.xml framework/common/webcommon/WEB-INF/common-controller.xml
index ed52c93241..3cde470944 100644
--- framework/common/webcommon/WEB-INF/common-controller.xml
+++ framework/common/webcommon/WEB-INF/common-controller.xml
@@ -53,6 +53,18 @@ under the License.
         <response name="success" type="view" value="main"/>
         <response name="error" type="view" value="ajaxLogin"/>
     </request-map>
+    <request-map uri="impersonateLogin">
+        <security https="true" auth="true"/>
+        <event type="java" path="org.apache.ofbiz.webapp.control.LoginWorker" invoke="impersonateLogin"/>
+        <response name="success" type="view" value="main"/>
+        <response name="error" type="view-last"/>
+    </request-map>
+    <request-map uri="depersonateLogin">
+        <security https="true" auth="true"/>
+        <event type="java" path="org.apache.ofbiz.webapp.control.LoginWorker" invoke="depersonateLogin"/>
+        <response name="success" type="view" value="main"/>
+        <response name="error" type="view-last"/>
+    </request-map>
     <request-map uri="login">
         <security https="true" auth="false"/>
         <event type="java" path="org.apache.ofbiz.webapp.control.LoginWorker" invoke="login"/>
diff --git framework/security/data/SecurityGroupDemoData.xml framework/security/data/SecurityGroupDemoData.xml
index a2605e8997..bd903bcf73 100644
--- framework/security/data/SecurityGroupDemoData.xml
+++ framework/security/data/SecurityGroupDemoData.xml
@@ -25,7 +25,8 @@ under the License.
     <SecurityGroup groupId="FLEXADMIN" description="Flexible Admin group, has all granular permissions." groupName="Flex Admin"/>
     <SecurityGroup groupId="VIEWADMIN" description="Demo Admin group, has all view permissions." groupName="View Admin"/>
     <SecurityGroup groupId="BIZADMIN" description="Full Business Applications permission group, has all business app admin permissions, not technical permissions." groupName="Biz Admin"/>
-    
+    <SecurityGroup groupId="IMPERSONATION" description="Permission group to impersonate user."/>
+
     <!-- general admin tools permission -->
     <SecurityPermission description="Permission to access the Stock OFBiz Manager Applications." permissionId="OFBTOOLS_VIEW"/>
     <SecurityGroupPermission fromDate="2001-05-13 12:00:00.0" groupId="FULLADMIN" permissionId="OFBTOOLS_VIEW"/>
diff --git framework/security/entitydef/entitymodel.xml framework/security/entitydef/entitymodel.xml
index 1a056e868a..4dd7913c09 100644
--- framework/security/entitydef/entitymodel.xml
+++ framework/security/entitydef/entitymodel.xml
@@ -106,11 +106,15 @@ under the License.
       <field name="thruDate" type="date-time"></field>
       <field name="passwordUsed" type="long-varchar" encrypt="true"></field>
       <field name="successfulLogin" type="indicator"></field>
+      <field name="originUserLoginId" type="id-vlong"></field>
       <prim-key field="userLoginId"/>
       <prim-key field="fromDate"/>
       <relation type="one" fk-name="USER_LH_USER" rel-entity-name="UserLogin">
         <key-map field-name="userLoginId"/>
       </relation>
+      <relation type="one-nofk" fk-name="ORIG_USER_LH_USER" rel-entity-name="UserLogin">
+        <key-map field-name="originUserLoginId" rel-field-name="userLoginId"/>
+      </relation>
     </entity>
     <entity entity-name="UserLoginSession"
             package-name="org.apache.ofbiz.security.login"
diff --git framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
index ca3515cfe7..a61b68de27 100644
--- framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
+++ framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
@@ -533,6 +533,153 @@ public class LoginWorker {
         }
     }
 
+    /**
+     * An HTTP WebEvent handler to impersonate a given userLogin without using password. This should run before the security check.
+     *
+     * @param request The HTTP request object for the current JSP or Servlet request.
+     * @param response The HTTP response object for the current JSP or Servlet request.
+     * @return Return a boolean which specifies whether or not the calling Servlet or
+     *         JSP should generate its own content. This allows an event to override the default content.
+     */
+    public static String impersonateLogin(HttpServletRequest request, HttpServletResponse response) {
+        HttpSession session = request.getSession();
+        Delegator delegator = (Delegator) request.getAttribute("delegator");
+        String userLoginIdToImpersonate = request.getParameter("userLoginIdToImpersonate");
+        GenericValue userLogin = (GenericValue) session.getAttribute("userLogin");
+        LocalDispatcher dispatcher;
+
+        //Check if user has impersonate permission
+        Security security = (Security) request.getAttribute("security");
+        if (!security.hasEntityPermission("IMPERSONATE", "_ADMIN", userLogin)) {
+            String errMsg = UtilProperties.getMessage(resourceWebapp, "loginevents.unable_to_login_this_application", UtilHttp.getLocale(request));
+            request.setAttribute("_ERROR_MESSAGE_", errMsg);
+            return "error";
+        }
+
+        List<String> errMsgList = new LinkedList<>();
+        if (UtilValidate.isNotEmpty(session.getAttribute("originUserLogin"))) {
+            errMsgList.add(UtilProperties.getMessage(resourceWebapp, "loginevents.origin_username_is_present", UtilHttp.getLocale(request)));
+        }
+        if (UtilValidate.isEmpty(userLoginIdToImpersonate)) {
+            errMsgList.add(UtilProperties.getMessage(resourceWebapp, "loginevents.username_was_empty_reenter", UtilHttp.getLocale(request)));
+        }
+
+        try {
+            GenericValue userLoginToImpersonate = delegator.findOne("UserLogin", false, "userLoginId", userLoginIdToImpersonate);
+            if (!hasBasePermission(userLoginToImpersonate, request)) {
+                errMsgList.add(UtilProperties.getMessage(resourceWebapp, "loginevents.unable_to_login_this_application", UtilHttp.getLocale(request)));
+            }
+
+            //Check if user is trying to impersonate a full admin user
+            GenericValue userLoginSecurityGroup = EntityQuery.use(delegator).from("UserLoginSecurityGroup")
+                    .where("userLoginId", userLoginIdToImpersonate, "groupId", "FULLADMIN").queryFirst();
+            if (userLoginSecurityGroup != null) {
+                userLoginSecurityGroup = EntityQuery.use(delegator).from("UserLoginSecurityGroup")
+                        .where("userLoginId",userLogin.getString("userLoginId"), "groupId", "FULLADMIN").queryFirst();
+                if (userLoginSecurityGroup == null) {
+                    String errMsg = UtilProperties.getMessage(resourceWebapp, "loginevents.impersonate_needsFullAdmin", UtilHttp.getLocale(request));
+                    Debug.logError(errMsg, module);
+                    request.setAttribute("_ERROR_MESSAGE_", errMsg);
+                    return  "error";
+                }
+            }
+        } catch (GenericEntityException e) {
+            String errMsg ="Error impersonating the userLoginId" + userLoginIdToImpersonate;
+            Debug.logError(e, errMsg, module);
+            errMsgList.add(errMsg);
+            request.setAttribute("_ERROR_MESSAGE_LIST_", errMsgList);
+            return  "error";
+        }
+        if (!errMsgList.isEmpty()) {
+            request.setAttribute("_ERROR_MESSAGE_LIST_", errMsgList);
+            return  "error";
+        }
+
+        // After this line, contrary to in the login method, multi-tenant is not handled
+        ServletContext servletContext = session.getServletContext();
+
+        // Set default delegator
+        Debug.logInfo("Setting default delegator", module);
+        String delegatorName = delegator.getDelegatorBaseName();
+        delegator = DelegatorFactory.getDelegator(delegatorName);
+        dispatcher = WebAppUtil.makeWebappDispatcher(servletContext, delegator);
+
+        Map<String, Object> result;
+        try {
+            // get the visit id to pass to the userLogin for history
+            String visitId = VisitHandler.getVisitId(session);
+            result = dispatcher.runSync("userImpersonate",
+                    UtilMisc.toMap("userLoginIdToImpersonate", userLoginIdToImpersonate,
+                            "userLogin", userLogin,"visitId", visitId, "locale", UtilHttp.getLocale(request)));
+        } catch (GenericServiceException e) {
+            Debug.logError(e, "Error calling userImpersonate service", module);
+            Map<String, String> messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
+            String errMsg = UtilProperties.getMessage(resourceWebapp, "loginevents.following_error_occurred_during_login", messageMap, UtilHttp.getLocale(request));
+            request.setAttribute("_ERROR_MESSAGE_", errMsg);
+            return "error";
+        }
+
+        if (ModelService.RESPOND_SUCCESS.equals(result.get(ModelService.RESPONSE_MESSAGE))) {
+            userLogin = (GenericValue) result.get("userLogin");
+            GenericValue originUserLogin = (GenericValue) result.get("originUserLogin");
+
+            Map<String, Object> userLoginSession = checkMap(result.get("userLoginSession"), String.class, Object.class);
+
+            // check on JavaScriptEnabled
+            String javaScriptEnabled = "N";
+            if ("Y".equals(request.getParameter("JavaScriptEnabled"))) {
+                javaScriptEnabled = "Y";
+            }
+            try {
+                dispatcher.runSync("setUserPreference", UtilMisc.toMap("userPrefTypeId", "javaScriptEnabled",
+                        "userPrefGroupTypeId", "GLOBAL_PREFERENCES", "userPrefValue", javaScriptEnabled, "userLogin", userLogin));
+            } catch (GenericServiceException e) {
+                Debug.logError(e, "Error setting user preference", module);
+            }
+
+            //add originUserLogin in session
+            session.setAttribute("originUserLogin", originUserLogin);
+            // finally do the main login routine to set everything else up in the session, etc
+            return doMainLogin(request, response, userLogin, userLoginSession);
+        } else {
+            Map<String, String> messageMap = UtilMisc.toMap("errorMessage", result.get(ModelService.ERROR_MESSAGE));
+            String errMsg = UtilProperties.getMessage(resourceWebapp, "loginevents.following_error_occurred_during_login", messageMap, UtilHttp.getLocale(request));
+            request.setAttribute("_ERROR_MESSAGE_", errMsg);
+            return "error";
+        }
+    }
+
+    /**
+     * An HTTP WebEvent handler to reverse an impersonate login.
+     *
+     * @param request The HTTP request object for the current JSP or Servlet request.
+     * @param response The HTTP response object for the current JSP or Servlet request.
+     * @return Return a boolean which specifies whether or not the calling Servlet or
+     *         JSP should generate its own content. This allows an event to override the default content.
+     */
+    public static String depersonateLogin(HttpServletRequest request, HttpServletResponse response) {
+        HttpSession session = request.getSession();
+        GenericValue originUserLogin = (GenericValue) session.getAttribute("originUserLogin");
+        session.removeAttribute("originUserLogin");
+
+        List<String> errMsgList = new LinkedList<>();
+        if (null == originUserLogin) {
+            errMsgList.add(UtilProperties.getMessage(resourceWebapp, "loginevents.username_was_empty_reenter", UtilHttp.getLocale(request)));
+        }
+        if (!errMsgList.isEmpty()) {
+            request.setAttribute("_ERROR_MESSAGE_LIST_", errMsgList);
+            return  "error";
+        }
+
+        // logout the impersonated user
+        autoLoginRemove(request, response);
+        logout(request, response);
+        // ignore the return value; even if the operation failed we want to set the new UserLogin
+
+        // Log back the impersonating user
+        return doMainLogin(request, response, originUserLogin, null);
+    }
+
     protected static void setWebContextObjects(HttpServletRequest request, HttpServletResponse response, Delegator delegator, LocalDispatcher dispatcher) {
         HttpSession session = request.getSession();
         // NOTE: we do NOT want to set this in the servletContext, only in the request and session
diff --git themes/bluelight/template/Header.ftl themes/bluelight/template/Header.ftl
index 7cdc4a4995..8866f27d4c 100644
--- themes/bluelight/template/Header.ftl
+++ themes/bluelight/template/Header.ftl
@@ -113,6 +113,7 @@ under the License.
 </#if>
 
 <body>
+  <#include "component://common-theme/template/ImpersonateBanner.ftl"/>
   <div id="wait-spinner" style="display:none">
     <div id="wait-spinner-image"></div>
   </div>
diff --git themes/common-theme/template/ImpersonateBanner.ftl themes/common-theme/template/ImpersonateBanner.ftl
new file mode 100644
index 0000000000..2dd3e9f2d1
--- /dev/null
+++ themes/common-theme/template/ImpersonateBanner.ftl
@@ -0,0 +1,11 @@
+<#if parameters.originUserLogin??>
+    <a href="#impersonateContent" title="${uiLabelMap.CommonImpersonateTitle}" id="impersonateBtn"><img src="/images/img/impersonate-ico.png" alt="${uiLabelMap.CommonImpersonateTitle}"/></a>
+    <div id="impersonateContent">
+        <div class="impersonateModal">
+            <a href="#" class="btn-close" title="${uiLabelMap.CommonClose}">×</a>
+            <h3>${uiLabelMap.CommonImpersonateTitle}</h3>
+            <p>${uiLabelMap.CommonImpersonateUserLogin} : <strong>${context.userLogin.userLoginId!}</strong></p>
+            <a href="depersonateLogin" class="btn" title="${uiLabelMap.CommonImpersonateStop}">${uiLabelMap.CommonImpersonateStop}</a>
+        </div>
+    </div>
+</#if>
diff --git themes/common-theme/webapp/common/css/impersonate.css themes/common-theme/webapp/common/css/impersonate.css
new file mode 100644
index 0000000000..25d7b5e54d
--- /dev/null
+++ themes/common-theme/webapp/common/css/impersonate.css
@@ -0,0 +1,132 @@
+#impersonateBtn{
+    position:fixed;
+    bottom:37px;
+    right:20px;
+    z-index:10000;
+    width: 79px;
+    height: 60px;
+    cursor:pointer;
+}
+
+#impersonateBtn img{
+    width:100%;
+    max-width:79px;
+    height:auto;
+    opacity: 0.6;
+    transition: opacity .6s;
+}
+
+#impersonateBtn:hover img{
+     opacity: 1;
+}
+
+#impersonateContent:before {
+    content: "";
+    display: none;
+    background: rgba(225, 225, 225, 0.8);
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    z-index: 10;
+}
+
+#impersonateContent:target:before {
+    display: block;
+}
+
+#impersonateContent:target .impersonateModal {
+    opacity:1;
+    bottom: 117px;
+    right: 20px;
+    -webkit-transform: translate(0, 0);
+        -ms-transform: translate(0, 0);
+            transform: translate(0, 0);
+}
+
+.impersonateModal {
+    opacity:0;
+    position: fixed;
+    background: #FFF;
+    text-align: center;
+    padding:30px 30px 15px 30px;
+    border-radius: 5px;
+    z-index: 11;
+    box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.15);
+    -webkit-transform: translate(0, -500%);
+        -ms-transform: translate(0, -500%);
+            transform: translate(0, -500%);
+    -webkit-transition: -webkit-transform 0.3s ease-out;
+       -moz-transition: -moz-transform 0.3s ease-out;
+         -o-transition: -o-transform 0.3s ease-out;
+            transition: transform 0.3s ease-out;
+}
+
+.impersonateModal:before {
+    content: "";
+    position: absolute;
+    bottom: -20px;
+    right: 37px;
+    border: 1em solid #FFF;
+    border-color: transparent transparent #FFF #FFF;
+    transform-origin: 0 0;
+    transform: rotate(-45deg);
+    box-shadow: -3px 3px 5px 0 rgba(0, 0, 0, 0.05);
+}
+
+#impersonateContent .btn-close {
+    color: #aaa;
+    font-size: 25px;
+    text-decoration: none;
+    position: absolute;
+    right: 10px;
+    top: 10px;
+}
+
+#impersonateContent .btn-close:hover {
+    color: #919191;
+}
+
+#impersonateContent h3 {
+    font-size:26px;
+    font-weight: normal;
+    letter-spacing: 0.5px;
+    line-height: 24px;
+    color:#f08906;
+    border-bottom:1px solid #F2F2F2;
+    padding-bottom: 10px;
+    margin:15px 0 20px 0;
+}
+
+#impersonateContent p {
+    font-size:18px;
+    color:#666;
+    letter-spacing: 0.3px;
+}
+
+#impersonateContent p strong {
+    color:#005982;
+    font-weight:bold;
+}
+
+#impersonateContent .btn{
+    border-radius: 2px;
+    border:1px solid #005982;
+    padding:7px 12px;
+    text-transform:uppercase;
+    letter-spacing: 1px;
+    color:#005982;
+    margin:30px 0 10px 0;
+    line-height:22px;
+    display:inline-block;
+    -webkit-transition: 0.2s ease-out;
+    -moz-transition: 0.2s ease-out;
+    -o-transition: 0.2s ease-out;
+    transition: 0.2s ease-out;
+}
+
+#impersonateContent .btn:hover{
+    color:#f08906;
+    border-color:#f08906;
+}
diff --git themes/common-theme/webapp/images/img/impersonate-ico.png themes/common-theme/webapp/images/img/impersonate-ico.png
new file mode 100644
index 0000000000..d12c252dfc
Binary files /dev/null and themes/common-theme/webapp/images/img/impersonate-ico.png differ
diff --git themes/common-theme/widget/CommonScreens.xml themes/common-theme/widget/CommonScreens.xml
index 2b42e6694c..5aa38f7043 100644
--- themes/common-theme/widget/CommonScreens.xml
+++ themes/common-theme/widget/CommonScreens.xml
@@ -155,6 +155,7 @@ under the License.
                         <set field="appbarCloseTemplateLocation" from-field="layoutSettings.VT_NAV_CLOSE_TMPLT" />
                         <set field="messagesTemplateLocation" from-field="layoutSettings.VT_MSG_TMPLT_LOC" />
                         <set field="layoutSettings.suppressTab" value="ofbizsetup"/><!-- diseable ofbiz setup by default -->
+                        <set field="layoutSettings.styleSheets[+0]" value="/common/css/impersonate.css" global="true" />
                     </actions>
                     <widgets />
                 </section>
diff --git themes/flatgrey/template/Header.ftl themes/flatgrey/template/Header.ftl
index 56550f7077..e83cdc32db 100644
--- themes/flatgrey/template/Header.ftl
+++ themes/flatgrey/template/Header.ftl
@@ -93,6 +93,7 @@ under the License.
 </#if>
 <#assign organizationLogoLinkURL = "${layoutSettings.organizationLogoLinkUrl!}">
 <body>
+  <#include "component://common-theme/template/ImpersonateBanner.ftl"/>
   <div id="wait-spinner" style="display:none">
     <div id="wait-spinner-image"></div>
   </div>
diff --git themes/rainbowstone/template/includes/TopAppBar.ftl themes/rainbowstone/template/includes/TopAppBar.ftl
index cb05b52b07..6967ee9a47 100644
--- themes/rainbowstone/template/includes/TopAppBar.ftl
+++ themes/rainbowstone/template/includes/TopAppBar.ftl
@@ -30,6 +30,7 @@ under the License.
     </#if>
 </#if>
 <body>
+<#include "component://common-theme/template/ImpersonateBanner.ftl"/>
 <div id="wait-spinner" style="display:none">
     <div id="wait-spinner-image"></div>
 </div>
diff --git themes/tomahawk/template/Header.ftl themes/tomahawk/template/Header.ftl
index 87d4327cbf..7e04c8ff3e 100644
--- themes/tomahawk/template/Header.ftl
+++ themes/tomahawk/template/Header.ftl
@@ -98,6 +98,7 @@ under the License.
 <#assign organizationLogoLinkURL = "${layoutSettings.organizationLogoLinkUrl!}">
 
 <body>
+  <#include "component://common-theme/template/ImpersonateBanner.ftl"/>
   <div id="wait-spinner" style="display:none">
     <div id="wait-spinner-image"></div>
   </div>
