CVE-2023-34465: Improper Privilege Management (CWE-269)
value: XWiki Platform is a generic wiki platform. Starting in version 11.8-rc-1 and prior to versions 14.4.8, 14.10.6, and 15.2, `Mail.MailConfig` can be edited by any logged-in user by default. Consequently, they can change the mail obfuscation configuration and view and edit the mail sending configuration, including the smtp domain name and credentials. The problem has been patched in XWiki 14.4.8, 14.10.6, and 15.1. As a workaround, the rights of the `Mail.MailConfig` page can be manually updated so that only a set of trusted users can view, edit and delete it (e.g., the `XWiki.XWikiAdminGroup` group).
CWE description: The product does not properly assign, modify, track, or check privileges for an actor, creating an unintended sphere of control for that actor.
CVSS v3 base score: 8.1
Published: 2023-06-23T16:15Z
Repository: https://github.com/xwiki/xwiki-platform
Language: Java
Files changed: xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/pom.xml, xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/src/main/java/org/xwiki/mail/internal/MailConfigMandatoryDocumentInitializer.java, xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/src/test/java/org/xwiki/mail/internal/MailConfigMandatoryDocumentInitializerTest.java, xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/pom.xml, xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/java/org/xwiki/security/internal/DocumentInitializerRightsManager.java, xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/resources/META-INF/components.txt, xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/test/java/org/xwiki/security/internal/DocumentInitializerRightsManagerTest.java
Commit date: 2023-02-07 10:13:45 +0100
Commit message: XWIKI-20519: Improve Mail.MailConfig initialization

Diff: diff --git a/xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/pom.xml b/xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/pom.xml
index 735b4bbc96b24..d98220565a30b 100644
--- a/xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/pom.xml
+++ b/xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/pom.xml
@@ -111,7 +111,12 @@
       <groupId>org.xwiki.commons</groupId>
       <artifactId>xwiki-commons-tool-test-component</artifactId>
       <version>${commons.version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.xwiki.platform</groupId>
+      <artifactId>xwiki-platform-security-authorization-bridge</artifactId>
+      <version>${project.version}</version>
+    </dependency>
   </dependencies>
 </project>
diff --git a/xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/src/main/java/org/xwiki/mail/internal/MailConfigMandatoryDocumentInitializer.java b/xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/src/main/java/org/xwiki/mail/internal/MailConfigMandatoryDocumentInitializer.java
index 35ffac9df7cc2..ce4a002a794ed 100644
--- a/xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/src/main/java/org/xwiki/mail/internal/MailConfigMandatoryDocumentInitializer.java
+++ b/xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/src/main/java/org/xwiki/mail/internal/MailConfigMandatoryDocumentInitializer.java
@@ -30,10 +30,11 @@
 import org.xwiki.component.annotation.Component;
 import org.xwiki.mail.internal.configuration.SendMailConfigClassDocumentConfigurationSource;
 import org.xwiki.model.reference.DocumentReference;
 import org.xwiki.model.reference.EntityReference;
 import org.xwiki.model.reference.LocalDocumentReference;
+import org.xwiki.security.internal.DocumentInitializerRightsManager;
 import org.xwiki.wiki.descriptor.WikiDescriptorManager;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Provider;
@@ -60,10 +61,13 @@ public class MailConfigMandatoryDocumentInitializer implements MandatoryDocument
     private WikiDescriptorManager wikiDescriptorManager;
 
     @Inject
     private Provider<XWikiContext> xcontextProvider;
 
+    @Inject
+    private DocumentInitializerRightsManager documentInitializerRightsManager;
+
     @Override
     public EntityReference getDocumentReference()
     {
         return SendMailConfigClassDocumentConfigurationSource.MAILCONFIG_REFERENCE;
     }
@@ -105,10 +109,14 @@ public boolean updateDocument(XWikiDocument document)
         // TODO: Ideally this code should be executed only once.
         if (removeConfigurableClass(document)) {
             needsUpdate = true;
         }
 
+        if (this.documentInitializerRightsManager.restrictToAdmin(document)) {
+            needsUpdate = true;
+        }
+
         return needsUpdate;
     }
 
     private boolean updateReferences(XWikiDocument document)
     {
diff --git a/xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/src/test/java/org/xwiki/mail/internal/MailConfigMandatoryDocumentInitializerTest.java b/xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/src/test/java/org/xwiki/mail/internal/MailConfigMandatoryDocumentInitializerTest.java
index 8717c22a8493a..7043aaaa962f2 100644
--- a/xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/src/test/java/org/xwiki/mail/internal/MailConfigMandatoryDocumentInitializerTest.java
+++ b/xwiki-platform-core/xwiki-platform-mail/xwiki-platform-mail-send/xwiki-platform-mail-send-default/src/test/java/org/xwiki/mail/internal/MailConfigMandatoryDocumentInitializerTest.java
@@ -17,29 +17,35 @@
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
 package org.xwiki.mail.internal;
 
+import javax.inject.Provider;
+
+import org.junit.jupiter.api.Test;
+import org.xwiki.model.reference.DocumentReference;
+import org.xwiki.model.reference.LocalDocumentReference;
+import org.xwiki.security.internal.DocumentInitializerRightsManager;
+import org.xwiki.test.junit5.mockito.InjectMockComponents;
+import org.xwiki.test.junit5.mockito.MockComponent;
+import org.xwiki.wiki.descriptor.WikiDescriptorManager;
+
 import com.xpn.xwiki.XWiki;
 import com.xpn.xwiki.XWikiContext;
 import com.xpn.xwiki.doc.XWikiDocument;
 import com.xpn.xwiki.objects.BaseObject;
 import com.xpn.xwiki.test.MockitoOldcore;
 import com.xpn.xwiki.test.junit5.mockito.InjectMockitoOldcore;
 import com.xpn.xwiki.test.junit5.mockito.OldcoreTest;
 import com.xpn.xwiki.test.reference.ReferenceComponentList;
-import org.junit.jupiter.api.Test;
-import org.xwiki.model.reference.DocumentReference;
-import org.xwiki.model.reference.LocalDocumentReference;
-import org.xwiki.test.junit5.mockito.InjectMockComponents;
-import org.xwiki.test.junit5.mockito.MockComponent;
-import org.xwiki.wiki.descriptor.WikiDescriptorManager;
 
-import javax.inject.Provider;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 /**
  * Unit tests for {@link MailConfigMandatoryDocumentInitializer}.
  *
  * @version $Id$
@@ -58,10 +64,13 @@
     private Provider<XWikiContext> xcontextProvider;
 
     @InjectMockitoOldcore
     private MockitoOldcore oldcore;
 
+    @MockComponent
+    private DocumentInitializerRightsManager documentInitializerRightsManager;
+
     @Test
     public void updateDocument()
     {
         when(this.wikiDescriptorManager.getMainWikiId()).thenReturn("mainwiki");
         XWikiDocument document = new XWikiDocument(new DocumentReference("mainwiki", "Mail", "MailConfig"));
@@ -79,7 +88,8 @@ public void updateDocument()
         assertEquals("Mail Configuration", document.getTitle());
         BaseObject sendMailConfigObject =
             document.getXObject(new LocalDocumentReference("Mail", "SendMailConfigClass"));
         assertNotNull(sendMailConfigObject);
         assertNotNull(document.getXObject(new LocalDocumentReference("Mail", "GeneralMailConfigClass")));
+        verify(this.documentInitializerRightsManager).restrictToAdmin(document);
     }
 }
diff --git a/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/pom.xml b/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/pom.xml
index 5dadc3e5df0e1..2ba79d6424d61 100644
--- a/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/pom.xml
+++ b/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/pom.xml
@@ -29,11 +29,11 @@
   </parent>
   <artifactId>xwiki-platform-security-authorization-bridge</artifactId>
   <name>XWiki Platform - Security - Authorization - Bridge</name>
   <description>Authorization API implementation using oldcore</description>
   <properties>
-    <xwiki.jacoco.instructionRatio>0.70</xwiki.jacoco.instructionRatio>
+    <xwiki.jacoco.instructionRatio>0.71</xwiki.jacoco.instructionRatio>
     <!-- TODO: Remove once the tests have been fixed to not output anything to the console! -->
     <xwiki.surefire.captureconsole.skip>true</xwiki.surefire.captureconsole.skip>
     <!-- Name to display by the Extension Manager -->
     <xwiki.extension.name>Authorization Bridge</xwiki.extension.name>
     <xwiki.extension.features>
diff --git a/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/java/org/xwiki/security/internal/DocumentInitializerRightsManager.java b/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/java/org/xwiki/security/internal/DocumentInitializerRightsManager.java
new file mode 100644
index 0000000000000..9d55432458496
--- /dev/null
+++ b/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/java/org/xwiki/security/internal/DocumentInitializerRightsManager.java
@@ -0,0 +1,110 @@
+/*
+ * See the NOTICE file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.xwiki.security.internal;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.slf4j.Logger;
+import org.xwiki.component.annotation.Component;
+import org.xwiki.security.authorization.Right;
+
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.XWikiException;
+import com.xpn.xwiki.doc.XWikiDocument;
+import com.xpn.xwiki.objects.BaseObject;
+
+import static org.xwiki.security.authorization.Right.DELETE;
+import static org.xwiki.security.authorization.Right.EDIT;
+import static org.xwiki.security.authorization.Right.VIEW;
+import static org.xwiki.security.internal.XWikiConstants.ALLOW_FIELD_NAME;
+import static org.xwiki.security.internal.XWikiConstants.GROUPS_FIELD_NAME;
+import static org.xwiki.security.internal.XWikiConstants.LEVELS_FIELD_NAME;
+import static org.xwiki.security.internal.XWikiConstants.LOCAL_CLASS_REFERENCE;
+
+/**
+ * Service provided to {@link com.xpn.xwiki.doc.MandatoryDocumentInitializer}s to initialize documents with the correct
+ * rights.
+ *
+ * @version $Id$
+ * @since 14.4.8
+ * @since 14.10.5
+ * @since 15.1RC1
+ */
+@Component(roles = DocumentInitializerRightsManager.class)
+@Singleton
+public class DocumentInitializerRightsManager
+{
+    private static final String XWIKI_ADMIN_GROUP_DOCUMENT_REFERENCE = "XWiki.XWikiAdminGroup";
+
+    @Inject
+    private Provider<XWikiContext> xcontextProvider;
+
+    @Inject
+    private Logger logger;
+
+    /**
+     * Restrict the rights of the provided document so that it can only be viewed, edited and deleted by the
+     * {@code XWiki.XWikiAdminGroup} group. Note that this restriction is only applied if no rights are already applied
+     * on the current document.
+     * <br>
+     *
+     * @param document the document to updated rights on
+     * @return {@code true} if the document has been modified, {@code false} otherwise (including if the document hasn't
+     *     been modified because of an error during the modification)
+     */
+    public boolean restrictToAdmin(XWikiDocument document)
+    {
+        boolean updated = false;
+        // If some rights have already been set on the document, we consider that it has already been protected 
+        // manually.
+        if (document.getXObjects(LOCAL_CLASS_REFERENCE).isEmpty()) {
+            updated = initializeRights(document, XWIKI_ADMIN_GROUP_DOCUMENT_REFERENCE, List.of(VIEW, EDIT, DELETE));
+        }
+
+        return updated;
+    }
+
+    private boolean initializeRights(XWikiDocument document, String xwikiAdminGroupDocumentReference,
+        List<Right> rights)
+    {
+        boolean updated = false;
+
+        try {
+            XWikiContext xwikiContext = this.xcontextProvider.get();
+            BaseObject object = document.newXObject(LOCAL_CLASS_REFERENCE, xwikiContext);
+            XWikiContext xWikiContext = this.xcontextProvider.get();
+            object.set(GROUPS_FIELD_NAME, xwikiAdminGroupDocumentReference, xWikiContext);
+            object.set(LEVELS_FIELD_NAME, rights.stream().map(Right::getName).collect(Collectors.toList()),
+                xWikiContext);
+            object.set(ALLOW_FIELD_NAME, 1, xWikiContext);
+            updated = true;
+        } catch (XWikiException e) {
+            this.logger.error(String.format("Error adding a [%s] object to the document [%s]", LOCAL_CLASS_REFERENCE,
+                document.getDocumentReference()));
+        }
+
+        return updated;
+    }
+}
diff --git a/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/resources/META-INF/components.txt b/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/resources/META-INF/components.txt
index e6a5a97485bc6..f9d7d702026fe 100644
--- a/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/resources/META-INF/components.txt
+++ b/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/main/resources/META-INF/components.txt
@@ -4,5 +4,6 @@ org.xwiki.security.authorization.internal.DefaultSecurityCacheRulesInvalidator
 org.xwiki.security.authorization.internal.DefaultSecurityCacheRulesInvalidatorListener
 org.xwiki.security.authorization.internal.DefaultSecurityEntryReader
 org.xwiki.security.authorization.internal.RightsFilterListener
 org.xwiki.security.internal.DefaultUserBridge
 org.xwiki.security.internal.DefaultXWikiBridge
+org.xwiki.security.internal.DocumentInitializerRightsManager
diff --git a/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/test/java/org/xwiki/security/internal/DocumentInitializerRightsManagerTest.java b/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/test/java/org/xwiki/security/internal/DocumentInitializerRightsManagerTest.java
new file mode 100644
index 0000000000000..6b548ee96fa02
--- /dev/null
+++ b/xwiki-platform-core/xwiki-platform-security/xwiki-platform-security-authorization/xwiki-platform-security-authorization-bridge/src/test/java/org/xwiki/security/internal/DocumentInitializerRightsManagerTest.java
@@ -0,0 +1,122 @@
+/*
+ * See the NOTICE file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.xwiki.security.internal;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.xwiki.model.reference.DocumentReference;
+import org.xwiki.model.reference.EntityReference;
+import org.xwiki.test.LogLevel;
+import org.xwiki.test.annotation.AllComponents;
+import org.xwiki.test.junit5.LogCaptureExtension;
+import org.xwiki.test.junit5.mockito.InjectMockComponents;
+import org.xwiki.test.mockito.MockitoComponentManager;
+
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.XWikiException;
+import com.xpn.xwiki.doc.MandatoryDocumentInitializer;
+import com.xpn.xwiki.doc.XWikiDocument;
+import com.xpn.xwiki.internal.mandatory.XWikiRightsDocumentInitializer;
+import com.xpn.xwiki.objects.BaseObject;
+import com.xpn.xwiki.test.MockitoOldcore;
+import com.xpn.xwiki.test.junit5.mockito.InjectMockitoOldcore;
+import com.xpn.xwiki.test.junit5.mockito.OldcoreTest;
+
+import ch.qos.logback.classic.Level;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.spy;
+import static org.xwiki.security.internal.XWikiConstants.ALLOW_FIELD_NAME;
+import static org.xwiki.security.internal.XWikiConstants.GROUPS_FIELD_NAME;
+import static org.xwiki.security.internal.XWikiConstants.LEVELS_FIELD_NAME;
+import static org.xwiki.security.internal.XWikiConstants.LOCAL_CLASS_REFERENCE;
+
+/**
+ * Test of {@link DocumentInitializerRightsManager}.
+ *
+ * @version $Id$
+ */
+@OldcoreTest
+@AllComponents
+class DocumentInitializerRightsManagerTest
+{
+    @InjectMockitoOldcore
+    private MockitoOldcore oldcore;
+
+    @InjectMockComponents
+    private DocumentInitializerRightsManager rightsManager;
+
+    @RegisterExtension
+    LogCaptureExtension logCapture = new LogCaptureExtension(LogLevel.WARN);
+
+    private XWikiDocument document;
+
+    private XWikiContext xWikiContext;
+
+    @BeforeEach
+    void setUp(MockitoComponentManager componentManager) throws Exception
+    {
+        this.xWikiContext = this.oldcore.getXWikiContext();
+        String wikiId = this.xWikiContext.getWikiId();
+        this.document = this.oldcore.getSpyXWiki()
+            .getDocument(new DocumentReference(wikiId, "Space", "Page"), this.xWikiContext);
+        XWikiDocument xWikiRigths = this.oldcore.getSpyXWiki()
+            .getDocument(new DocumentReference(wikiId, "XWiki", "XWikiRights"), this.xWikiContext);
+        componentManager.<MandatoryDocumentInitializer>getInstance(MandatoryDocumentInitializer.class,
+            XWikiRightsDocumentInitializer.CLASS_REFERENCE_STRING).updateDocument(xWikiRigths);
+        this.oldcore.getSpyXWiki().saveDocument(xWikiRigths, this.xWikiContext);
+    }
+
+    @Test
+    void restrictToAdminSkipWhenAlreadyHasRights() throws Exception
+    {
+        this.document.newXObject(LOCAL_CLASS_REFERENCE, this.xWikiContext);
+        assertFalse(this.rightsManager.restrictToAdmin(this.document));
+    }
+
+    @Test
+    void restrictToAdmin()
+    {
+        assertTrue(this.rightsManager.restrictToAdmin(this.document));
+        assertEquals(1, this.document.getXObjects(LOCAL_CLASS_REFERENCE).size());
+        BaseObject xObject = this.document.getXObject(LOCAL_CLASS_REFERENCE);
+        assertEquals("XWiki.XWikiAdminGroup", xObject.getStringValue(GROUPS_FIELD_NAME));
+        assertEquals("view, edit, delete", xObject.getStringValue(LEVELS_FIELD_NAME));
+        assertEquals("1", xObject.getStringValue(ALLOW_FIELD_NAME));
+    }
+
+    @Test
+    void restrictToAdminWithException() throws XWikiException
+    {
+        this.document = spy(this.document);
+        doThrow(XWikiException.class).when(this.document)
+            .newXObject(any(EntityReference.class), any(XWikiContext.class));
+        assertFalse(this.rightsManager.restrictToAdmin(this.document));
+        assertEquals(0, this.document.getXObjects(LOCAL_CLASS_REFERENCE).size());
+        assertEquals("Error adding a [XWiki.XWikiRights] object to the document [xwiki:Space.Page]",
+            this.logCapture.getMessage(0));
+        assertEquals(Level.ERROR, this.logCapture.getLogEvent(0).getLevel());
+    }
+}

Vulnerable code: import org.junit.jupiter.api.Test;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.LocalDocumentReference;
import org.xwiki.test.junit5.mockito.InjectMockComponents;
import org.xwiki.test.junit5.mockito.MockComponent;
import org.xwiki.wiki.descriptor.WikiDescriptorManager;
import javax.inject.Provider;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
    <xwiki.jacoco.instructionRatio>0.70</xwiki.jacoco.instructionRatio>
Fixed code:     <dependency>
      <groupId>org.xwiki.platform</groupId>
      <artifactId>xwiki-platform-security-authorization-bridge</artifactId>
      <version>${project.version}</version>
    </dependency>
import org.xwiki.security.internal.DocumentInitializerRightsManager;
    @Inject
    private DocumentInitializerRightsManager documentInitializerRightsManager;

        if (this.documentInitializerRightsManager.restrictToAdmin(document)) {
            needsUpdate = true;
        }

import javax.inject.Provider;

import org.junit.jupiter.api.Test;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.LocalDocumentReference;
import org.xwiki.security.internal.DocumentInitializerRightsManager;
import org.xwiki.test.junit5.mockito.InjectMockComponents;
import org.xwiki.test.junit5.mockito.MockComponent;
import org.xwiki.wiki.descriptor.WikiDescriptorManager;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
    @MockComponent
    private DocumentInitializerRightsManager documentInitializerRightsManager;

        verify(this.documentInitializerRightsManager).restrictToAdmin(document);
    <xwiki.jacoco.instructionRatio>0.71</xwiki.jacoco.instructionRatio>
/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.security.internal;

import java.util.List;
import java.util.stream.Collectors;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;

import org.slf4j.Logger;
import org.xwiki.component.annotation.Component;
import org.xwiki.security.authorization.Right;

import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;

import static org.xwiki.security.authorization.Right.DELETE;
import static org.xwiki.security.authorization.Right.EDIT;
import static org.xwiki.security.authorization.Right.VIEW;
import static org.xwiki.security.internal.XWikiConstants.ALLOW_FIELD_NAME;
import static org.xwiki.security.internal.XWikiConstants.GROUPS_FIELD_NAME;
import static org.xwiki.security.internal.XWikiConstants.LEVELS_FIELD_NAME;
import static org.xwiki.security.internal.XWikiConstants.LOCAL_CLASS_REFERENCE;

/**
 * Service provided to {@link com.xpn.xwiki.doc.MandatoryDocumentInitializer}s to initialize documents with the correct
 * rights.
 *
 * @version $Id$
 * @since 14.4.8
 * @since 14.10.5
 * @since 15.1RC1
 */
@Component(roles = DocumentInitializerRightsManager.class)
@Singleton
public class DocumentInitializerRightsManager
{
    private static final String XWIKI_ADMIN_GROUP_DOCUMENT_REFERENCE = "XWiki.XWikiAdminGroup";

    @Inject
    private Provider<XWikiContext> xcontextProvider;

    @Inject
    private Logger logger;

    /**
     * Restrict the rights of the provided document so that it can only be viewed, edited and deleted by the
     * {@code XWiki.XWikiAdminGroup} group. Note that this restriction is only applied if no rights are already applied
     * on the current document.
     * <br>
     *
     * @param document the document to updated rights on
     * @return {@code true} if the document has been modified, {@code false} otherwise (including if the document hasn't
     *     been modified because of an error during the modification)
     */
    public boolean restrictToAdmin(XWikiDocument document)
    {
        boolean updated = false;
        // If some rights have already been set on the document, we consider that it has already been protected 
        // manually.
        if (document.getXObjects(LOCAL_CLASS_REFERENCE).isEmpty()) {
            updated = initializeRights(document, XWIKI_ADMIN_GROUP_DOCUMENT_REFERENCE, List.of(VIEW, EDIT, DELETE));
        }

        return updated;
    }

    private boolean initializeRights(XWikiDocument document, String xwikiAdminGroupDocumentReference,
        List<Right> rights)
    {
        boolean updated = false;

        try {
            XWikiContext xwikiContext = this.xcontextProvider.get();
            BaseObject object = document.newXObject(LOCAL_CLASS_REFERENCE, xwikiContext);
            XWikiContext xWikiContext = this.xcontextProvider.get();
            object.set(GROUPS_FIELD_NAME, xwikiAdminGroupDocumentReference, xWikiContext);
            object.set(LEVELS_FIELD_NAME, rights.stream().map(Right::getName).collect(Collectors.toList()),
                xWikiContext);
            object.set(ALLOW_FIELD_NAME, 1, xWikiContext);
            updated = true;
        } catch (XWikiException e) {
            this.logger.error(String.format("Error adding a [%s] object to the document [%s]", LOCAL_CLASS_REFERENCE,
                document.getDocumentReference()));
        }

        return updated;
    }
}
org.xwiki.security.internal.DocumentInitializerRightsManager
/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.security.internal;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.EntityReference;
import org.xwiki.test.LogLevel;
import org.xwiki.test.annotation.AllComponents;
import org.xwiki.test.junit5.LogCaptureExtension;
import org.xwiki.test.junit5.mockito.InjectMockComponents;
import org.xwiki.test.mockito.MockitoComponentManager;

import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.doc.MandatoryDocumentInitializer;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.internal.mandatory.XWikiRightsDocumentInitializer;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.test.MockitoOldcore;
import com.xpn.xwiki.test.junit5.mockito.InjectMockitoOldcore;
import com.xpn.xwiki.test.junit5.mockito.OldcoreTest;

import ch.qos.logback.classic.Level;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.spy;
import static org.xwiki.security.internal.XWikiConstants.ALLOW_FIELD_NAME;
import static org.xwiki.security.internal.XWikiConstants.GROUPS_FIELD_NAME;
import static org.xwiki.security.internal.XWikiConstants.LEVELS_FIELD_NAME;
import static org.xwiki.security.internal.XWikiConstants.LOCAL_CLASS_REFERENCE;

/**
 * Test of {@link DocumentInitializerRightsManager}.
 *
 * @version $Id$
 */
@OldcoreTest
@AllComponents
class DocumentInitializerRightsManagerTest
{
    @InjectMockitoOldcore
    private MockitoOldcore oldcore;

    @InjectMockComponents
    private DocumentInitializerRightsManager rightsManager;

    @RegisterExtension
    LogCaptureExtension logCapture = new LogCaptureExtension(LogLevel.WARN);

    private XWikiDocument document;

    private XWikiContext xWikiContext;

    @BeforeEach
    void setUp(MockitoComponentManager componentManager) throws Exception
    {
        this.xWikiContext = this.oldcore.getXWikiContext();
        String wikiId = this.xWikiContext.getWikiId();
        this.document = this.oldcore.getSpyXWiki()
            .getDocument(new DocumentReference(wikiId, "Space", "Page"), this.xWikiContext);
        XWikiDocument xWikiRigths = this.oldcore.getSpyXWiki()
            .getDocument(new DocumentReference(wikiId, "XWiki", "XWikiRights"), this.xWikiContext);
        componentManager.<MandatoryDocumentInitializer>getInstance(MandatoryDocumentInitializer.class,
            XWikiRightsDocumentInitializer.CLASS_REFERENCE_STRING).updateDocument(xWikiRigths);
        this.oldcore.getSpyXWiki().saveDocument(xWikiRigths, this.xWikiContext);
    }

    @Test
    void restrictToAdminSkipWhenAlreadyHasRights() throws Exception
    {
        this.document.newXObject(LOCAL_CLASS_REFERENCE, this.xWikiContext);
        assertFalse(this.rightsManager.restrictToAdmin(this.document));
    }

    @Test
    void restrictToAdmin()
    {
        assertTrue(this.rightsManager.restrictToAdmin(this.document));
        assertEquals(1, this.document.getXObjects(LOCAL_CLASS_REFERENCE).size());
        BaseObject xObject = this.document.getXObject(LOCAL_CLASS_REFERENCE);
        assertEquals("XWiki.XWikiAdminGroup", xObject.getStringValue(GROUPS_FIELD_NAME));
        assertEquals("view, edit, delete", xObject.getStringValue(LEVELS_FIELD_NAME));
        assertEquals("1", xObject.getStringValue(ALLOW_FIELD_NAME));
    }

    @Test
    void restrictToAdminWithException() throws XWikiException
    {
        this.document = spy(this.document);
        doThrow(XWikiException.class).when(this.document)
            .newXObject(any(EntityReference.class), any(XWikiContext.class));
        assertFalse(this.rightsManager.restrictToAdmin(this.document));
        assertEquals(0, this.document.getXObjects(LOCAL_CLASS_REFERENCE).size());
        assertEquals("Error adding a [XWiki.XWikiRights] object to the document [xwiki:Space.Page]",
            this.logCapture.getMessage(0));
        assertEquals(Level.ERROR, this.logCapture.getLogEvent(0).getLevel());
    }
}