VYPR
Critical severityNVD Advisory· Published Jun 24, 2024· Updated Aug 2, 2024

XWiki programming rights may be inherited by inclusion

CVE-2024-38369

Description

XWiki Platform is a generic wiki platform offering runtime services for applications built on top of it. The content of a document included using {{include reference="targetdocument"/}} is executed with the right of the includer and not with the right of its author. This means that any user able to modify the target document can impersonate the author of the content which used the include macro. This vulnerability has been patched in XWiki 15.0 RC1 by making the default behavior safe.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.xwiki.platform:xwiki-platform-rendering-macro-includeMaven
< 15.0-rc-115.0-rc-1

Affected products

1

Patches

5
0a4f9b026ba9

XWIKI-5027: Improve included content transformation

https://github.com/xwiki/xwiki-platformThomas MortagneDec 13, 2022via ghsa
2 files changed · +44 1
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/main/resources/ApplicationResources.properties+3 0 modified
    @@ -37,6 +37,9 @@ rendering.macro.include.parameter.author.description=The author to use to execut
     
     org.xwiki.rendering.macro.include.IncludeMacroParameters$Context.NEW=New
     org.xwiki.rendering.macro.include.IncludeMacroParameters$Context.CURRENT=Current
    +org.xwiki.rendering.macro.include.IncludeMacroParameters$Author.AUTO=Auto
    +org.xwiki.rendering.macro.include.IncludeMacroParameters$Author.CURRENT=Current
    +org.xwiki.rendering.macro.include.IncludeMacroParameters$Author.TARGET=Target
     
     ###############################################################################
     ## Deprecated
    
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/test/java/org/xwiki/rendering/internal/macro/include/IncludeMacroTest.java+41 1 modified
    @@ -214,6 +214,42 @@ void executeWithCURRENTAuthor() throws Exception
             assertBlocks(expected, blocks, this.rendererFactory);
         }
     
    +    @Test
    +    void executeWithNoPRAuthor() throws Exception
    +    {
    +        // @formatter:off
    +        String expected = "beginDocument\n"
    +            + "beginMetaData [[source]=[wiki:Space.IncludedPage][syntax]=[XWiki 2.0]]\n"
    +            + "beginParagraph\n"
    +            + "onWord [word]\n"
    +            + "endParagraph\n"
    +            + "endMetaData [[source]=[wiki:Space.IncludedPage][syntax]=[XWiki 2.0]]\n"
    +            + "endDocument";
    +        // @formatter:on
    +
    +        List<Block> blocks = runIncludeMacro(Context.CURRENT, Author.AUTO, "word", false);
    +
    +        assertBlocks(expected, blocks, this.rendererFactory);
    +    }
    +
    +    @Test
    +    void executeWithTARGETAuthor() throws Exception
    +    {
    +        // @formatter:off
    +        String expected = "beginDocument\n"
    +            + "beginMetaData [[source]=[wiki:Space.IncludedPage][syntax]=[XWiki 2.0]]\n"
    +            + "beginParagraph\n"
    +            + "onWord [word]\n"
    +            + "endParagraph\n"
    +            + "endMetaData [[source]=[wiki:Space.IncludedPage][syntax]=[XWiki 2.0]]\n"
    +            + "endDocument";
    +        // @formatter:on
    +
    +        List<Block> blocks = runIncludeMacro(Context.CURRENT, Author.TARGET, "word", false);
    +
    +        assertBlocks(expected, blocks, this.rendererFactory);
    +    }
    +
         @Test
         void executeWithCurrentUserNoView() throws Exception
         {
    @@ -669,7 +705,10 @@ private MacroTransformationContext createMacroTransformationContext(String docum
             MacroTransformationContext context = new MacroTransformationContext();
             MacroBlock includeMacro =
                 new MacroBlock("include", Collections.singletonMap("reference", documentName), isInline);
    +        XDOM xdom = new XDOM(List.of(includeMacro));
             context.setCurrentMacroBlock(includeMacro);
    +        context.setXDOM(xdom);
    +
             return context;
         }
     
    @@ -760,7 +799,8 @@ private List<Block> runIncludeMacro(final Context context, final Author author,
                 verify(this.dab).pushDocumentInContext(any(Map.class), same(this.includedDocument));
                 verify(this.dab).popDocumentFromContext(any(Map.class));
             } else {
    -            if (author == Author.CURRENT || this.authorizationManager.hasAccess(Right.PROGRAM, INCLUDED_AUHOR, null)) {
    +            if (parameters.getAuthor() == Author.CURRENT || (parameters.getAuthor() == Author.AUTO
    +                && this.authorizationManager.hasAccess(Right.PROGRAM, INCLUDED_AUHOR, null))) {
                     verifyNoInteractions(this.authorExecutor);
                 } else {
                     DocumentReference includedReference = this.includedDocument.getDocumentReference();
    
d1a84a3eea38

XWIKI-5027: Improve included content transformation

https://github.com/xwiki/xwiki-platformThomas MortagneDec 13, 2022via ghsa
2 files changed · +44 1
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/main/resources/ApplicationResources.properties+3 0 modified
    @@ -37,6 +37,9 @@ rendering.macro.include.parameter.author.description=The author to use to execut
     
     org.xwiki.rendering.macro.include.IncludeMacroParameters$Context.NEW=New
     org.xwiki.rendering.macro.include.IncludeMacroParameters$Context.CURRENT=Current
    +org.xwiki.rendering.macro.include.IncludeMacroParameters$Author.AUTO=Auto
    +org.xwiki.rendering.macro.include.IncludeMacroParameters$Author.CURRENT=Current
    +org.xwiki.rendering.macro.include.IncludeMacroParameters$Author.TARGET=Target
     
     ###############################################################################
     ## Deprecated
    
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/test/java/org/xwiki/rendering/internal/macro/include/IncludeMacroTest.java+41 1 modified
    @@ -214,6 +214,42 @@ void executeWithCURRENTAuthor() throws Exception
             assertBlocks(expected, blocks, this.rendererFactory);
         }
     
    +    @Test
    +    void executeWithNoPRAuthor() throws Exception
    +    {
    +        // @formatter:off
    +        String expected = "beginDocument\n"
    +            + "beginMetaData [[source]=[wiki:Space.IncludedPage][syntax]=[XWiki 2.0]]\n"
    +            + "beginParagraph\n"
    +            + "onWord [word]\n"
    +            + "endParagraph\n"
    +            + "endMetaData [[source]=[wiki:Space.IncludedPage][syntax]=[XWiki 2.0]]\n"
    +            + "endDocument";
    +        // @formatter:on
    +
    +        List<Block> blocks = runIncludeMacro(Context.CURRENT, Author.AUTO, "word", false);
    +
    +        assertBlocks(expected, blocks, this.rendererFactory);
    +    }
    +
    +    @Test
    +    void executeWithTARGETAuthor() throws Exception
    +    {
    +        // @formatter:off
    +        String expected = "beginDocument\n"
    +            + "beginMetaData [[source]=[wiki:Space.IncludedPage][syntax]=[XWiki 2.0]]\n"
    +            + "beginParagraph\n"
    +            + "onWord [word]\n"
    +            + "endParagraph\n"
    +            + "endMetaData [[source]=[wiki:Space.IncludedPage][syntax]=[XWiki 2.0]]\n"
    +            + "endDocument";
    +        // @formatter:on
    +
    +        List<Block> blocks = runIncludeMacro(Context.CURRENT, Author.TARGET, "word", false);
    +
    +        assertBlocks(expected, blocks, this.rendererFactory);
    +    }
    +
         @Test
         void executeWithCurrentUserNoView() throws Exception
         {
    @@ -669,7 +705,10 @@ private MacroTransformationContext createMacroTransformationContext(String docum
             MacroTransformationContext context = new MacroTransformationContext();
             MacroBlock includeMacro =
                 new MacroBlock("include", Collections.singletonMap("reference", documentName), isInline);
    +        XDOM xdom = new XDOM(List.of(includeMacro));
             context.setCurrentMacroBlock(includeMacro);
    +        context.setXDOM(xdom);
    +
             return context;
         }
     
    @@ -760,7 +799,8 @@ private List<Block> runIncludeMacro(final Context context, final Author author,
                 verify(this.dab).pushDocumentInContext(any(Map.class), same(this.includedDocument));
                 verify(this.dab).popDocumentFromContext(any(Map.class));
             } else {
    -            if (author == Author.CURRENT || this.authorizationManager.hasAccess(Right.PROGRAM, INCLUDED_AUHOR, null)) {
    +            if (parameters.getAuthor() == Author.CURRENT || (parameters.getAuthor() == Author.AUTO
    +                && this.authorizationManager.hasAccess(Right.PROGRAM, INCLUDED_AUHOR, null))) {
                     verifyNoInteractions(this.authorExecutor);
                 } else {
                     DocumentReference includedReference = this.includedDocument.getDocumentReference();
    
f627abe2dc39

XWIKI-5027: Improve included content transformation

https://github.com/xwiki/xwiki-platformThomas MortagneDec 2, 2022via ghsa
4 files changed · +85 66
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/main/java/org/xwiki/rendering/internal/macro/include/IncludeMacro.java+32 29 modified
    @@ -178,37 +178,40 @@ public List<Block> execute(IncludeMacroParameters parameters, String content, Ma
                 metadata.getMetaData().addMetaData(MetaData.BASE, source);
             }
     
    -        // Step 7: The the include macro is explicitly configured to be executed with the included document content
    -        // author of if that author does not have programming right, execute it right away
    -        // Get the translated version of the document to get the content author
    -        DocumentModelBridge translatedDocumentBridge;
    -        try {
    -            translatedDocumentBridge = this.documentAccessBridge.getTranslatedDocumentInstance(documentBridge);
    -        } catch (Exception e) {
    -            throw new MacroExecutionException("Failed to retrieve the translated version of the document", e);
    -        }
    -        if (parameters.getAuthor() == Author.TARGET || parameters.getAuthor() == Author.AUTO && !this.authorization
    -            .hasAccess(Right.PROGRAM, translatedDocumentBridge.getContentAuthorReference(), null)) {
    -            // Merge the two XDOM before executing the included content so that it's as close as possible to the expect
    -            // execution conditions
    -            MacroBlock includeMacro = context.getCurrentMacroBlock();
    -            MacroMarkerBlock includeMacroMarker = new MacroMarkerBlock(includeMacro.getId(),
    -                includeMacro.getParameters(), Collections.singletonList(metadata), includeMacro.isInline());
    -            includeMacro.getParent().replaceChild(includeMacroMarker, includeMacro);
    -
    +        if (parametersContext == Context.CURRENT) {
    +            // Step 7: If the include macro is explicitly configured to be executed with the included document content
    +            // author of if that author does not have programming right, execute it right away
    +            // Get the translated version of the document to get the content author
    +            DocumentModelBridge translatedDocumentBridge;
                 try {
    -                // Execute the content with the right author
    -                // Keep the same transformation context
    -                this.authorExecutor.call(() -> {
    -                    this.transformationManager.performTransformations(metadata, context.getTransformationContext());
    -                    return null;
    -                }, translatedDocumentBridge.getContentAuthorReference(), documentBridge.getDocumentReference());
    +                translatedDocumentBridge = this.documentAccessBridge.getTranslatedDocumentInstance(documentBridge);
                 } catch (Exception e) {
    -                throw new MacroExecutionException("Failed to execute tranformations for document ["
    -                    + translatedDocumentBridge.getDocumentReference() + "]");
    -            } finally {
    -                // Put back the macro in the main XDOM (it will be replaced that the current macro transformation)
    -                includeMacroMarker.getParent().replaceChild(includeMacro, includeMacroMarker);
    +                throw new MacroExecutionException("Failed to retrieve the translated version of the document", e);
    +            }
    +            if (parameters.getAuthor() == Author.TARGET || parameters.getAuthor() == Author.AUTO && !this.authorization
    +                .hasAccess(Right.PROGRAM, translatedDocumentBridge.getContentAuthorReference(), null)) {
    +                // Merge the two XDOM before executing the included content so that it's as close as possible to the
    +                // expect
    +                // execution conditions
    +                MacroBlock includeMacro = context.getCurrentMacroBlock();
    +                MacroMarkerBlock includeMacroMarker = new MacroMarkerBlock(includeMacro.getId(),
    +                    includeMacro.getParameters(), Collections.singletonList(metadata), includeMacro.isInline());
    +                includeMacro.getParent().replaceChild(includeMacroMarker, includeMacro);
    +
    +                try {
    +                    // Execute the content with the right author
    +                    // Keep the same transformation context
    +                    this.authorExecutor.call(() -> {
    +                        this.transformationManager.performTransformations(metadata, context.getTransformationContext());
    +                        return null;
    +                    }, translatedDocumentBridge.getContentAuthorReference(), documentBridge.getDocumentReference());
    +                } catch (Exception e) {
    +                    throw new MacroExecutionException("Failed to execute tranformations for document ["
    +                        + translatedDocumentBridge.getDocumentReference() + "]");
    +                } finally {
    +                    // Put back the macro in the main XDOM (it will be replaced that the current macro transformation)
    +                    includeMacroMarker.getParent().replaceChild(includeMacro, includeMacroMarker);
    +                }
                 }
             }
     
    
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/main/java/org/xwiki/rendering/macro/include/IncludeMacroParameters.java+4 4 modified
    @@ -104,7 +104,7 @@ public enum Author
          */
         private boolean excludeFirstHeading;
     
    -    private Author author;
    +    private Author author = Author.AUTO;
     
         /**
          * @param reference the reference of the resource to include
    @@ -234,7 +234,7 @@ public void setPage(String page)
         }
     
         /**
    -     * @return the author to use to execute the content
    +     * @return the author to use to execute the content when {@link #getContext()} is {@value Context#CURRENT}
          * @since 15.0RC1
          */
         public Author getAuthor()
    @@ -243,10 +243,10 @@ public Author getAuthor()
         }
     
         /**
    -     * @param author the author to use to execute the content
    +     * @param author the author to use to execute the content when {@link #getContext()} is {@value Context#CURRENT}
          * @since 15.0RC1
          */
    -    @PropertyDescription("The author to use to execute the content")
    +    @PropertyDescription("The author to use to execute the content when context is \"Current\"")
         @PropertyAdvanced
         public void setAuthor(Author author)
         {
    
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/main/resources/ApplicationResources.properties+2 0 modified
    @@ -32,6 +32,8 @@ rendering.macro.include.parameter.type.name=type
     rendering.macro.include.parameter.type.description=The type of the reference.
     rendering.macro.include.parameter.section.name=section
     rendering.macro.include.parameter.section.description=An optional id of a section to include in the specified page.
    +rendering.macro.include.parameter.author.name=Author.
    +rendering.macro.include.parameter.author.description=The author to use to execute the content when context is "Current".
     
     org.xwiki.rendering.macro.include.IncludeMacroParameters$Context.NEW=New
     org.xwiki.rendering.macro.include.IncludeMacroParameters$Context.CURRENT=Current
    
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/test/java/org/xwiki/rendering/internal/macro/include/IncludeMacroTest.java+47 33 modified
    @@ -60,6 +60,7 @@
     import org.xwiki.rendering.macro.Macro;
     import org.xwiki.rendering.macro.MacroExecutionException;
     import org.xwiki.rendering.macro.include.IncludeMacroParameters;
    +import org.xwiki.rendering.macro.include.IncludeMacroParameters.Author;
     import org.xwiki.rendering.macro.include.IncludeMacroParameters.Context;
     import org.xwiki.rendering.parser.Parser;
     import org.xwiki.rendering.renderer.PrintRendererFactory;
    @@ -176,7 +177,7 @@ public Void answer(InvocationOnMock invocation) throws Throwable
         }
     
         @Test
    -    void execute() throws Exception
    +    void executeWithPRAuthors() throws Exception
         {
             // @formatter:off
             String expected = "beginDocument\n"
    @@ -188,13 +189,15 @@ void execute() throws Exception
                 + "endDocument";
             // @formatter:on
     
    -        List<Block> blocks = runIncludeMacro(Context.CURRENT, "word", false, true);
    +        when(this.authorizationManager.hasAccess(Right.PROGRAM, INCLUDED_AUHOR, null)).thenReturn(true);
    +
    +        List<Block> blocks = runIncludeMacro(Context.CURRENT, "word", false);
     
             assertBlocks(expected, blocks, this.rendererFactory);
         }
     
         @Test
    -    void executeWithDifferentAuthors() throws Exception
    +    void executeWithCURRENTAuthor() throws Exception
         {
             // @formatter:off
             String expected = "beginDocument\n"
    @@ -206,7 +209,7 @@ void executeWithDifferentAuthors() throws Exception
                 + "endDocument";
             // @formatter:on
     
    -        List<Block> blocks = runIncludeMacro(Context.CURRENT, "word", false, false);
    +        List<Block> blocks = runIncludeMacro(Context.CURRENT, Author.CURRENT, "word", false);
     
             assertBlocks(expected, blocks, this.rendererFactory);
         }
    @@ -274,7 +277,7 @@ void executeWithNewContextShowsPassingOnRestrictedFlag() throws Exception
             // @formatter:on
     
             // We verify that a Velocity macro set in the including page is not seen in the included page.
    -        List<Block> blocks = runIncludeMacro(Context.NEW, "{{velocity}}$foo{{/velocity}}", true, false);
    +        List<Block> blocks = runIncludeMacro(Context.NEW, "{{velocity}}$foo{{/velocity}}", true);
     
             assertBlocksStartsWith(expected, blocks, this.rendererFactory);
         }
    @@ -290,6 +293,8 @@ void executeWithCurrentContextShowsVelocityMacrosAreShared() throws Exception
                 + "endDocument";
             // @formatter:on
     
    +        when(this.authorizationManager.hasAccess(Right.PROGRAM, INCLUDED_AUHOR, null)).thenReturn(true);
    +
             // We verify that a Velocity macro set in the including page is seen in the included page.
             List<Block> blocks = runIncludeMacroWithPreVelocity(Context.CURRENT, "#macro(testmacro)#end",
                 "{{velocity}}#testmacro{{/velocity}}");
    @@ -337,7 +342,7 @@ void executeWhenIncludingDocumentWithRelativeReferences() throws Exception
             PageReference includedPageReference = new PageReference("includedWiki", "includedSpace", "includedPage");
             setupDocumentMocks("includedWiki:includedSpace.includedPage", includedDocumentReference,
                 "includedWiki:includedSpace/includedPage", includedPageReference,
    -            "[[page]] [[attach:test.png]] image:test.png", false);
    +            "[[page]] [[attach:test.png]] image:test.png");
             when(this.dab.getCurrentDocumentReference()).thenReturn(includedDocumentReference);
     
             IncludeMacroParameters parameters = new IncludeMacroParameters();
    @@ -383,8 +388,7 @@ void adaptIdsOfIncludedHeadingsAndImages() throws Exception
     
             DocumentReference includedDocumentReference =
                 new DocumentReference("includedWiki", "includedSpace", "includedPage");
    -        setupDocumentMocks("includedWiki:includedSpace.includedPage", includedDocumentReference, documentContent,
    -            false);
    +        setupDocumentMocks("includedWiki:includedSpace.includedPage", includedDocumentReference, documentContent);
             when(this.dab.getCurrentDocumentReference()).thenReturn(includedDocumentReference);
     
             IncludeMacroParameters parameters = new IncludeMacroParameters();
    @@ -441,7 +445,7 @@ void executeWithRecursiveIncludeContextNew() throws Exception
             parameters.setContext(Context.NEW);
     
             DocumentReference includedDocumentReference = new DocumentReference("wiki", "space", "page");
    -        setupDocumentMocks("wiki:space.page", includedDocumentReference, "", false);
    +        setupDocumentMocks("wiki:space.page", includedDocumentReference, "");
     
             when(documentDisplayer.display(same(this.includedDocument), any(DocumentDisplayerParameters.class)))
                 .thenAnswer((Answer) invocation -> {
    @@ -482,7 +486,7 @@ void executeInsideSourceMetaDataBlockAndWithRelativeDocumentReferencePassed() th
     
             DocumentReference sourceReference = new DocumentReference("wiki", "space", "page");
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "relativePage");
    -        setupDocumentMocks("relativePage", resolvedReference, "content", false);
    +        setupDocumentMocks("relativePage", resolvedReference, "content");
             when(this.dab.getCurrentDocumentReference()).thenReturn(sourceReference);
     
             List<Block> blocks = this.includeMacro.execute(parameters, null, macroContext);
    @@ -509,10 +513,11 @@ void executeWhenSectionSpecified() throws Exception
             IncludeMacroParameters parameters = new IncludeMacroParameters();
             parameters.setReference("document");
             parameters.setSection("Hsection");
    +        parameters.setAuthor(Author.CURRENT);
     
             MacroTransformationContext macroContext = createMacroTransformationContext("whatever", false);
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "document");
    -        setupDocumentMocks("document", resolvedReference, "content1\n\n= section =\ncontent2", false);
    +        setupDocumentMocks("document", resolvedReference, "content1\n\n= section =\ncontent2");
     
             List<Block> blocks = this.includeMacro.execute(parameters, null, macroContext);
     
    @@ -528,7 +533,7 @@ void executeWhenInvalidSectionSpecified() throws Exception
     
             MacroTransformationContext macroContext = createMacroTransformationContext("whatever", false);
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "document");
    -        setupDocumentMocks("document", resolvedReference, "content", false);
    +        setupDocumentMocks("document", resolvedReference, "content");
             when(this.dab.getCurrentDocumentReference())
                 .thenReturn(new DocumentReference("wiki", "Space", "IncludingPage"));
     
    @@ -553,10 +558,11 @@ void executeWhenExcludeFirstHeadingTrueAndSectionIsFirstBlock() throws Exception
             IncludeMacroParameters parameters = new IncludeMacroParameters();
             parameters.setReference("document");
             parameters.setExcludeFirstHeading(true);
    +        parameters.setAuthor(Author.CURRENT);
     
             MacroTransformationContext macroContext = createMacroTransformationContext("whatever", false);
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "document");
    -        setupDocumentMocks("document", resolvedReference, "= Heading =\ncontent", false);
    +        setupDocumentMocks("document", resolvedReference, "= Heading =\ncontent");
             when(this.dab.getCurrentDocumentReference())
                 .thenReturn(new DocumentReference("wiki", "Space", "IncludingPage"));
     
    @@ -585,10 +591,12 @@ void executeWhenExcludeFirstHeadingTrueAndSectionSpecifiedAndHeadingIsFirstBlock
     
             MacroTransformationContext macroContext = createMacroTransformationContext("whatever", false);
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "document");
    -        setupDocumentMocks("document", resolvedReference, "= Heading =\ncontent", false);
    +        setupDocumentMocks("document", resolvedReference, "= Heading =\ncontent");
             when(this.dab.getCurrentDocumentReference())
                 .thenReturn(new DocumentReference("wiki", "Space", "IncludingPage"));
     
    +        when(this.authorizationManager.hasAccess(Right.PROGRAM, INCLUDED_AUHOR, null)).thenReturn(true);
    +
             List<Block> blocks = this.includeMacro.execute(parameters, null, macroContext);
     
             assertBlocks(expected, blocks, this.rendererFactory);
    @@ -612,10 +620,11 @@ void executeWhenExcludeFirstHeadingFalseAndSectionIsFirstBlock() throws Exceptio
             IncludeMacroParameters parameters = new IncludeMacroParameters();
             parameters.setReference("document");
             parameters.setExcludeFirstHeading(false);
    +        parameters.setAuthor(Author.CURRENT);
     
             MacroTransformationContext macroContext = createMacroTransformationContext("whatever", false);
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "document");
    -        setupDocumentMocks("document", resolvedReference, "=content=", false);
    +        setupDocumentMocks("document", resolvedReference, "=content=");
             when(this.dab.getCurrentDocumentReference())
                 .thenReturn(new DocumentReference("wiki", "Space", "IncludingPage"));
     
    @@ -644,11 +653,12 @@ void executeWhenExcludeFirstHeadingTrueAndSectionIsNotFirstBlock() throws Except
             IncludeMacroParameters parameters = new IncludeMacroParameters();
             parameters.setReference("document");
             parameters.setExcludeFirstHeading(true);
    +        parameters.setAuthor(Author.CURRENT);
     
             // Getting the macro context
             MacroTransformationContext macroContext = createMacroTransformationContext("whatever", false);
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "document");
    -        setupDocumentMocks("document", resolvedReference, "(((= content =)))", false);
    +        setupDocumentMocks("document", resolvedReference, "(((= content =)))");
     
             List<Block> blocks = this.includeMacro.execute(parameters, null, macroContext);
             assertBlocks(expected, blocks, this.rendererFactory);
    @@ -664,14 +674,14 @@ private MacroTransformationContext createMacroTransformationContext(String docum
         }
     
         private void setupDocumentMocks(String includedReferenceString, DocumentReference includedReference,
    -        String includedContent, boolean sameAuthors) throws Exception
    +        String includedContent) throws Exception
         {
    -        setupDocumentMocks(includedReferenceString, includedReference, null, null, includedContent, sameAuthors);
    +        setupDocumentMocks(includedReferenceString, includedReference, null, null, includedContent);
         }
     
         private void setupDocumentMocks(String includedDocumentReferenceString, DocumentReference includedDocumentReference,
    -        String includedPageReferenceString, PageReference includedPageReference, String includedContent,
    -        boolean sameAuthors) throws Exception
    +        String includedPageReferenceString, PageReference includedPageReference, String includedContent)
    +        throws Exception
         {
             when(this.macroEntityReferenceResolver.resolve(eq(includedDocumentReferenceString), eq(EntityType.DOCUMENT),
                 any(MacroBlock.class))).thenReturn(includedDocumentReference);
    @@ -690,12 +700,7 @@ private void setupDocumentMocks(String includedDocumentReferenceString, Document
             when(this.includedDocument.getSyntax()).thenReturn(Syntax.XWIKI_2_0);
             when(this.includedDocument.getXDOM()).thenReturn(getXDOM(includedContent));
             when(this.includedDocument.getRealLanguage()).thenReturn("");
    -
    -        if (sameAuthors) {
    -            when(this.includedDocument.getContentAuthorReference()).thenReturn(INCLUDER_AUHOR);
    -        } else {
    -            when(this.includedDocument.getContentAuthorReference()).thenReturn(INCLUDED_AUHOR);
    -        }
    +        when(this.includedDocument.getContentAuthorReference()).thenReturn(INCLUDED_AUHOR);
         }
     
         private XDOM getXDOM(String content) throws Exception
    @@ -717,19 +722,28 @@ private List<Block> runIncludeMacroWithPreVelocity(Context context, String veloc
     
         private List<Block> runIncludeMacro(final Context context, String includedContent) throws Exception
         {
    -        return runIncludeMacro(context, includedContent, false, false);
    +        return runIncludeMacro(context, includedContent, false);
    +    }
    +
    +    private List<Block> runIncludeMacro(final Context context, String includedContent, boolean restricted)
    +        throws Exception
    +    {
    +        return runIncludeMacro(context, null, includedContent, restricted);
         }
     
    -    private List<Block> runIncludeMacro(final Context context, String includedContent, boolean restricted,
    -        boolean sameAuthor) throws Exception
    +    private List<Block> runIncludeMacro(final Context context, final Author author, String includedContent,
    +        boolean restricted) throws Exception
         {
             DocumentReference includedDocumentReference = new DocumentReference("wiki", "Space", "IncludedPage");
             String includedDocStringRef = "wiki:space.page";
    -        setupDocumentMocks(includedDocStringRef, includedDocumentReference, includedContent, sameAuthor);
    +        setupDocumentMocks(includedDocStringRef, includedDocumentReference, includedContent);
     
             IncludeMacroParameters parameters = new IncludeMacroParameters();
             parameters.setReference(includedDocStringRef);
             parameters.setContext(context);
    +        if (author != null) {
    +            parameters.setAuthor(author);
    +        }
     
             // Create a Macro transformation context with the Macro transformation object defined so that the include
             // macro can transform included page which is using a new context.
    @@ -746,11 +760,11 @@ private List<Block> runIncludeMacro(final Context context, String includedConten
                 verify(this.dab).pushDocumentInContext(any(Map.class), same(this.includedDocument));
                 verify(this.dab).popDocumentFromContext(any(Map.class));
             } else {
    -            if (sameAuthor) {
    +            if (author == Author.CURRENT || this.authorizationManager.hasAccess(Right.PROGRAM, INCLUDED_AUHOR, null)) {
                     verifyNoInteractions(this.authorExecutor);
                 } else {
    -                verify(this.authorExecutor).call(any(), eq(INCLUDED_AUHOR),
    -                    eq(this.includedDocument.getDocumentReference()));
    +                DocumentReference includedReference = this.includedDocument.getDocumentReference();
    +                verify(this.authorExecutor).call(any(), eq(INCLUDED_AUHOR), eq(includedReference));
                 }
             }
     
    
b48116a3ebe9

XWIKI-5027: Improve included content transformation

https://github.com/xwiki/xwiki-platformThomas MortagneDec 1, 2022via ghsa
8 files changed · +66 34
  • xwiki-platform-core/xwiki-platform-display/xwiki-platform-display-macro/src/main/java/org/xwiki/rendering/internal/macro/display/DisplayMacro.java+1 4 modified
    @@ -65,9 +65,6 @@ public DisplayMacro()
         {
             super("Display", DESCRIPTION, DisplayMacroParameters.class);
     
    -        // The display macro must execute first since if it runs with the current context it needs to bring
    -        // all the macros from the displayed page before the other macros are executed.
    -        setPriority(10);
             setDefaultCategories(Set.of(DEFAULT_CATEGORY_CONTENT));
         }
     
    @@ -97,7 +94,7 @@ public List<Block> execute(DisplayMacroParameters parameters, String content, Ma
             }
     
             // Step 3: Check right
    -        if (!this.authorization.hasAccess(Right.VIEW, documentBridge.getDocumentReference())) {
    +        if (!this.contextualAuthorization.hasAccess(Right.VIEW, documentBridge.getDocumentReference())) {
                 throw new MacroExecutionException(
                     String.format("Current user [%s] doesn't have view rights on document [%s]",
                         this.documentAccessBridge.getCurrentUserReference(), documentBridge.getDocumentReference()));
    
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-context/src/main/java/org/xwiki/rendering/internal/macro/context/ContextMacro.java+0 3 modified
    @@ -90,9 +90,6 @@ public ContextMacro()
             super("Context", DESCRIPTION, new DefaultContentDescriptor(CONTENT_DESCRIPTION, true, Block.LIST_BLOCK_TYPE),
                 ContextMacroParameters.class);
     
    -        // The Context macro must execute early since it can contain include macros which can bring stuff like headings
    -        // for other macros (TOC macro, etc). Make it the same priority as the Include macro.
    -        setPriority(10);
             setDefaultCategories(Set.of(DEFAULT_CATEGORY_DEVELOPMENT));
         }
     
    
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/main/java/org/xwiki/rendering/internal/macro/include/AbstractIncludeMacro.java+1 1 modified
    @@ -57,7 +57,7 @@ public abstract class AbstractIncludeMacro<P> extends AbstractMacro<P>
         protected DocumentAccessBridge documentAccessBridge;
     
         @Inject
    -    protected ContextualAuthorizationManager authorization;
    +    protected ContextualAuthorizationManager contextualAuthorization;
     
         /**
          * Used to serialize resolved document links into a string again since the Rendering API only manipulates Strings
    
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/main/java/org/xwiki/rendering/internal/macro/include/IncludeMacro.java+11 10 modified
    @@ -22,7 +22,6 @@
     import java.util.Collections;
     import java.util.List;
     import java.util.Map;
    -import java.util.Objects;
     import java.util.Set;
     import java.util.Stack;
     
    @@ -44,10 +43,12 @@
     import org.xwiki.rendering.listener.MetaData;
     import org.xwiki.rendering.macro.MacroExecutionException;
     import org.xwiki.rendering.macro.include.IncludeMacroParameters;
    +import org.xwiki.rendering.macro.include.IncludeMacroParameters.Author;
     import org.xwiki.rendering.macro.include.IncludeMacroParameters.Context;
     import org.xwiki.rendering.transformation.MacroTransformationContext;
     import org.xwiki.rendering.transformation.TransformationManager;
     import org.xwiki.security.authorization.AuthorExecutor;
    +import org.xwiki.security.authorization.AuthorizationManager;
     import org.xwiki.security.authorization.Right;
     
     /**
    @@ -74,16 +75,16 @@ public class IncludeMacro extends AbstractIncludeMacro<IncludeMacroParameters>
         @Inject
         private AuthorExecutor authorExecutor;
     
    +    @Inject
    +    protected AuthorizationManager authorization;
    +
         /**
          * Default constructor.
          */
         public IncludeMacro()
         {
             super("Include", DESCRIPTION, IncludeMacroParameters.class);
     
    -        // The include macro must execute first since if it runs with the current context it needs to bring
    -        // all the macros from the included page before the other macros are executed.
    -        setPriority(10);
             setDefaultCategories(Set.of(DEFAULT_CATEGORY_CONTENT));
         }
     
    @@ -113,7 +114,7 @@ public List<Block> execute(IncludeMacroParameters parameters, String content, Ma
             }
     
             // Step 3: Check right
    -        if (!this.authorization.hasAccess(Right.VIEW, documentBridge.getDocumentReference())) {
    +        if (!this.contextualAuthorization.hasAccess(Right.VIEW, documentBridge.getDocumentReference())) {
                 throw new MacroExecutionException(
                     String.format("Current user [%s] doesn't have view rights on document [%s]",
                         this.documentAccessBridge.getCurrentUserReference(), documentBridge.getDocumentReference()));
    @@ -177,17 +178,17 @@ public List<Block> execute(IncludeMacroParameters parameters, String content, Ma
                 metadata.getMetaData().addMetaData(MetaData.BASE, source);
             }
     
    -        // Step 7: If the included content author is different from the current author, we have to execute it right now
    -        // so that it used the proper rights
    -        // Get the translated version of the document to compare with the right author
    +        // Step 7: The the include macro is explicitly configured to be executed with the included document content
    +        // author of if that author does not have programming right, execute it right away
    +        // Get the translated version of the document to get the content author
             DocumentModelBridge translatedDocumentBridge;
             try {
                 translatedDocumentBridge = this.documentAccessBridge.getTranslatedDocumentInstance(documentBridge);
             } catch (Exception e) {
                 throw new MacroExecutionException("Failed to retrieve the translated version of the document", e);
             }
    -        if (!Objects.equals(translatedDocumentBridge.getContentAuthorReference(),
    -            this.documentAccessBridge.getCurrentAuthorReference())) {
    +        if (parameters.getAuthor() == Author.TARGET || parameters.getAuthor() == Author.AUTO && !this.authorization
    +            .hasAccess(Right.PROGRAM, translatedDocumentBridge.getContentAuthorReference(), null)) {
                 // Merge the two XDOM before executing the included content so that it's as close as possible to the expect
                 // execution conditions
                 MacroBlock includeMacro = context.getCurrentMacroBlock();
    
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/main/java/org/xwiki/rendering/macro/include/IncludeMacroParameters.java+53 7 modified
    @@ -54,6 +54,30 @@ public enum Context
             CURRENT
         }
     
    +    /**
    +     * Control which author to execute the included content with.
    +     * 
    +     * @since 15.0RC1
    +     */
    +    public enum Author
    +    {
    +        /**
    +         * Apply TARGET option unless the target author has programming right in which case it applies CURRENT (mainly
    +         * for retro-compatibility reasons).
    +         */
    +        AUTO,
    +
    +        /**
    +         * The content is executed with the right of the current author which uses the include macro.
    +         */
    +        CURRENT,
    +
    +        /**
    +         * The content is executed with the right of the included content author.
    +         */
    +        TARGET
    +    }
    +
         /**
          * @see #getReference()
          */
    @@ -74,12 +98,14 @@ public enum Context
          * @see #getSection()
          */
         private String section;
    -    
    +
         /**
          * @see #isExcludeFirstHeading()
          */
         private boolean excludeFirstHeading;
    -    
    +
    +    private Author author;
    +
         /**
          * @param reference the reference of the resource to include
          * @since 3.4M1
    @@ -122,9 +148,9 @@ public String getSection()
         }
     
         /**
    -     * @param excludeFirstHeading {@code true} to remove the first heading found inside
    -     *        the document or the section, {@code false} to keep it 
    -     * @since 12.4RC1 
    +     * @param excludeFirstHeading {@code true} to remove the first heading found inside the document or the section,
    +     *            {@code false} to keep it
    +     * @since 12.4RC1
          */
         @PropertyName("Exclude First Heading")
         @PropertyDescription("Exclude the first heading from the included document or section.")
    @@ -133,10 +159,10 @@ public void setExcludeFirstHeading(boolean excludeFirstHeading)
         {
             this.excludeFirstHeading = excludeFirstHeading;
         }
    -    
    +
         /**
          * @return whether to exclude the first heading from the included document or section, or not.
    -     * @since 12.4RC1 
    +     * @since 12.4RC1
          */
         public boolean isExcludeFirstHeading()
         {
    @@ -206,4 +232,24 @@ public void setPage(String page)
             this.reference = page;
             this.type = EntityType.PAGE;
         }
    +
    +    /**
    +     * @return the author to use to execute the content
    +     * @since 15.0RC1
    +     */
    +    public Author getAuthor()
    +    {
    +        return this.author;
    +    }
    +
    +    /**
    +     * @param author the author to use to execute the content
    +     * @since 15.0RC1
    +     */
    +    @PropertyDescription("The author to use to execute the content")
    +    @PropertyAdvanced
    +    public void setAuthor(Author author)
    +    {
    +        this.author = author;
    +    }
     }
    
  • xwiki-platform-core/xwiki-platform-template/xwiki-platform-template-api/src/main/java/org/xwiki/template/internal/macro/TemplateMacro.java+0 3 modified
    @@ -63,9 +63,6 @@ public TemplateMacro()
         {
             super("Template", DESCRIPTION, TemplateMacroParameters.class);
     
    -        // The template macro must execute first since if it runs with the current context it needs to bring
    -        // all the macros from the template before the other macros are executed.
    -        setPriority(10);
             setDefaultCategories(Set.of(DEFAULT_CATEGORY_DEVELOPMENT));
         }
     
    
  • xwiki-platform-core/xwiki-platform-uiextension/xwiki-platform-uiextension-api/src/main/java/org/xwiki/uiextension/internal/macro/UIExtensionMacro.java+0 3 modified
    @@ -66,9 +66,6 @@ public UIExtensionMacro()
         {
             super("UI Extensions", DESCRIPTION, UIExtensionsMacroParameters.class);
     
    -        // The ui extensions macro must execute first since if it runs with the current context it needs to bring
    -        // all the macros from the extension before the other macros are executed.
    -        setPriority(10);
             setDefaultCategories(Set.of(DEFAULT_CATEGORY_DEVELOPMENT));
         }
     
    
  • xwiki-platform-core/xwiki-platform-uiextension/xwiki-platform-uiextension-api/src/main/java/org/xwiki/uiextension/internal/macro/UIExtensionsMacro.java+0 3 modified
    @@ -64,9 +64,6 @@ public UIExtensionsMacro()
         {
             super("UI Extensions", DESCRIPTION, UIExtensionsMacroParameters.class);
     
    -        // The ui extensions macro must execute first since if it runs with the current context it needs to bring
    -        // all the macros from the extension before the other macros are executed.
    -        setPriority(10);
             setDefaultCategories(Set.of(DEFAULT_CATEGORY_DEVELOPMENT));
         }
     
    
c1fb14402ce2

XWIKI-5027: Improve included content transformation

https://github.com/xwiki/xwiki-platformThomas MortagneNov 9, 2022via ghsa
2 files changed · +154 41
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/main/java/org/xwiki/rendering/internal/macro/include/IncludeMacro.java+47 3 modified
    @@ -22,6 +22,7 @@
     import java.util.Collections;
     import java.util.List;
     import java.util.Map;
    +import java.util.Objects;
     import java.util.Set;
     import java.util.Stack;
     
    @@ -36,6 +37,7 @@
     import org.xwiki.properties.BeanManager;
     import org.xwiki.properties.PropertyException;
     import org.xwiki.rendering.block.Block;
    +import org.xwiki.rendering.block.MacroBlock;
     import org.xwiki.rendering.block.MacroMarkerBlock;
     import org.xwiki.rendering.block.MetaDataBlock;
     import org.xwiki.rendering.block.XDOM;
    @@ -44,6 +46,8 @@
     import org.xwiki.rendering.macro.include.IncludeMacroParameters;
     import org.xwiki.rendering.macro.include.IncludeMacroParameters.Context;
     import org.xwiki.rendering.transformation.MacroTransformationContext;
    +import org.xwiki.rendering.transformation.TransformationManager;
    +import org.xwiki.security.authorization.AuthorExecutor;
     import org.xwiki.security.authorization.Right;
     
     /**
    @@ -64,6 +68,12 @@ public class IncludeMacro extends AbstractIncludeMacro<IncludeMacroParameters>
         @Inject
         private BeanManager beans;
     
    +    @Inject
    +    private TransformationManager transformationManager;
    +
    +    @Inject
    +    private AuthorExecutor authorExecutor;
    +
         /**
          * Default constructor.
          */
    @@ -88,8 +98,8 @@ public List<Block> execute(IncludeMacroParameters parameters, String content, Ma
             throws MacroExecutionException
         {
             // Step 1: Perform checks.
    -        EntityReference includedReference = resolve(context.getCurrentMacroBlock(), parameters.getReference(),
    -            parameters.getType(), "include");
    +        EntityReference includedReference =
    +            resolve(context.getCurrentMacroBlock(), parameters.getReference(), parameters.getType(), "include");
             checkRecursion(context.getCurrentMacroBlock(), includedReference);
     
             // Step 2: Retrieve the included document.
    @@ -149,7 +159,7 @@ public List<Block> execute(IncludeMacroParameters parameters, String content, Ma
                     references.pop();
                 }
             }
    -        
    +
             // Step 5: If the user has asked for it, remove both Section and Heading Blocks if the first included block is
             // a Section block with a Heading block inside.
             if (parameters.isExcludeFirstHeading()) {
    @@ -167,6 +177,40 @@ public List<Block> execute(IncludeMacroParameters parameters, String content, Ma
                 metadata.getMetaData().addMetaData(MetaData.BASE, source);
             }
     
    +        // Step 7: If the included content author is different from the current author, we have to execute it right now
    +        // so that it used the proper rights
    +        // Get the translated version of the document to compare with the right author
    +        DocumentModelBridge translatedDocumentBridge;
    +        try {
    +            translatedDocumentBridge = this.documentAccessBridge.getTranslatedDocumentInstance(documentBridge);
    +        } catch (Exception e) {
    +            throw new MacroExecutionException("Failed to retrieve the translated version of the document", e);
    +        }
    +        if (!Objects.equals(translatedDocumentBridge.getContentAuthorReference(),
    +            this.documentAccessBridge.getCurrentAuthorReference())) {
    +            // Merge the two XDOM before executing the included content so that it's as close as possible to the expect
    +            // execution conditions
    +            MacroBlock includeMacro = context.getCurrentMacroBlock();
    +            MacroMarkerBlock includeMacroMarker = new MacroMarkerBlock(includeMacro.getId(),
    +                includeMacro.getParameters(), Collections.singletonList(metadata), includeMacro.isInline());
    +            includeMacro.getParent().replaceChild(includeMacroMarker, includeMacro);
    +
    +            try {
    +                // Execute the content with the right author
    +                // Keep the same transformation context
    +                this.authorExecutor.call(() -> {
    +                    this.transformationManager.performTransformations(metadata, context.getTransformationContext());
    +                    return null;
    +                }, translatedDocumentBridge.getContentAuthorReference(), documentBridge.getDocumentReference());
    +            } catch (Exception e) {
    +                throw new MacroExecutionException("Failed to execute tranformations for document ["
    +                    + translatedDocumentBridge.getDocumentReference() + "]");
    +            } finally {
    +                // Put back the macro in the main XDOM (it will be replaced that the current macro transformation)
    +                includeMacroMarker.getParent().replaceChild(includeMacro, includeMacroMarker);
    +            }
    +        }
    +
             return Collections.singletonList(metadata);
         }
     
    
  • xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-macros/xwiki-platform-rendering-macro-include/src/test/java/org/xwiki/rendering/internal/macro/include/IncludeMacroTest.java+107 38 modified
    @@ -25,11 +25,14 @@
     import java.util.HashMap;
     import java.util.List;
     import java.util.Map;
    +import java.util.concurrent.Callable;
     
     import javax.inject.Named;
     
     import org.junit.jupiter.api.BeforeEach;
     import org.junit.jupiter.api.Test;
    +import org.mockito.Mock;
    +import org.mockito.invocation.InvocationOnMock;
     import org.mockito.stubbing.Answer;
     import org.xwiki.bridge.DocumentAccessBridge;
     import org.xwiki.bridge.DocumentModelBridge;
    @@ -64,6 +67,7 @@
     import org.xwiki.rendering.transformation.MacroTransformationContext;
     import org.xwiki.rendering.transformation.Transformation;
     import org.xwiki.rendering.wiki.WikiModel;
    +import org.xwiki.security.authorization.AuthorExecutor;
     import org.xwiki.security.authorization.AuthorizationManager;
     import org.xwiki.security.authorization.ContextualAuthorizationManager;
     import org.xwiki.security.authorization.DefaultAuthorizationManager;
    @@ -83,6 +87,7 @@
     import static org.mockito.ArgumentMatchers.same;
     import static org.mockito.Mockito.mock;
     import static org.mockito.Mockito.verify;
    +import static org.mockito.Mockito.verifyNoInteractions;
     import static org.mockito.Mockito.when;
     import static org.xwiki.rendering.test.integration.junit5.BlockAssert.assertBlocks;
     import static org.xwiki.rendering.test.integration.junit5.BlockAssert.assertBlocksStartsWith;
    @@ -94,18 +99,16 @@
      * @since 1.5M2
      */
     @ComponentTest
    -@AllComponents(excludes = {
    -    CurrentMacroEntityReferenceResolver.class,
    -    DefaultAuthorizationManager.class
    -})
    +@AllComponents(excludes = {CurrentMacroEntityReferenceResolver.class, DefaultAuthorizationManager.class})
     class IncludeMacroTest
     {
    +    private final static DocumentReference INCLUDER_AUHOR = new DocumentReference("wiki", "XWiki", "includer");
    +
    +    private final static DocumentReference INCLUDED_AUHOR = new DocumentReference("wiki", "XWiki", "included");
    +
         @InjectComponentManager
         private MockitoComponentManager componentManager;
     
    -    @MockComponent
    -    private DocumentModelBridge includedDocument;
    -
         @MockComponent
         private DocumentAccessBridge dab;
     
    @@ -120,6 +123,12 @@ class IncludeMacroTest
         @Named("current")
         private AttachmentReferenceResolver<String> currentAttachmentReferenceResolver;
     
    +    @MockComponent
    +    private AuthorExecutor authorExecutor;
    +
    +    @Mock
    +    private DocumentModelBridge includedDocument;
    +
         /**
          * Mocks the component that is used to resolve the 'reference' parameter.
          */
    @@ -141,6 +150,8 @@ public void setUp() throws Exception
             this.includeMacro = this.componentManager.getInstance(Macro.class, "include");
             this.rendererFactory = this.componentManager.getInstance(PrintRendererFactory.class, "event/1.0");
     
    +        when(this.dab.getCurrentAuthorReference()).thenReturn(INCLUDER_AUHOR);
    +
             // Put a fake XWiki context on the execution context.
             Execution execution = this.componentManager.getInstance(Execution.class);
             ExecutionContextManager ecm = this.componentManager.getInstance(ExecutionContextManager.class);
    @@ -153,6 +164,15 @@ public void setUp() throws Exception
     
             // Register a WikiModel mock so that we're in wiki mode (otherwise links will be considered as URLs for ex).
             this.componentManager.registerMockComponent(WikiModel.class);
    +
    +        when(this.authorExecutor.call(any(), any(), any())).then(new Answer<Void>()
    +        {
    +            @Override
    +            public Void answer(InvocationOnMock invocation) throws Throwable
    +            {
    +                return ((Callable<Void>) invocation.getArgument(0)).call();
    +            }
    +        });
         }
     
         @Test
    @@ -168,11 +188,50 @@ void execute() throws Exception
                 + "endDocument";
             // @formatter:on
     
    -        List<Block> blocks = runIncludeMacro(Context.CURRENT, "word", false);
    +        List<Block> blocks = runIncludeMacro(Context.CURRENT, "word", false, true);
     
             assertBlocks(expected, blocks, this.rendererFactory);
         }
     
    +    @Test
    +    void executeWithDifferentAuthors() throws Exception
    +    {
    +        // @formatter:off
    +        String expected = "beginDocument\n"
    +            + "beginMetaData [[source]=[wiki:Space.IncludedPage][syntax]=[XWiki 2.0]]\n"
    +            + "beginParagraph\n"
    +            + "onWord [word]\n"
    +            + "endParagraph\n"
    +            + "endMetaData [[source]=[wiki:Space.IncludedPage][syntax]=[XWiki 2.0]]\n"
    +            + "endDocument";
    +        // @formatter:on
    +
    +        List<Block> blocks = runIncludeMacro(Context.CURRENT, "word", false, false);
    +
    +        assertBlocks(expected, blocks, this.rendererFactory);
    +    }
    +
    +    @Test
    +    void executeWithCurrentUserNoView() throws Exception
    +    {
    +        String referenceString = "reference";
    +        DocumentReference reference = new DocumentReference("wiki", "space", "page");
    +
    +        when(this.macroEntityReferenceResolver.resolve(eq(referenceString), eq(EntityType.DOCUMENT),
    +            any(MacroBlock.class))).thenReturn(reference);
    +        when(this.dab.getDocumentInstance((EntityReference) reference)).thenReturn(this.includedDocument);
    +        when(this.includedDocument.getDocumentReference()).thenReturn(reference);
    +        when(this.contextualAuthorizationManager.hasAccess(Right.VIEW, reference)).thenReturn(false);
    +
    +        IncludeMacroParameters parameters = new IncludeMacroParameters();
    +        parameters.setReference(referenceString);
    +
    +        Throwable exception = assertThrows(MacroExecutionException.class,
    +            () -> this.includeMacro.execute(parameters, null, createMacroTransformationContext("whatever", false)));
    +        assertEquals("Current user [null] doesn't have view rights on document [wiki:space.page]",
    +            exception.getMessage());
    +    }
    +
         @Test
         void executeWithNewContextShowsVelocityMacrosAreIsolated() throws Exception
         {
    @@ -215,7 +274,7 @@ void executeWithNewContextShowsPassingOnRestrictedFlag() throws Exception
             // @formatter:on
     
             // We verify that a Velocity macro set in the including page is not seen in the included page.
    -        List<Block> blocks = runIncludeMacro(Context.NEW, "{{velocity}}$foo{{/velocity}}", true);
    +        List<Block> blocks = runIncludeMacro(Context.NEW, "{{velocity}}$foo{{/velocity}}", true, false);
     
             assertBlocksStartsWith(expected, blocks, this.rendererFactory);
         }
    @@ -278,7 +337,7 @@ void executeWhenIncludingDocumentWithRelativeReferences() throws Exception
             PageReference includedPageReference = new PageReference("includedWiki", "includedSpace", "includedPage");
             setupDocumentMocks("includedWiki:includedSpace.includedPage", includedDocumentReference,
                 "includedWiki:includedSpace/includedPage", includedPageReference,
    -            "[[page]] [[attach:test.png]] image:test.png");
    +            "[[page]] [[attach:test.png]] image:test.png", false);
             when(this.dab.getCurrentDocumentReference()).thenReturn(includedDocumentReference);
     
             IncludeMacroParameters parameters = new IncludeMacroParameters();
    @@ -294,8 +353,7 @@ void executeWhenIncludingDocumentWithRelativeReferences() throws Exception
     
             parameters.setPage("includedWiki:includedSpace/includedPage");
     
    -        blocks =
    -            this.includeMacro.execute(parameters, null, createMacroTransformationContext("whatever", false));
    +        blocks = this.includeMacro.execute(parameters, null, createMacroTransformationContext("whatever", false));
     
             assertBlocks(expected, blocks, this.rendererFactory);
         }
    @@ -321,13 +379,12 @@ void adaptIdsOfIncludedHeadingsAndImages() throws Exception
                 + "endDocument";
             // @formatter:on
     
    -        String documentContent = "= Heading =\n"
    -            + "image:test.png";
    +        String documentContent = "= Heading =\n" + "image:test.png";
     
             DocumentReference includedDocumentReference =
                 new DocumentReference("includedWiki", "includedSpace", "includedPage");
    -        setupDocumentMocks("includedWiki:includedSpace.includedPage", includedDocumentReference,
    -            documentContent);
    +        setupDocumentMocks("includedWiki:includedSpace.includedPage", includedDocumentReference, documentContent,
    +            false);
             when(this.dab.getCurrentDocumentReference()).thenReturn(includedDocumentReference);
     
             IncludeMacroParameters parameters = new IncludeMacroParameters();
    @@ -384,18 +441,17 @@ void executeWithRecursiveIncludeContextNew() throws Exception
             parameters.setContext(Context.NEW);
     
             DocumentReference includedDocumentReference = new DocumentReference("wiki", "space", "page");
    -        setupDocumentMocks("wiki:space.page", includedDocumentReference, "");
    +        setupDocumentMocks("wiki:space.page", includedDocumentReference, "", false);
     
    -        when(documentDisplayer.display(same(this.includedDocument), any(DocumentDisplayerParameters.class))).thenAnswer(
    -            (Answer) invocation -> {
    +        when(documentDisplayer.display(same(this.includedDocument), any(DocumentDisplayerParameters.class)))
    +            .thenAnswer((Answer) invocation -> {
                     // Call again the include macro when the document displayer executes to simulate a recursive call.
                     // Verify that it raises a MacroExecutionException in this case.
                     Throwable exception = assertThrows(MacroExecutionException.class,
                         () -> this.includeMacro.execute(parameters, null, macroContext));
                     assertEquals("Found recursive inclusion of document [wiki:space.page]", exception.getMessage());
                     throw exception;
    -            }
    -        );
    +            });
     
             // Verify that the exception bubbles up.
             Throwable exception = assertThrows(MacroExecutionException.class,
    @@ -426,7 +482,7 @@ void executeInsideSourceMetaDataBlockAndWithRelativeDocumentReferencePassed() th
     
             DocumentReference sourceReference = new DocumentReference("wiki", "space", "page");
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "relativePage");
    -        setupDocumentMocks("relativePage", resolvedReference, "content");
    +        setupDocumentMocks("relativePage", resolvedReference, "content", false);
             when(this.dab.getCurrentDocumentReference()).thenReturn(sourceReference);
     
             List<Block> blocks = this.includeMacro.execute(parameters, null, macroContext);
    @@ -456,7 +512,7 @@ void executeWhenSectionSpecified() throws Exception
     
             MacroTransformationContext macroContext = createMacroTransformationContext("whatever", false);
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "document");
    -        setupDocumentMocks("document", resolvedReference, "content1\n\n= section =\ncontent2");
    +        setupDocumentMocks("document", resolvedReference, "content1\n\n= section =\ncontent2", false);
     
             List<Block> blocks = this.includeMacro.execute(parameters, null, macroContext);
     
    @@ -472,9 +528,9 @@ void executeWhenInvalidSectionSpecified() throws Exception
     
             MacroTransformationContext macroContext = createMacroTransformationContext("whatever", false);
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "document");
    -        setupDocumentMocks("document", resolvedReference, "content");
    -        when(this.dab.getCurrentDocumentReference()).thenReturn(
    -            new DocumentReference("wiki", "Space", "IncludingPage"));
    +        setupDocumentMocks("document", resolvedReference, "content", false);
    +        when(this.dab.getCurrentDocumentReference())
    +            .thenReturn(new DocumentReference("wiki", "Space", "IncludingPage"));
     
             Throwable exception = assertThrows(MacroExecutionException.class,
                 () -> this.includeMacro.execute(parameters, null, macroContext));
    @@ -500,7 +556,7 @@ void executeWhenExcludeFirstHeadingTrueAndSectionIsFirstBlock() throws Exception
     
             MacroTransformationContext macroContext = createMacroTransformationContext("whatever", false);
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "document");
    -        setupDocumentMocks("document", resolvedReference, "= Heading =\ncontent");
    +        setupDocumentMocks("document", resolvedReference, "= Heading =\ncontent", false);
             when(this.dab.getCurrentDocumentReference())
                 .thenReturn(new DocumentReference("wiki", "Space", "IncludingPage"));
     
    @@ -529,7 +585,7 @@ void executeWhenExcludeFirstHeadingTrueAndSectionSpecifiedAndHeadingIsFirstBlock
     
             MacroTransformationContext macroContext = createMacroTransformationContext("whatever", false);
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "document");
    -        setupDocumentMocks("document", resolvedReference, "= Heading =\ncontent");
    +        setupDocumentMocks("document", resolvedReference, "= Heading =\ncontent", false);
             when(this.dab.getCurrentDocumentReference())
                 .thenReturn(new DocumentReference("wiki", "Space", "IncludingPage"));
     
    @@ -559,7 +615,7 @@ void executeWhenExcludeFirstHeadingFalseAndSectionIsFirstBlock() throws Exceptio
     
             MacroTransformationContext macroContext = createMacroTransformationContext("whatever", false);
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "document");
    -        setupDocumentMocks("document", resolvedReference, "=content=");
    +        setupDocumentMocks("document", resolvedReference, "=content=", false);
             when(this.dab.getCurrentDocumentReference())
                 .thenReturn(new DocumentReference("wiki", "Space", "IncludingPage"));
     
    @@ -592,7 +648,7 @@ void executeWhenExcludeFirstHeadingTrueAndSectionIsNotFirstBlock() throws Except
             // Getting the macro context
             MacroTransformationContext macroContext = createMacroTransformationContext("whatever", false);
             DocumentReference resolvedReference = new DocumentReference("wiki", "space", "document");
    -        setupDocumentMocks("document", resolvedReference, "(((= content =)))");
    +        setupDocumentMocks("document", resolvedReference, "(((= content =)))", false);
     
             List<Block> blocks = this.includeMacro.execute(parameters, null, macroContext);
             assertBlocks(expected, blocks, this.rendererFactory);
    @@ -608,14 +664,14 @@ private MacroTransformationContext createMacroTransformationContext(String docum
         }
     
         private void setupDocumentMocks(String includedReferenceString, DocumentReference includedReference,
    -        String includedContent) throws Exception
    +        String includedContent, boolean sameAuthors) throws Exception
         {
    -        setupDocumentMocks(includedReferenceString, includedReference, null, null, includedContent);
    +        setupDocumentMocks(includedReferenceString, includedReference, null, null, includedContent, sameAuthors);
         }
     
         private void setupDocumentMocks(String includedDocumentReferenceString, DocumentReference includedDocumentReference,
    -        String includedPageReferenceString, PageReference includedPageReference, String includedContent)
    -        throws Exception
    +        String includedPageReferenceString, PageReference includedPageReference, String includedContent,
    +        boolean sameAuthors) throws Exception
         {
             when(this.macroEntityReferenceResolver.resolve(eq(includedDocumentReferenceString), eq(EntityType.DOCUMENT),
                 any(MacroBlock.class))).thenReturn(includedDocumentReference);
    @@ -634,6 +690,12 @@ private void setupDocumentMocks(String includedDocumentReferenceString, Document
             when(this.includedDocument.getSyntax()).thenReturn(Syntax.XWIKI_2_0);
             when(this.includedDocument.getXDOM()).thenReturn(getXDOM(includedContent));
             when(this.includedDocument.getRealLanguage()).thenReturn("");
    +
    +        if (sameAuthors) {
    +            when(this.includedDocument.getContentAuthorReference()).thenReturn(INCLUDER_AUHOR);
    +        } else {
    +            when(this.includedDocument.getContentAuthorReference()).thenReturn(INCLUDED_AUHOR);
    +        }
         }
     
         private XDOM getXDOM(String content) throws Exception
    @@ -655,15 +717,15 @@ private List<Block> runIncludeMacroWithPreVelocity(Context context, String veloc
     
         private List<Block> runIncludeMacro(final Context context, String includedContent) throws Exception
         {
    -        return runIncludeMacro(context, includedContent, false);
    +        return runIncludeMacro(context, includedContent, false, false);
         }
     
    -    private List<Block> runIncludeMacro(final Context context, String includedContent, boolean restricted)
    -        throws Exception
    +    private List<Block> runIncludeMacro(final Context context, String includedContent, boolean restricted,
    +        boolean sameAuthor) throws Exception
         {
             DocumentReference includedDocumentReference = new DocumentReference("wiki", "Space", "IncludedPage");
             String includedDocStringRef = "wiki:space.page";
    -        setupDocumentMocks(includedDocStringRef, includedDocumentReference, includedContent);
    +        setupDocumentMocks(includedDocStringRef, includedDocumentReference, includedContent, sameAuthor);
     
             IncludeMacroParameters parameters = new IncludeMacroParameters();
             parameters.setReference(includedDocStringRef);
    @@ -683,6 +745,13 @@ private List<Block> runIncludeMacro(final Context context, String includedConten
             if (context == Context.NEW) {
                 verify(this.dab).pushDocumentInContext(any(Map.class), same(this.includedDocument));
                 verify(this.dab).popDocumentFromContext(any(Map.class));
    +        } else {
    +            if (sameAuthor) {
    +                verifyNoInteractions(this.authorExecutor);
    +            } else {
    +                verify(this.authorExecutor).call(any(), eq(INCLUDED_AUHOR),
    +                    eq(this.includedDocument.getDocumentReference()));
    +            }
             }
     
             return blocks;
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

10

News mentions

0

No linked articles in our index yet.