CVE-2022-36090: Other (NVD-CWE-Other)
value: XWiki Platform Old Core is a core package for XWiki Platform, a generic wiki platform. Prior to versions 13.1.0.5 and 14.3-rc-1, some resources are missing a check for inactive (not yet activated or disabled) users in XWiki, including the REST service. This means a disabled user can enable themselves using a REST call. On the same way some resources handler created by extensions are not protected by default, so an inactive user could perform actions for such extensions. This issue has existed since at least version 1.1 of XWiki for instance configured with the email activation required for new users. Now it's more critical for versions 11.3-rc-1 and later since the maintainers provided the capability to disable user without deleting them and encouraged using that feature. XWiki 14.3-rc-1 and XWiki 13.10.5 contain a patch. There is no workaround for this other than upgrading XWiki.
CWE description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
CVSS v3 base score: 8.1
Published: 2022-09-08T15:15Z
Repository: https://github.com/xwiki/xwiki-platform
Language: Java
Files changed: xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/drawer.vm, xwiki-platform-core/xwiki-platform-notifications/xwiki-platform-notifications-rest/src/main/java/org/xwiki/notifications/rest/internal/DefaultNotificationsResource.java, xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java, xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWikiContext.java, xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/api/XWiki.java, xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/user/api/XWikiUser.java, xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/java/org/xwiki/security/authorization/internal/XWikiCachingRightService.java
Commit date: 2022-03-31 17:17:18 +0200
Commit message: XWIKI-19559: Refactor handling of users in oldcore

  * Add property for inactive users in XWikiContext
  * Ensure that all calls to checkAuth in XS goes through
    XWiki#checkAuth so that inactive users are handled
  * Improve code of XWiki#prepareDocuments to simplify it
  * Ensure that the login page is not displayed if a inactive user
    logged in, in XWikiCachingRightService
  * Improve a bit the code of the drawer to display the logout link in
    case of logged in inactive user

Diff: diff --git a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/drawer.vm b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/drawer.vm
index 36503f563e57..ce44e090f933 100644
--- a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/drawer.vm
+++ b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/drawer.vm
@@ -29,13 +29,19 @@
     <li class="drawer-brand clearfix">
       <a href="$xwiki.getURL($xcontext.user, 'view')">
         #largeUserAvatar($xcontext.user)
       </a>
       <div class="brand-links">
+        #define ($logoutLink)
+          <a href="$xwiki.getURL('XWiki.XWikiLogout', 'logout', "xredirect=$escapetool.url($xwiki.relativeRequestURL)")" id="tmLogout" rel="nofollow">$services.icon.renderHTML('log-out') $escapetool.xml($services.localization.render('logout'))</a>
+        #end
         #if ($xcontext.user != 'XWiki.XWikiGuest')
           <a href="$xwiki.getURL($xcontext.user, 'view')" class="brand-user" id="tmUser">$!xwiki.getUserName($xcontext.user, false)</a>
-          <a href="$xwiki.getURL('XWiki.XWikiLogout', 'logout', "xredirect=$escapetool.url($xwiki.relativeRequestURL)")" id="tmLogout" rel="nofollow">$services.icon.renderHTML('log-out') $escapetool.xml($services.localization.render('logout'))</a>
+          $logoutLink
+        #elseif($xcontext.user == 'XWiki.XWikiGuest' && $xcontext.inactiveUserReference)
+          <a href="$xwiki.getURL($xcontext.inactiveUserReference, 'view')" class="brand-user" id="tmUser">$!xwiki.getUserName($xcontext.inactiveUserReference, false)</a>
+          $logoutLink
         #else
           <a href="$xwiki.getURL('XWiki.XWikiLogin', 'login', "xredirect=$escapetool.url($xwiki.relativeRequestURL)&loginLink=1")" id="tmLogin" rel="nofollow">$services.icon.renderHTML('log-in') $escapetool.xml($services.localization.render('login'))</a>
           #if ($xwiki.hasAccessLevel('register', 'XWiki.XWikiPreferences'))
             <a href="$xwiki.getURL('XWiki.XWikiRegister', 'register', "xredirect=$escapetool.url($xwiki.relativeRequestURL)")" id="tmRegister" rel="nofollow">$services.icon.renderHTML('log-in') $escapetool.xml($services.localization.render('register'))</a>
           #end
diff --git a/xwiki-platform-core/xwiki-platform-notifications/xwiki-platform-notifications-rest/src/main/java/org/xwiki/notifications/rest/internal/DefaultNotificationsResource.java b/xwiki-platform-core/xwiki-platform-notifications/xwiki-platform-notifications-rest/src/main/java/org/xwiki/notifications/rest/internal/DefaultNotificationsResource.java
index 406d66e3d2a9..bde4d83ec755 100644
--- a/xwiki-platform-core/xwiki-platform-notifications/xwiki-platform-notifications-rest/src/main/java/org/xwiki/notifications/rest/internal/DefaultNotificationsResource.java
+++ b/xwiki-platform-core/xwiki-platform-notifications/xwiki-platform-notifications-rest/src/main/java/org/xwiki/notifications/rest/internal/DefaultNotificationsResource.java
@@ -183,11 +183,11 @@ public Response getNotificationsCount(String useUserPreferences, String userId,
         String displaySystemEvents, String displayReadEvents, String displayReadStatus, String tags, String currentWiki,
         String async, String asyncId) throws Exception
     {
         // Build the response
         Response.ResponseBuilder response;
-        XWikiUser xWikiUser = getXWikiContext().getWiki().getAuthService().checkAuth(getXWikiContext());
+        XWikiUser xWikiUser = getXWikiContext().getWiki().checkAuth(getXWikiContext());
         if (xWikiUser == null) {
             response = Response.status(Status.UNAUTHORIZED);
         } else {
             Object result = getCompositeEvents(useUserPreferences, userId, null, true, null, pages, spaces, wikis,
                 users, toMaxCount(maxCount, 21), displayOwnEvents, displayMinorEvents, displaySystemEvents,
@@ -213,11 +213,11 @@ public String getNotificationsRSS(String useUserPreferences, String userId, Stri
         String pages, String spaces, String wikis, String users, String maxCount, String displayOwnEvents,
         String displayMinorEvents, String displaySystemEvents, String displayReadEvents, String displayReadStatus,
         String tags, String currentWiki) throws Exception
     {
         // Build the response
-        XWikiUser xWikiUser = getXWikiContext().getWiki().getAuthService().checkAuth(getXWikiContext());
+        XWikiUser xWikiUser = getXWikiContext().getWiki().checkAuth(getXWikiContext());
         DocumentReference userIdDoc = this.documentReferenceResolver.resolve(userId);
         if (xWikiUser == null || !userIdDoc.equals(xWikiUser.getUserReference())) {
             getXWikiContext().getResponse().sendError(HttpServletResponse.SC_UNAUTHORIZED);
             return null;
         } else {
diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java
index f7a9ac2133d0..057832fd7090 100644
--- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java
+++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java
@@ -4320,13 +4320,27 @@ public void prepareResources(XWikiContext context)
             XWikiMessageTool msg = new XWikiMessageTool(Utils.getComponent(ContextualLocalizationManager.class));
             context.put("msg", msg);
         }
     }
 
+    /**
+     * Authenticate the user from the context and check if the user is disabled or not.
+     * If the user is disabled, the method returns {@code null} but set the reference of the authenticated user in the
+     * context with the {@link XWikiContext#INACTIVE_USER_REFERENCE} property.
+     *
+     * @param context the context used to authenticate the user.
+     * @return an {@link XWikiUser} if the user is authenticated and enabled, else {@code null}.
+     * @throws XWikiException in case of problem when dealing with the authentication.
+     */
     public XWikiUser checkAuth(XWikiContext context) throws XWikiException
     {
-        return getAuthService().checkAuth(context);
+        XWikiUser user = getAuthService().checkAuth(context);
+        if (user != null && user.isDisabled(context)) {
+            context.put(XWikiContext.INACTIVE_USER_REFERENCE, user.getUserReference());
+            user = null;
+        }
+        return user;
     }
 
     public boolean checkAccess(String action, XWikiDocument doc, XWikiContext context) throws XWikiException
     {
         // Handle the 'skin' action specially so that resources don`t require special (or even 'view') rights.
@@ -5862,74 +5876,30 @@ public boolean prepareDocuments(XWikiRequest request, XWikiContext context, Velo
 
         // the user is set after the access is checked.
         boolean hasAccess = checkAccess(context.getAction(), doc, context);
 
         XWikiUser user;
+        XWikiUser inactiveUser = null;
+        if (context.getUserReference() == null && context.get(XWikiContext.INACTIVE_USER_REFERENCE) != null) {
+            inactiveUser = new XWikiUser((DocumentReference) context.get(XWikiContext.INACTIVE_USER_REFERENCE));
+        }
         if (context.getUserReference() != null) {
             user = new XWikiUser(context.getUserReference());
         } else {
             user = new XWikiUser(context.getUser());
         }
 
+        if (inactiveUser != null && context.getAction().equals("view")) {
+            this.handleInactiveUserViewAction(inactiveUser, context, reference, vcontext);
+        }
         // We need to check rights before we look for translations
         // Otherwise we don't have the user language
-        if (!hasAccess) {
+        else if (!hasAccess) {
             Object[] args = { doc.getFullName(), user.getUser() };
             setPhonyDocument(reference, context, vcontext);
             throw new XWikiException(XWikiException.MODULE_XWIKI_ACCESS, XWikiException.ERROR_XWIKI_ACCESS_DENIED,
                 "Access to document {0} has been denied to user {1}", null, args);
-        // User is disabled: the mail address is marked as checked
-        } else if (user.isDisabled(context) && user.isEmailChecked(context)) {
-            String action = context.getAction();
-            /*
-             * Allow inactive users to see skins, ressources, SSX, JSX and downloads they could have seen as guest. The
-             * rational behind this behaviour is that inactive users should be able to access the same UI that guests
-             * are used to see, including custom icons, panels, and so on...
-             */
-            if (!((action.equals("skin") && (doc.getSpace().equals("skins") || doc.getSpace().equals("resources")))
-                || ((action.equals("skin") || action.equals("download") || action.equals("ssx") || action.equals("jsx"))
-                    && getRightService().hasAccessLevel("view", XWikiRightService.GUEST_USER_FULLNAME,
-                        doc.getPrefixedFullName(), context))
-                || ((action.equals("view") && doc.getFullName().equals("XWiki.AccountValidation"))))) {
-                Object[] args = { user.getUser() };
-                setPhonyDocument(reference, context, vcontext);
-                throw new XWikiException(XWikiException.MODULE_XWIKI_USER, XWikiException.ERROR_XWIKI_USER_DISABLED,
-                    "User {0} account is disabled", null, args);
-            }
-        // User actually needs to activate his mail address.
-        } else if (user.isDisabled(context) && !user.isEmailChecked(context)) {
-            boolean allow = false;
-            String action = context.getAction();
-            /*
-             * Allow inactive users to see skins, ressources, SSX, JSX and downloads they could have seen as guest. The
-             * rational behind this behaviour is that inactive users should be able to access the same UI that guests
-             * are used to see, including custom icons, panels, and so on...
-             */
-            if ((action.equals("skin") && (doc.getSpace().equals("skins") || doc.getSpace().equals("resources")))
-                || ((action.equals("skin") || action.equals("download") || action.equals("ssx") || action.equals("jsx"))
-                    && getRightService().hasAccessLevel("view", XWikiRightService.GUEST_USER_FULLNAME,
-                        doc.getPrefixedFullName(), context))
-                || ((action.equals("view") && doc.getFullName().equals("XWiki.AccountValidation")))) {
-                allow = true;
-            } else {
-                String allowed = getConfiguration().getProperty("xwiki.inactiveuser.allowedpages", "");
-                if (context.getAction().equals("view") && !allowed.equals("")) {
-                    String[] allowedList = StringUtils.split(allowed, " ,");
-                    for (String element : allowedList) {
-                        if (element.equals(doc.getFullName())) {
-                            allow = true;
-                            break;
-                        }
-                    }
-                }
-            }
-            if (!allow) {
-                Object[] args = { context.getUser() };
-                setPhonyDocument(reference, context, vcontext);
-                throw new XWikiException(XWikiException.MODULE_XWIKI_USER, XWikiException.ERROR_XWIKI_USER_INACTIVE,
-                    "User {0} account is inactive", null, args);
-            }
         }
 
         if (!"skin".equals(context.getAction())
             && !getAuthorizationManager().hasAccess(Right.VIEW, context.getUserReference(), reference)) {
             // If for some reason (e.g., login action) the user has rights for the action but no view right on the
@@ -5967,10 +5937,41 @@ && getRightService().hasAccessLevel("view", XWikiRightService.GUEST_USER_FULLNAM
         }
 
         return true;
     }
 
+    private void handleInactiveUserViewAction(XWikiUser inactiveUser, XWikiContext context, DocumentReference reference,
+        VelocityContext vcontext) throws XWikiException
+    {
+        if (inactiveUser.isEmailChecked(context)) {
+            Object[] args = { inactiveUser.getUser() };
+            setPhonyDocument(reference, context, vcontext);
+            throw new XWikiException(XWikiException.MODULE_XWIKI_USER, XWikiException.ERROR_XWIKI_USER_DISABLED,
+                "User {0} account is disabled", null, args);
+        } else if (!reference.getLocalDocumentReference().equals(XWikiUser.ACCOUNT_VALIDATION_DOCUMENT_REFERENCE)) {
+            String allowed = getConfiguration().getProperty("xwiki.inactiveuser.allowedpages", "");
+            boolean allow = false;
+            if (!StringUtils.isEmpty(allowed)) {
+                XWikiDocument doc = this.getDocument(reference, context);
+                String[] allowedList = StringUtils.split(allowed, " ,");
+                for (String element : allowedList) {
+                    if (element.equals(doc.getFullName())) {
+                        allow = true;
+                        break;
+                    }
+                }
+            }
+
+            if (!allow) {
+                Object[] args = { inactiveUser.getUser() };
+                setPhonyDocument(reference, context, vcontext);
+                throw new XWikiException(XWikiException.MODULE_XWIKI_USER, XWikiException.ERROR_XWIKI_USER_INACTIVE,
+                    "User {0} account is inactive", null, args);
+            }
+        }
+    }
+
     /**
      * @since 8.3M1
      */
     public void setPhonyDocument(DocumentReference reference, XWikiContext context)
     {
diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWikiContext.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWikiContext.java
index 1b9caa9326cc..77d5e73e8314 100644
--- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWikiContext.java
+++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWikiContext.java
@@ -99,10 +99,20 @@ public class XWikiContext extends Hashtable<Object, Object>
      * @deprecated use {@link VelocityManager#getVelocityContext()} instead
      */
     @Deprecated
     public static final String KEY_LEGACY_VELOCITYCONTEXT = "vcontext";
 
+    /**
+     * The reference of a logged-in inactive user: in such case the context user reference is guest, so we store
+     * the actual logged-in user with that key.
+     *
+     * @since 14.3RC1
+     * @since 13.10.5
+     */
+    @Unstable
+    public static final String INACTIVE_USER_REFERENCE = "inactiveUserReference";
+
     /** Logging helper object. */
     protected static final Logger LOGGER = LoggerFactory.getLogger(XWikiContext.class);
 
     private static final String WIKI_KEY = "wiki";
 
diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/api/XWiki.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/api/XWiki.java
index 8c3a9e5785d5..1a782b8c8b46 100644
--- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/api/XWiki.java
+++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/api/XWiki.java
@@ -2908,11 +2908,11 @@ public String getCounter(String name)
      * @return null if failed, non null XWikiUser if sucess
      * @throws XWikiException
      */
     public XWikiUser checkAuth() throws XWikiException
     {
-        return this.context.getWiki().getAuthService().checkAuth(this.context);
+        return this.context.getWiki().checkAuth(this.context);
     }
 
     /**
      * Check authentication from username and password and set according persitent login information If it fails user is
      * unlogged
@@ -2923,11 +2923,17 @@ public XWikiUser checkAuth() throws XWikiException
      * @return null if failed, non null XWikiUser if sucess
      * @throws XWikiException
      */
     public XWikiUser checkAuth(String username, String password, String rememberme) throws XWikiException
     {
-        return this.context.getWiki().getAuthService().checkAuth(username, password, rememberme, this.context);
+        XWikiUser user =
+            this.context.getWiki().getAuthService().checkAuth(username, password, rememberme, this.context);
+        if (user.isDisabled(this.context)) {
+            this.context.put(XWikiContext.INACTIVE_USER_REFERENCE, user.getUserReference());
+            user = null;
+        }
+        return user;
     }
 
     /**
      * Access statistics api
      *
diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/user/api/XWikiUser.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/user/api/XWikiUser.java
index 82336c60cc57..3dca7c8da2c5 100644
--- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/user/api/XWikiUser.java
+++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/user/api/XWikiUser.java
@@ -27,10 +27,11 @@
 import org.slf4j.LoggerFactory;
 import org.xwiki.localization.ContextualLocalizationManager;
 import org.xwiki.model.reference.DocumentReference;
 import org.xwiki.model.reference.DocumentReferenceResolver;
 import org.xwiki.model.reference.EntityReferenceSerializer;
+import org.xwiki.model.reference.LocalDocumentReference;
 import org.xwiki.model.reference.WikiReference;
 
 import com.xpn.xwiki.XWiki;
 import com.xpn.xwiki.XWikiContext;
 import com.xpn.xwiki.XWikiException;
@@ -56,10 +57,13 @@
      * 
      * @since 11.8RC1
      */
     public static final String EMAIL_CHECKED_PROPERTY = "email_checked";
 
+    public static final LocalDocumentReference ACCOUNT_VALIDATION_DOCUMENT_REFERENCE =
+        new LocalDocumentReference(XWiki.SYSTEM_SPACE, "AccountValidation");
+
     /**
      * @see com.xpn.xwiki.internal.model.reference.CurrentMixedStringDocumentReferenceResolver
      */
     private DocumentReferenceResolver<String> currentMixedDocumentReferenceResolver;
 
diff --git a/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/java/org/xwiki/security/authorization/internal/XWikiCachingRightService.java b/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/java/org/xwiki/security/authorization/internal/XWikiCachingRightService.java
index ba110b3cfc8e..6b4503a47768 100644
--- a/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/java/org/xwiki/security/authorization/internal/XWikiCachingRightService.java
+++ b/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/java/org/xwiki/security/authorization/internal/XWikiCachingRightService.java
@@ -278,11 +278,13 @@ public boolean checkAccess(String action, XWikiDocument doc, XWikiContext contex
         // unless the denied is on the login action, which could cause infinite redirection.
         // FIXME: The hasAccessLevel is broken (do not allow document creator) on the delete action in the old
         // implementation, so code that simply want to verify if a user can delete (but is not actually deleting)
         // has to call checkAccess. This happen really often, and this why we should not redirect to login on failed
         // delete, since it would prevent most user to do anything.
-        if (context.getUserReference() == null && !DELETE_ACTION.equals(action) && !LOGIN_ACTION.equals(action)) {
+        // Also we don't show the login if an inactive user logged in.
+        if (context.getUserReference() == null && !DELETE_ACTION.equals(action) && !LOGIN_ACTION.equals(action)
+            && context.get(XWikiContext.INACTIVE_USER_REFERENCE) == null) {
             LOGGER.debug("Redirecting unauthenticated user to login, since it have been denied [{}] on [{}].",
                          right, entityReference);
             showLogin(context);
         }
 

Vulnerable code:           <a href="$xwiki.getURL('XWiki.XWikiLogout', 'logout', "xredirect=$escapetool.url($xwiki.relativeRequestURL)")" id="tmLogout" rel="nofollow">$services.icon.renderHTML('log-out') $escapetool.xml($services.localization.render('logout'))</a>
        XWikiUser xWikiUser = getXWikiContext().getWiki().getAuthService().checkAuth(getXWikiContext());
        XWikiUser xWikiUser = getXWikiContext().getWiki().getAuthService().checkAuth(getXWikiContext());
        return getAuthService().checkAuth(context);
        if (!hasAccess) {
        // User is disabled: the mail address is marked as checked
        } else if (user.isDisabled(context) && user.isEmailChecked(context)) {
            String action = context.getAction();
            /*
             * Allow inactive users to see skins, ressources, SSX, JSX and downloads they could have seen as guest. The
             * rational behind this behaviour is that inactive users should be able to access the same UI that guests
             * are used to see, including custom icons, panels, and so on...
             */
            if (!((action.equals("skin") && (doc.getSpace().equals("skins") || doc.getSpace().equals("resources")))
                || ((action.equals("skin") || action.equals("download") || action.equals("ssx") || action.equals("jsx"))
                    && getRightService().hasAccessLevel("view", XWikiRightService.GUEST_USER_FULLNAME,
                        doc.getPrefixedFullName(), context))
                || ((action.equals("view") && doc.getFullName().equals("XWiki.AccountValidation"))))) {
                Object[] args = { user.getUser() };
                setPhonyDocument(reference, context, vcontext);
                throw new XWikiException(XWikiException.MODULE_XWIKI_USER, XWikiException.ERROR_XWIKI_USER_DISABLED,
                    "User {0} account is disabled", null, args);
            }
        // User actually needs to activate his mail address.
        } else if (user.isDisabled(context) && !user.isEmailChecked(context)) {
            boolean allow = false;
            String action = context.getAction();
            /*
             * Allow inactive users to see skins, ressources, SSX, JSX and downloads they could have seen as guest. The
             * rational behind this behaviour is that inactive users should be able to access the same UI that guests
             * are used to see, including custom icons, panels, and so on...
             */
            if ((action.equals("skin") && (doc.getSpace().equals("skins") || doc.getSpace().equals("resources")))
                || ((action.equals("skin") || action.equals("download") || action.equals("ssx") || action.equals("jsx"))
                    && getRightService().hasAccessLevel("view", XWikiRightService.GUEST_USER_FULLNAME,
                        doc.getPrefixedFullName(), context))
                || ((action.equals("view") && doc.getFullName().equals("XWiki.AccountValidation")))) {
                allow = true;
            } else {
                String allowed = getConfiguration().getProperty("xwiki.inactiveuser.allowedpages", "");
                if (context.getAction().equals("view") && !allowed.equals("")) {
                    String[] allowedList = StringUtils.split(allowed, " ,");
                    for (String element : allowedList) {
                        if (element.equals(doc.getFullName())) {
                            allow = true;
                            break;
                        }
                    }
                }
            }
            if (!allow) {
                Object[] args = { context.getUser() };
                setPhonyDocument(reference, context, vcontext);
                throw new XWikiException(XWikiException.MODULE_XWIKI_USER, XWikiException.ERROR_XWIKI_USER_INACTIVE,
                    "User {0} account is inactive", null, args);
            }
        return this.context.getWiki().getAuthService().checkAuth(this.context);
        return this.context.getWiki().getAuthService().checkAuth(username, password, rememberme, this.context);
        if (context.getUserReference() == null && !DELETE_ACTION.equals(action) && !LOGIN_ACTION.equals(action)) {
Fixed code:         #define ($logoutLink)
          <a href="$xwiki.getURL('XWiki.XWikiLogout', 'logout', "xredirect=$escapetool.url($xwiki.relativeRequestURL)")" id="tmLogout" rel="nofollow">$services.icon.renderHTML('log-out') $escapetool.xml($services.localization.render('logout'))</a>
        #end
          $logoutLink
        #elseif($xcontext.user == 'XWiki.XWikiGuest' && $xcontext.inactiveUserReference)
          <a href="$xwiki.getURL($xcontext.inactiveUserReference, 'view')" class="brand-user" id="tmUser">$!xwiki.getUserName($xcontext.inactiveUserReference, false)</a>
          $logoutLink
        XWikiUser xWikiUser = getXWikiContext().getWiki().checkAuth(getXWikiContext());
        XWikiUser xWikiUser = getXWikiContext().getWiki().checkAuth(getXWikiContext());
    /**
     * Authenticate the user from the context and check if the user is disabled or not.
     * If the user is disabled, the method returns {@code null} but set the reference of the authenticated user in the
     * context with the {@link XWikiContext#INACTIVE_USER_REFERENCE} property.
     *
     * @param context the context used to authenticate the user.
     * @return an {@link XWikiUser} if the user is authenticated and enabled, else {@code null}.
     * @throws XWikiException in case of problem when dealing with the authentication.
     */
        XWikiUser user = getAuthService().checkAuth(context);
        if (user != null && user.isDisabled(context)) {
            context.put(XWikiContext.INACTIVE_USER_REFERENCE, user.getUserReference());
            user = null;
        }
        return user;
        XWikiUser inactiveUser = null;
        if (context.getUserReference() == null && context.get(XWikiContext.INACTIVE_USER_REFERENCE) != null) {
            inactiveUser = new XWikiUser((DocumentReference) context.get(XWikiContext.INACTIVE_USER_REFERENCE));
        }
        if (inactiveUser != null && context.getAction().equals("view")) {
            this.handleInactiveUserViewAction(inactiveUser, context, reference, vcontext);
        }
        else if (!hasAccess) {
    private void handleInactiveUserViewAction(XWikiUser inactiveUser, XWikiContext context, DocumentReference reference,
        VelocityContext vcontext) throws XWikiException
    {
        if (inactiveUser.isEmailChecked(context)) {
            Object[] args = { inactiveUser.getUser() };
            setPhonyDocument(reference, context, vcontext);
            throw new XWikiException(XWikiException.MODULE_XWIKI_USER, XWikiException.ERROR_XWIKI_USER_DISABLED,
                "User {0} account is disabled", null, args);
        } else if (!reference.getLocalDocumentReference().equals(XWikiUser.ACCOUNT_VALIDATION_DOCUMENT_REFERENCE)) {
            String allowed = getConfiguration().getProperty("xwiki.inactiveuser.allowedpages", "");
            boolean allow = false;
            if (!StringUtils.isEmpty(allowed)) {
                XWikiDocument doc = this.getDocument(reference, context);
                String[] allowedList = StringUtils.split(allowed, " ,");
                for (String element : allowedList) {
                    if (element.equals(doc.getFullName())) {
                        allow = true;
                        break;
                    }
                }
            }

            if (!allow) {
                Object[] args = { inactiveUser.getUser() };
                setPhonyDocument(reference, context, vcontext);
                throw new XWikiException(XWikiException.MODULE_XWIKI_USER, XWikiException.ERROR_XWIKI_USER_INACTIVE,
                    "User {0} account is inactive", null, args);
            }
        }
    }

    /**
     * The reference of a logged-in inactive user: in such case the context user reference is guest, so we store
     * the actual logged-in user with that key.
     *
     * @since 14.3RC1
     * @since 13.10.5
     */
    @Unstable
    public static final String INACTIVE_USER_REFERENCE = "inactiveUserReference";

        return this.context.getWiki().checkAuth(this.context);
        XWikiUser user =
            this.context.getWiki().getAuthService().checkAuth(username, password, rememberme, this.context);
        if (user.isDisabled(this.context)) {
            this.context.put(XWikiContext.INACTIVE_USER_REFERENCE, user.getUserReference());
            user = null;
        }
        return user;
import org.xwiki.model.reference.LocalDocumentReference;
    public static final LocalDocumentReference ACCOUNT_VALIDATION_DOCUMENT_REFERENCE =
        new LocalDocumentReference(XWiki.SYSTEM_SPACE, "AccountValidation");

        // Also we don't show the login if an inactive user logged in.
        if (context.getUserReference() == null && !DELETE_ACTION.equals(action) && !LOGIN_ACTION.equals(action)
            && context.get(XWikiContext.INACTIVE_USER_REFERENCE) == null) {