Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XWIKI-22821: Allow having generic analyzers for different types of macro arguments #3846

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
*/
package org.xwiki.platform.security.requiredrights.internal.analyzer;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import javax.inject.Inject;
Expand All @@ -35,6 +37,8 @@
import org.xwiki.component.manager.ComponentLookupException;
import org.xwiki.component.manager.ComponentManager;
import org.xwiki.component.util.DefaultParameterizedType;
import org.xwiki.platform.security.requiredrights.MacroParameterRequiredRightsAnalyzer;
import org.xwiki.platform.security.requiredrights.MacroRequiredRight;
import org.xwiki.platform.security.requiredrights.MacroRequiredRightsAnalyzer;
import org.xwiki.platform.security.requiredrights.RequiredRightAnalysisResult;
import org.xwiki.platform.security.requiredrights.RequiredRightAnalyzer;
Expand Down Expand Up @@ -122,26 +126,49 @@ private List<RequiredRightAnalysisResult> analyzeWithExceptions(MacroBlock macro
}

private List<RequiredRightAnalysisResult> maybeAnalyzeParameters(MacroBlock macroBlock, Macro<?> macro)
throws RequiredRightsException
{
List<RequiredRightAnalysisResult> results = new ArrayList<>();

Map<String, ParameterDescriptor> parameterDescriptorMap = macro.getDescriptor().getParameterDescriptorMap();

ComponentManager componentManager = this.componentManagerProvider.get();
DefaultMacroRequiredRightReporter reporter = this.macroRequiredRightReporterProvider.get();

for (Map.Entry<String, String> parameter : macroBlock.getParameters().entrySet()) {
ParameterDescriptor parameterDescriptor = parameterDescriptorMap.get(parameter.getKey().toLowerCase());

if (parameterDescriptor != null && parameter.getValue() != null
// Analyze the content if either the display type or the parameter type is wiki syntax as both are a
// strong indication that the content is parsed and executed.
&& (Block.LIST_BLOCK_TYPE.equals(parameterDescriptor.getParameterType())
|| Block.LIST_BLOCK_TYPE.equals(parameterDescriptor.getDisplayType())))
{
results.addAll(analyzeMacroContent(macroBlock, parameter.getValue()));
if (parameterDescriptor != null && parameter.getValue() != null) {
if (parameterDescriptor.getParameterType() != null) {
analyzeMacroParameter(macroBlock, parameter, parameterDescriptor, componentManager, reporter,
parameterDescriptor.getParameterType());
}

if (!Objects.equals(parameterDescriptor.getDisplayType(), parameterDescriptor.getParameterType())
&& parameterDescriptor.getDisplayType() != null)
{
analyzeMacroParameter(macroBlock, parameter, parameterDescriptor, componentManager, reporter,
parameterDescriptor.getDisplayType());
}
}
}

return results;
return reporter.getResults();
}

private static void analyzeMacroParameter(MacroBlock macroBlock, Map.Entry<String, String> parameter,
ParameterDescriptor parameterDescriptor, ComponentManager componentManager,
DefaultMacroRequiredRightReporter reporter, Type parameterType)
{
try {
Type componentType = new DefaultParameterizedType(null, MacroParameterRequiredRightsAnalyzer.class,
parameterType);
if (componentManager.hasComponent(componentType)) {
MacroParameterRequiredRightsAnalyzer<?> analyzer = componentManager.getInstance(componentType);
analyzer.analyze(macroBlock, parameterDescriptor, parameter.getValue(), reporter);
}
} catch (Exception e) {
reporter.report(macroBlock, List.of(MacroRequiredRight.MAYBE_PROGRAM),
"security.requiredrights.macro.analyzer.parameterError",
parameterDescriptor.getId(), macroBlock.getId(), ExceptionUtils.getRootCauseMessage(e));
}
}

private List<RequiredRightAnalysisResult> maybeAnalyzeMacroContent(MacroBlock macroBlock, Macro<?> macro)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ security.requiredrights.macro.script.program=A [{0}] scripting macro requires pr
security.requiredrights.macro.script.script=A [{0}] scripting macro requires script rights.
security.requiredrights.macro.analyzer.error=An error occurred during the analysis of the macro [{0}]. \
Please manually check which rights it requires including its contents. Root cause of the error: [{1}].
security.requiredrights.macro.analyzer.parameterError=An error occurred during the analysis of the parameter [{0}] of \
the macro [{1}]. Please manually check which rights it requires. Root cause of the error: [{2}].

####################
# For objects
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.xwiki.platform.security.requiredrights.MacroParameterRequiredRightsAnalyzer;
import org.xwiki.platform.security.requiredrights.MacroRequiredRight;
import org.xwiki.platform.security.requiredrights.MacroRequiredRightReporter;
import org.xwiki.platform.security.requiredrights.MacroRequiredRightsAnalyzer;
Expand Down Expand Up @@ -58,6 +59,7 @@
import com.xpn.xwiki.test.reference.ReferenceComponentList;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.argThat;
Expand Down Expand Up @@ -106,6 +108,9 @@ class DefaultMacroBlockRequiredRightAnalyzerTest
@MockComponent
private RequiredRightAnalyzer<XDOM> xdomRequiredRightAnalyzer;

@MockComponent
private MacroParameterRequiredRightsAnalyzer<List<Block>> listBlockParameterAnalyzer;

@Test
void analyzeWithCustomAnalyzer() throws Exception
{
Expand Down Expand Up @@ -258,6 +263,16 @@ void analyzeWikiParameters() throws Exception
when(macroDescriptor.getParameterDescriptorMap()).thenReturn(parameterDescriptorMap);
when(macroDescriptor.getContentDescriptor()).thenReturn(new DefaultContentDescriptor(false));

doAnswer(invocationOnMock -> {
MacroBlock macroBlock = invocationOnMock.getArgument(0);
ParameterDescriptor parameterDescriptor = invocationOnMock.getArgument(1);
String value = invocationOnMock.getArgument(2);
MacroRequiredRightReporter reporter = invocationOnMock.getArgument(3);
assertSame(parameterDescriptorMap.get(parameterDescriptor.getId().toLowerCase()), parameterDescriptor);
reporter.analyzeContent(macroBlock, value);
return null;
}).when(this.listBlockParameterAnalyzer).analyze(eq(block), any(), any(), any());

// Stub the macro content parser and the XDOM analyzer to simply pass on the analyzed content as mock name.
// That way, we can easily verify that all parameters were analyzed.
when(this.macroContentParser.parse(any(), any(), any(), anyBoolean(), any(), anyBoolean()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,24 @@
<xwiki.extension.name>Required Rights Macro Analysis API</xwiki.extension.name>
<!-- Category to display in the Extension Manager. -->
<xwiki.extension.category>api</xwiki.extension.category>
<xwiki.jacoco.instructionRatio>0.00</xwiki.jacoco.instructionRatio>
<xwiki.jacoco.instructionRatio>1.00</xwiki.jacoco.instructionRatio>
</properties>
<dependencies>
<dependency>
<groupId>org.xwiki.rendering</groupId>
<artifactId>xwiki-rendering-api</artifactId>
<version>${rendering.version}</version>
</dependency>
<dependency>
<groupId>org.xwiki.rendering</groupId>
<artifactId>xwiki-rendering-transformation-macro</artifactId>
<version>${rendering.version}</version>
</dependency>
<dependency>
<groupId>org.xwiki.commons</groupId>
<artifactId>xwiki-commons-tool-test-component</artifactId>
<version>${commons.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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.platform.security.requiredrights;

import org.xwiki.component.annotation.Role;
import org.xwiki.rendering.block.MacroBlock;
import org.xwiki.rendering.macro.descriptor.ParameterDescriptor;
import org.xwiki.stability.Unstable;

/**
* An analyzer for a macro parameter.
*
* @param <T> the type of the macro parameter.
* @version $Id$
* @since 17.1.0RC1
* @since 16.10.3
* @since 16.4.7
*/
// The type parameter isn't used in the interface itself, but it is used to differentiate component implementations
// for different parameter types so it is definitely used.
@SuppressWarnings("unused")
@Role
@Unstable
public interface MacroParameterRequiredRightsAnalyzer<T>
{
/**
* Analyzes the given parameter value in the given macro block and reports the required rights to the given
* reporter.
*
* @param macroBlock the macro block to analyze
* @param parameterDescriptor the descriptor of the parameter being analyzed
* @param value the value of the parameter being analyzed
* @param reporter the reporter to report the required rights to
*/
void analyze(MacroBlock macroBlock, ParameterDescriptor parameterDescriptor,
String value, MacroRequiredRightReporter reporter);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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.platform.security.requiredrights.internal;

import java.util.List;

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

import org.xwiki.component.annotation.Component;
import org.xwiki.platform.security.requiredrights.MacroParameterRequiredRightsAnalyzer;
import org.xwiki.platform.security.requiredrights.MacroRequiredRight;
import org.xwiki.platform.security.requiredrights.MacroRequiredRightReporter;
import org.xwiki.properties.converter.Converter;
import org.xwiki.rendering.block.MacroBlock;
import org.xwiki.rendering.macro.descriptor.ParameterDescriptor;
import org.xwiki.rendering.macro.source.MacroContentSourceReference;

import static org.xwiki.rendering.macro.source.MacroContentSourceReference.TYPE_SCRIPT;

/**
* Required rights analyzer for {@link MacroContentSourceReference} macro parameters. Reports script right for the
* script type.
*
* @version $Id$
* @since 17.1.0RC1
* @since 16.10.3
* @since 16.4.7
*/
@Component
@Singleton
public class MacroContentSourceReferenceMacroParameterRequiredRightsAnalyzer
implements MacroParameterRequiredRightsAnalyzer<MacroContentSourceReference>
{
@Inject
private Converter<MacroContentSourceReference> macroContentSourceReferenceConverter;

@Override
public void analyze(MacroBlock macroBlock, ParameterDescriptor parameterDescriptor, String value,
MacroRequiredRightReporter reporter)
{
MacroContentSourceReference macroContentSourceReference =
this.macroContentSourceReferenceConverter.convert(MacroContentSourceReference.class, value);

if (TYPE_SCRIPT.equals(macroContentSourceReference.getType())) {
reporter.report(macroBlock, List.of(MacroRequiredRight.SCRIPT),
"security.requiredrights.macro.scriptContentSource",
parameterDescriptor.getId(), macroBlock.getId());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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.platform.security.requiredrights.internal;

import java.util.List;

import javax.inject.Singleton;

import org.xwiki.component.annotation.Component;
import org.xwiki.platform.security.requiredrights.MacroParameterRequiredRightsAnalyzer;
import org.xwiki.platform.security.requiredrights.MacroRequiredRightReporter;
import org.xwiki.rendering.block.Block;
import org.xwiki.rendering.block.MacroBlock;
import org.xwiki.rendering.macro.descriptor.ParameterDescriptor;

/**
* Required rights analyzer for wiki syntax parameters.
*
* @version $Id$
* @since 17.1.0RC1
* @since 16.10.3
* @since 16.4.7
*/
@Component
@Singleton
public class WikiSyntaxMacroParameterRequiredRightsAnalyzer implements MacroParameterRequiredRightsAnalyzer<List<Block>>
{
@Override
public void analyze(MacroBlock macroBlock, ParameterDescriptor parameterDescriptor, String value,
MacroRequiredRightReporter reporter)
{
reporter.analyzeContent(macroBlock, value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# ---------------------------------------------------------------------------
# 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.
# ---------------------------------------------------------------------------

###############################################################################
# Macro required rights localization
#
# This contains the translations of the module in the default language
# (generally English).
#
# Translation key syntax:
# <short top level project name>.<short module name>.<propertyName>
# where:
# * <short top level project name> = top level project name without the "xwiki-" prefix,
# for example: commons, rendering, platform, enterprise, manager, etc
# * <short module name> = the name of the Maven module without the <short top level project name> prefix,
# for example: oldcore, scheduler, activitystream, etc
# * <propertyName> = the name of the property using camel case,
# for example updateJobClassCommitComment
#
# Comments: it's possible to add some detail about a key to make easier to
# translate it by adding a comment before it. To make sure a comment is not
# assigned to the following key use at least three sharps (###) for the comment
# or after it.
#
# Deprecated keys:
# * when deleting a key it should be moved to deprecated section at the end
# of the file (between #@deprecatedstart and #@deprecatedend) and associated to the
# first version in which it started to be deprecated
# * when renaming a key, it should be moved to the same deprecated section
# and a comment should be added with the following syntax:
# #@deprecated new.key.name
# old.key.name=Some translation
###############################################################################

security.requiredrights.macro.scriptContentSource=The script content source in parameter [{0}] of the {1} macro \
requires script right.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.xwiki.platform.security.requiredrights.internal.MacroContentSourceReferenceMacroParameterRequiredRightsAnalyzer
org.xwiki.platform.security.requiredrights.internal.WikiSyntaxMacroParameterRequiredRightsAnalyzer
Loading