VYPR
Moderate severityNVD Advisory· Published Feb 9, 2022· Updated Apr 23, 2025

Open Redirect in xwiki-platform

CVE-2022-23618

Description

XWiki Platform is a generic wiki platform offering runtime services for applications built on top of it. In affected versions there is no protection against URL redirection to untrusted sites, in particular some well known parameters (xredirect) can be used to perform url redirections. This problem has been patched in XWiki 12.10.7 and XWiki 13.3RC1. Users are advised to update. There are no known workarounds for this issue.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.xwiki.platform:xwiki-platform-oldcoreMaven
< 12.10.712.10.7
org.xwiki.platform:xwiki-platform-oldcoreMaven
>= 13.0.0, < 13.3RC113.3RC1

Affected products

1

Patches

1
5251c0208046

XWIKI-10309: Check URL domains based on a whitelist (#1592)

https://github.com/xwiki/xwiki-platformSimon UrliApr 15, 2021via ghsa
40 files changed · +640 9
  • xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/user/impl/xwiki/MyFormAuthenticator.java+3 1 modified
    @@ -41,6 +41,8 @@
     import org.xwiki.security.authentication.AuthenticationFailureManager;
     import com.xpn.xwiki.internal.user.UserAuthenticatedEventNotifier;
     
    +import com.xpn.xwiki.web.XWikiResponse;
    +
     public class MyFormAuthenticator extends FormAuthenticator implements XWikiAuthenticator
     {
         private static final Logger LOGGER = LoggerFactory.getLogger(MyFormAuthenticator.class);
    @@ -244,8 +246,8 @@ public boolean processLogin(String username, String password, String rememberme,
     
                 Boolean bAjax = (Boolean) context.get("ajax");
                 if ((bAjax == null) || (!bAjax.booleanValue())) {
    -                String continueToURL = getContinueToURL(request);
                     // This is the url that the user was initially accessing before being prompted for login.
    +                String continueToURL = getContinueToURL(request);
                     response.sendRedirect(response.encodeRedirectURL(continueToURL));
                 }
             } else {
    
  • xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/XWikiAction.java+6 0 modified
    @@ -981,6 +981,12 @@ protected boolean sendGlobalRedirect(XWikiResponse response, String url, XWikiCo
             return false;
         }
     
    +    /**
    +     * Perform a redirect to the given URL.
    +     * @param response the response to use to perform the redirect
    +     * @param url the location of the redirect
    +     * @throws XWikiException in case of IOException when performing the redirect.
    +     */
         protected void sendRedirect(XWikiResponse response, String url) throws XWikiException
         {
             try {
    
  • xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/XWikiServletResponse.java+20 0 modified
    @@ -21,8 +21,10 @@
     
     import java.io.IOException;
     import java.io.PrintWriter;
    +import java.net.URL;
     import java.util.Collection;
     import java.util.Locale;
    +import java.util.regex.Pattern;
     
     import javax.servlet.ServletOutputStream;
     import javax.servlet.http.Cookie;
    @@ -31,10 +33,12 @@
     import org.apache.commons.lang3.StringUtils;
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
    +import org.xwiki.url.URLSecurityManager;
     
     public class XWikiServletResponse implements XWikiResponse
     {
         private static final Logger LOGGER = LoggerFactory.getLogger(XWikiServletResponse.class);
    +    private static final Pattern ABSOLUTE_URL_PATTERN = Pattern.compile("[a-z0-9]+://.*");
     
         private HttpServletResponse response;
     
    @@ -66,9 +70,25 @@ public void sendRedirect(String redirect) throws IOException
                 LOGGER.warn("Possible HTTP Response Splitting attack, attempting to redirect to [{}]", redirect);
                 return;
             }
    +
    +        // check for trusted domains, only if the given location is an absolute URL.
    +        if (ABSOLUTE_URL_PATTERN.matcher(redirect).matches()) {
    +            if (!getURLSecurityManager().isDomainTrusted(new URL(redirect))) {
    +                LOGGER.warn(
    +                    "Possible phishing attack, attempting to redirect to [{}], this request has been blocked. "
    +                        + "If the request was legitimate, add the domain related to this request in the list "
    +                        + "of trusted domains in the configuration.", redirect);
    +                return;
    +            }
    +        }
             this.response.sendRedirect(redirect);
         }
     
    +    private URLSecurityManager getURLSecurityManager()
    +    {
    +        return Utils.getComponent(URLSecurityManager.class);
    +    }
    +
         @Override
         public void setContentType(String type)
         {
    
  • xwiki-platform-core/xwiki-platform-url/pom.xml+1 0 modified
    @@ -35,6 +35,7 @@
         <!-- Sorted Alphabetically -->
         <module>xwiki-platform-url-api</module>
         <module>xwiki-platform-url-container</module>
    +    <module>xwiki-platform-url-default</module>
         <module>xwiki-platform-url-schemes</module>
       </modules>
     </project>
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-api/pom.xml+1 3 modified
    @@ -32,9 +32,7 @@
       <packaging>jar</packaging>
       <description>Allows configuration of the URL scheme used by XWiki to parse/serialize URLs</description>
       <properties>
    -    <!-- The reason for this low TPC value is because this module is tested using integration tests in the various
    -         URL Scheme modules -->
    -    <xwiki.jacoco.instructionRatio>0.45</xwiki.jacoco.instructionRatio>
    +    <xwiki.jacoco.instructionRatio>0.85</xwiki.jacoco.instructionRatio>
         <!-- Name to display by the Extension Manager -->
         <xwiki.extension.name>URL API</xwiki.extension.name>
       </properties>
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-api/src/main/java/org/xwiki/url/URLConfiguration.java+30 0 modified
    @@ -19,7 +19,11 @@
      */
     package org.xwiki.url;
     
    +import java.util.Collections;
    +import java.util.List;
    +
     import org.xwiki.component.annotation.Role;
    +import org.xwiki.stability.Unstable;
     
     /**
      * Configuration options for the URL module.
    @@ -47,4 +51,30 @@ default boolean useResourceLastModificationDate()
         {
             return true;
         }
    +
    +    /**
    +     * Specify the list of domains that are considered as trusted by the administrators of the wiki: those domains can
    +     * be used safely for redirections from the wiki or for performing other requests on them.
    +     * @return the list of trusted domains that can be used in the wiki.
    +     * @since 13.3RC1
    +     * @since 12.10.7
    +     */
    +    @Unstable
    +    default List<String> getTrustedDomains()
    +    {
    +        return Collections.emptyList();
    +    }
    +
    +    /**
    +     * Define if the trusted domains check should be performed or not. This option is provided only to allow bypassing
    +     * security checks globally on the wiki in case of problems.
    +     * @return {@code true} if the security check on domains should be performed. {@code false} otherwise.
    +     * @since 13.3RC1
    +     * @since 12.10.7
    +     */
    +    @Unstable
    +    default boolean isTrustedDomainsEnabled()
    +    {
    +        return true;
    +    }
     }
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-api/src/main/java/org/xwiki/url/URLSecurityManager.java+56 0 added
    @@ -0,0 +1,56 @@
    +/*
    + * 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.url;
    +
    +import java.net.URL;
    +
    +import org.xwiki.component.annotation.Role;
    +import org.xwiki.stability.Unstable;
    +
    +/**
    + * Dedicated component to perform security checks on URLs.
    + *
    + * @version $Id$
    + * @since 13.3RC1
    + * @since 12.10.7
    + */
    +@Role
    +@Unstable
    +public interface URLSecurityManager
    +{
    +    /**
    +     * Constant to be used in {@link org.xwiki.context.ExecutionContext} with the value {@code "true"} to bypass a
    +     * check of {@link #isDomainTrusted(URL)}.
    +     */
    +    String BYPASS_DOMAIN_SECURITY_CHECK_CONTEXT_PROPERTY = "bypassDomainSecurityCheck";
    +
    +    /**
    +     * Check if the given {@link URL} can be trusted based on the trusted domains of the wiki.
    +     * This method check on both the list of trusted domains given by the configuration
    +     * (see {@link URLConfiguration#getTrustedDomains()}) and the list of aliases used by the wiki descriptors.
    +     * Note that this method always returns {@code true} if {@link URLConfiguration#isTrustedDomainsEnabled()} returns
    +     * {@code true}. Also the method will return {@code true} whenever the {@link org.xwiki.context.ExecutionContext}
    +     * contains a property named {@link #BYPASS_DOMAIN_SECURITY_CHECK_CONTEXT_PROPERTY} with the value {@code "true"}.
    +     *
    +     * @param urlToCheck the URL for which we want to know if the domain is trusted or not.
    +     * @return {@code true} if the URL domain can be trusted or if the check is skipped, {@code false} otherwise
    +     */
    +    boolean isDomainTrusted(URL urlToCheck);
    +}
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/pom.xml+63 0 added
    @@ -0,0 +1,63 @@
    +<?xml version="1.0" encoding="UTF-8"?>
    +
    +<!--
    + * 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.
    +-->
    +
    +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    +  <modelVersion>4.0.0</modelVersion>
    +  <parent>
    +    <groupId>org.xwiki.platform</groupId>
    +    <artifactId>xwiki-platform-url</artifactId>
    +    <version>13.3-SNAPSHOT</version>
    +  </parent>
    +  <artifactId>xwiki-platform-url-default</artifactId>
    +  <name>XWiki Platform - URL - Default</name>
    +  <packaging>jar</packaging>
    +  <description>Default implementations of the API defined in xwiki-platform-url-api</description>
    +  <properties>
    +    <!-- The reason for this low TPC value is because this module is tested using integration tests in the various
    +    URL Scheme modules -->
    +    <xwiki.jacoco.instructionRatio>0.31</xwiki.jacoco.instructionRatio>
    +  </properties>
    +  <dependencies>
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-url-api</artifactId>
    +      <version>${project.version}</version>
    +    </dependency>
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-oldcore</artifactId>
    +      <version>${project.version}</version>
    +    </dependency>
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-wiki-api</artifactId>
    +      <version>${project.version}</version>
    +    </dependency>
    +    <!-- Testing Dependencies -->
    +    <dependency>
    +      <groupId>org.xwiki.commons</groupId>
    +      <artifactId>xwiki-commons-tool-test-component</artifactId>
    +      <version>${commons.version}</version>
    +      <scope>test</scope>
    +    </dependency>
    +  </dependencies>
    +</project>
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/AbstractExtendedURLResourceReferenceSerializer.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/AbstractExtendedURLResourceTypeResolver.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/AbstractParentResourceReferenceResolver.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/AbstractResourceReferenceResolver.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/DefaultResourceReferenceResolver.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/DefaultResourceReferenceSerializer.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/DefaultResourceTypeResolver.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/DefaultStringResourceTypeResolver.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/DefaultURLConfiguration.java+15 0 renamed
    @@ -19,6 +19,9 @@
      */
     package org.xwiki.url.internal;
     
    +import java.util.Collections;
    +import java.util.List;
    +
     import javax.inject.Inject;
     import javax.inject.Provider;
     import javax.inject.Singleton;
    @@ -60,4 +63,16 @@ public boolean useResourceLastModificationDate()
         {
             return this.configuration.get().getProperty(PREFIX + "useResourceLastModificationDate", true);
         }
    +
    +    @Override
    +    public List<String> getTrustedDomains()
    +    {
    +        return this.configuration.get().getProperty(PREFIX + "trustedDomains", Collections.emptyList());
    +    }
    +
    +    @Override
    +    public boolean isTrustedDomainsEnabled()
    +    {
    +        return this.configuration.get().getProperty(PREFIX + "trustedDomainsEnabled", true);
    +    }
     }
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/DefaultURLContextManager.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/DefaultURLSecurityManager.java+137 0 added
    @@ -0,0 +1,137 @@
    +/*
    + * 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.url.internal;
    +
    +import java.net.URL;
    +import java.util.HashSet;
    +import java.util.Set;
    +import java.util.regex.Pattern;
    +
    +import javax.inject.Inject;
    +import javax.inject.Singleton;
    +
    +import org.apache.commons.lang3.StringUtils;
    +import org.apache.commons.lang3.exception.ExceptionUtils;
    +import org.slf4j.Logger;
    +import org.xwiki.component.annotation.Component;
    +import org.xwiki.context.Execution;
    +import org.xwiki.url.URLConfiguration;
    +import org.xwiki.url.URLSecurityManager;
    +import org.xwiki.wiki.descriptor.WikiDescriptor;
    +import org.xwiki.wiki.descriptor.WikiDescriptorManager;
    +import org.xwiki.wiki.manager.WikiManagerException;
    +
    +/**
    + * Default implementation of {@link URLSecurityManager}.
    + * This implementation keeps a HashSet in memory containing the trusted domains defined in the configuration and
    + * for all subwikis. Use {@link #invalidateCache()} to compute back this hashset.
    + *
    + * @version $Id$
    + * @since 13.3RC1
    + * @since 12.10.7
    + */
    +@Component
    +@Singleton
    +public class DefaultURLSecurityManager implements URLSecurityManager
    +{
    +    private static final Pattern ACCEPTED_DOMAIN_PATTERN = Pattern.compile("([^.]+\\.[^.]+)+");
    +    private static final char DOT = '.';
    +
    +    @Inject
    +    private URLConfiguration urlConfiguration;
    +
    +    @Inject
    +    private WikiDescriptorManager wikiDescriptorManager;
    +
    +    @Inject
    +    private Execution execution;
    +
    +    @Inject
    +    private Logger logger;
    +
    +    private Set<String> trustedDomains;
    +
    +    private void computeTrustedDomains()
    +    {
    +        Set<String> domains;
    +        domains = new HashSet<>(this.urlConfiguration.getTrustedDomains());
    +
    +        try {
    +            for (WikiDescriptor wikiDescriptor : wikiDescriptorManager.getAll()) {
    +                domains.addAll(wikiDescriptor.getAliases());
    +            }
    +        } catch (WikiManagerException e) {
    +            logger.warn("Error while getting wiki descriptor to fill list of trusted domains: [{}]. "
    +                + "The subwikis won't be taken into account for the list of trusted domains.",
    +                ExceptionUtils.getRootCauseMessage(e));
    +        }
    +        this.trustedDomains = new HashSet<>();
    +
    +        for (String domain : domains) {
    +            if (ACCEPTED_DOMAIN_PATTERN.matcher(domain).matches()) {
    +                this.trustedDomains.add(domain);
    +            } else {
    +                logger.warn("The domain [{}] specified in the trusted domains configuration won't be taken into "
    +                    + "account since it doesn't respect the documented format.", domain);
    +            }
    +        }
    +    }
    +
    +    @Override
    +    public boolean isDomainTrusted(URL urlToCheck)
    +    {
    +        if (this.urlConfiguration.isTrustedDomainsEnabled()) {
    +            if (this.trustedDomains == null) {
    +                computeTrustedDomains();
    +            }
    +
    +            String host = urlToCheck.getHost();
    +
    +            while (StringUtils.contains(host, DOT)) {
    +                if (trustedDomains.contains(host)) {
    +                    return true;
    +                } else {
    +                    host = host.substring(host.indexOf(DOT) + 1);
    +                }
    +            }
    +
    +            Object bypassCheckProperty = execution.getContext()
    +                .getProperty(URLSecurityManager.BYPASS_DOMAIN_SECURITY_CHECK_CONTEXT_PROPERTY);
    +            boolean bypassCheck = bypassCheckProperty != null && Boolean.parseBoolean(bypassCheckProperty.toString());
    +
    +            if (bypassCheck) {
    +                logger.info("Domain of URL [{}] does not belong to the list of trusted domains but it's considered as "
    +                    + "trusted since the check has been bypassed.", urlToCheck);
    +            }
    +
    +            return bypassCheck;
    +        } else {
    +            return true;
    +        }
    +    }
    +
    +    /**
    +     * Invalidate the set of trusted domains: this should mainly be used when a subwiki is added/edited/deleted.
    +     */
    +    public void invalidateCache()
    +    {
    +        this.trustedDomains = null;
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/GenericResourceReferenceResolver.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/GenericStringResourceTypeResolver.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/ParentResourceReference.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/RelativeExtendedURL.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/URLExecutionContextInitializer.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/URLStringEntityReferenceResolver.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/URLStringEntityReferenceSerializer.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/URLSymbolScheme.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/java/org/xwiki/url/internal/XWikiServerClassListener.java+84 0 added
    @@ -0,0 +1,84 @@
    +/*
    + * 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.url.internal;
    +
    +import java.util.Arrays;
    +import java.util.List;
    +
    +import javax.inject.Inject;
    +import javax.inject.Named;
    +import javax.inject.Singleton;
    +
    +import org.xwiki.component.annotation.Component;
    +import org.xwiki.model.reference.LocalDocumentReference;
    +import org.xwiki.observation.AbstractEventListener;
    +import org.xwiki.observation.event.Event;
    +import org.xwiki.url.URLSecurityManager;
    +
    +import com.xpn.xwiki.internal.event.XObjectAddedEvent;
    +import com.xpn.xwiki.internal.event.XObjectDeletedEvent;
    +import com.xpn.xwiki.internal.event.XObjectUpdatedEvent;
    +
    +/**
    + * Listener for changes on XWikiServerClass xobjects to ensure the {@link URLSecurityManager} cache is invalidated
    + * in case of change on XWikiServerClass objects.
    + *
    + * @version $Id$
    + * @since 13.3RC1
    + * @since 12.10.7
    + */
    +@Component
    +@Singleton
    +@Named(XWikiServerClassListener.NAME)
    +public class XWikiServerClassListener extends AbstractEventListener
    +{
    +    /**
    +     * Name of the listener.
    +     */
    +    public static final String NAME = "org.xwiki.url.internal.XWikiServerClassListener";
    +
    +    private static final LocalDocumentReference XWIKISERVER_CLASS =
    +        new LocalDocumentReference("XWiki", "XWikiServerClass");
    +
    +    private static final List<Event> EVENTS = Arrays.asList(
    +        new XObjectAddedEvent(XWIKISERVER_CLASS),
    +        new XObjectDeletedEvent(XWIKISERVER_CLASS),
    +        new XObjectUpdatedEvent(XWIKISERVER_CLASS)
    +    );
    +
    +    @Inject
    +    private URLSecurityManager securityManager;
    +
    +    /**
    +     * Default constructor.
    +     */
    +    public XWikiServerClassListener()
    +    {
    +        super(NAME, EVENTS);
    +    }
    +
    +    @Override
    +    public void onEvent(Event event, Object source, Object data)
    +    {
    +        if (this.securityManager instanceof DefaultURLSecurityManager) {
    +            ((DefaultURLSecurityManager) this.securityManager).invalidateCache();
    +        }
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/main/resources/META-INF/components.txt+2 0 renamed
    @@ -1,3 +1,5 @@
    +org.xwiki.url.internal.XWikiServerClassListener
    +org.xwiki.url.internal.DefaultURLSecurityManager
     org.xwiki.url.internal.DefaultURLConfiguration
     org.xwiki.url.internal.DefaultResourceReferenceResolver
     org.xwiki.url.internal.DefaultResourceReferenceSerializer
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/test/java/org/xwiki/url/internal/AbstractParentResourceReferenceResolverTest.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/test/java/org/xwiki/url/internal/DefaultURLConfigurationTest.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/test/java/org/xwiki/url/internal/DefaultURLSecurityManagerTest.java+197 0 added
    @@ -0,0 +1,197 @@
    +/*
    + * 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.url.internal;
    +
    +import java.net.MalformedURLException;
    +import java.net.URL;
    +import java.util.Arrays;
    +import java.util.Collections;
    +
    +import org.junit.jupiter.api.BeforeEach;
    +import org.junit.jupiter.api.Test;
    +import org.junit.jupiter.api.extension.RegisterExtension;
    +import org.xwiki.context.Execution;
    +import org.xwiki.context.ExecutionContext;
    +import org.xwiki.test.LogLevel;
    +import org.xwiki.test.junit5.LogCaptureExtension;
    +import org.xwiki.test.junit5.mockito.ComponentTest;
    +import org.xwiki.test.junit5.mockito.InjectMockComponents;
    +import org.xwiki.test.junit5.mockito.MockComponent;
    +import org.xwiki.url.URLConfiguration;
    +import org.xwiki.url.URLSecurityManager;
    +import org.xwiki.wiki.descriptor.WikiDescriptor;
    +import org.xwiki.wiki.descriptor.WikiDescriptorManager;
    +
    +import static org.hamcrest.MatcherAssert.assertThat;
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +import static org.mockito.Mockito.mock;
    +import static org.mockito.Mockito.when;
    +
    +/**
    + * Tests for {@link DefaultURLSecurityManager}.
    + *
    + * @version $Id$
    + * @since 13.3RC1
    + * @since 12.10.7
    + */
    +@ComponentTest
    +class DefaultURLSecurityManagerTest
    +{
    +    @InjectMockComponents
    +    private DefaultURLSecurityManager urlSecurityManager;
    +
    +    @MockComponent
    +    private URLConfiguration urlConfiguration;
    +
    +    @MockComponent
    +    private WikiDescriptorManager wikiDescriptorManager;
    +
    +    @MockComponent
    +    private Execution execution;
    +    
    +    private ExecutionContext executionContext;
    +
    +    @RegisterExtension
    +    LogCaptureExtension logCapture = new LogCaptureExtension(LogLevel.INFO);
    +    
    +    @BeforeEach
    +    void setup()
    +    {
    +        this.executionContext = mock(ExecutionContext.class);
    +        when(this.execution.getContext()).thenReturn(this.executionContext);
    +        when(this.urlConfiguration.isTrustedDomainsEnabled()).thenReturn(true);
    +    }
    +
    +    @Test
    +    void isDomainTrusted() throws Exception
    +    {
    +        when(urlConfiguration.getTrustedDomains()).thenReturn(Arrays.asList(
    +            "foo.acme.org",
    +            "com" // this should not be taken into account
    +        ));
    +
    +        WikiDescriptor wikiDescriptor1 = mock(WikiDescriptor.class);
    +        when(wikiDescriptor1.getAliases()).thenReturn(Arrays.asList(
    +            "www.xwiki.org",
    +            "something.bar.com"
    +        ));
    +
    +        WikiDescriptor wikiDescriptor2 = mock(WikiDescriptor.class);
    +        when(wikiDescriptor2.getAliases()).thenReturn(Collections.singletonList(
    +            "enterprise.eu"
    +        ));
    +
    +        when(this.wikiDescriptorManager.getAll()).thenReturn(Arrays.asList(wikiDescriptor1, wikiDescriptor2));
    +
    +        assertThat("www.xwiki.org is trusted", this.urlSecurityManager
    +            .isDomainTrusted(new URL("http://www.xwiki.org/xwiki/bin/view/XWiki/Login")));
    +        assertThat("www.xwiki.org is trusted", this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://www.xwiki.org/xwiki/bin/view/XWiki/Login")));
    +        assertThat("www.xwiki.com is not trusted", !this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://www.xwiki.com/xwiki/bin/view/XWiki/Login")));
    +        assertThat("xwiki.org is not trusted", !this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://xwiki.org/xwiki/bin/view/XWiki/Login")));
    +        assertThat("foo.acme.org is trusted", this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://foo.acme.org/something/else")));
    +        assertThat("bar.foo.acme.org is trusted since foo.acme.org is", this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://bar.foo.acme.org/something/else")));
    +        assertThat("buz.bar.foo.acme.org is trusted since foo.acme.org is", this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://buz.bar.foo.acme.org/something/else")));
    +        assertThat("acme.org is not trusted", !this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://acme.org/something/else")));
    +        assertThat("www.acme.org is not trusted", !this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://www.acme.org/something/else")));
    +        assertThat("something.bar.thing.com is not trusted", !this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://something.bar.thing.com")));
    +        assertThat("bar.thing.com is not trusted", !this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://bar.thing.com")));
    +        assertThat("something.bar.com is tristed", this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://something.bar.com")));
    +        assertThat("enterprise.eu is trusted", this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://enterprise.eu/xwiki/")));
    +        assertThat("enterprise.eu. is not trusted", !this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://enterprise.eu./xwiki/")));
    +
    +        assertEquals("The domain [com] specified in the trusted domains configuration won't be taken into account "
    +                + "since it doesn't respect the documented format.",
    +            logCapture.getMessage(0));
    +    }
    +
    +    @Test
    +    void invalidateCache() throws Exception
    +    {
    +        when(urlConfiguration.getTrustedDomains()).thenReturn(Collections.singletonList(
    +            "xwiki.org"
    +        ));
    +        assertThat("www.xwiki.org is trusted", this.urlSecurityManager
    +            .isDomainTrusted(new URL("http://www.xwiki.org")));
    +        assertThat("foo.acme.org is not trusted", !this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://foo.acme.org/something/else")));
    +
    +        when(urlConfiguration.getTrustedDomains()).thenReturn(Collections.singletonList(
    +            "foo.acme.org"
    +        ));
    +
    +        // the asserts are still the same because we rely on cached values
    +        assertThat("www.xwiki.org is still trusted", this.urlSecurityManager
    +            .isDomainTrusted(new URL("http://www.xwiki.org")));
    +        assertThat("foo.acme.org is still not trusted", !this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://foo.acme.org/something/else")));
    +
    +        // after invalidation the cache has been recomputed.
    +        this.urlSecurityManager.invalidateCache();
    +        assertThat("www.xwiki.org is not trusted anymore", !this.urlSecurityManager
    +            .isDomainTrusted(new URL("http://www.xwiki.org")));
    +        assertThat("foo.acme.org is trusted now", this.urlSecurityManager
    +            .isDomainTrusted(new URL("https://foo.acme.org/something/else")));
    +    }
    +
    +    @Test
    +    void isDomainTrustedWhenCheckSkipped() throws MalformedURLException
    +    {
    +        when(urlConfiguration.getTrustedDomains()).thenReturn(Collections.singletonList(
    +            "foo.acme.org"
    +        ));
    +        when(urlConfiguration.isTrustedDomainsEnabled()).thenReturn(false);
    +        assertThat("Any domain can be trusted when check is skipped: check with www.xwiki.org",
    +            this.urlSecurityManager.isDomainTrusted(new URL("http://www.xwiki.org")));
    +        assertThat("Any domain can be trusted when check is skipped: check with www.bar.eu",
    +            this.urlSecurityManager.isDomainTrusted(new URL("http://www.bar.eu")));
    +        assertThat("Any domain can be trusted when check is skipped: check with foo.acme.org",
    +            this.urlSecurityManager.isDomainTrusted(new URL("http://foo.acme.org")));
    +
    +        when(urlConfiguration.isTrustedDomainsEnabled()).thenReturn(true);
    +        assertThat("www.xwiki.org should not be trusted",
    +            !this.urlSecurityManager.isDomainTrusted(new URL("http://www.xwiki.org")));
    +        assertThat("www.bar.eu should not be trusted",
    +            !this.urlSecurityManager.isDomainTrusted(new URL("http://www.bar.eu")));
    +        assertThat("foo.acme.org should be trusted",
    +            this.urlSecurityManager.isDomainTrusted(new URL("http://foo.acme.org")));
    +
    +        when(this.executionContext.getProperty(URLSecurityManager.BYPASS_DOMAIN_SECURITY_CHECK_CONTEXT_PROPERTY))
    +            .thenReturn(true);
    +        assertThat("www.xwiki.org should be trusted when check is bypassed",
    +            this.urlSecurityManager.isDomainTrusted(new URL("http://www.xwiki.org")));
    +
    +        assertEquals("Domain of URL [http://www.xwiki.org] does not belong to the list of trusted domains but "
    +                + "it's considered as trusted since the check has been bypassed.",
    +            logCapture.getMessage(0));
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/test/java/org/xwiki/url/internal/RelativeExtendedURLTest.java+1 1 renamed
    @@ -17,7 +17,7 @@
      * 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.url;
    +package org.xwiki.url.internal;
     
     import java.util.Arrays;
     
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/test/java/org/xwiki/url/internal/URLExecutionContextInitializerTest.java+2 1 renamed
    @@ -17,13 +17,14 @@
      * 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.url;
    +package org.xwiki.url.internal;
     
     import org.junit.jupiter.api.Test;
     import org.xwiki.context.ExecutionContext;
     import org.xwiki.test.junit5.mockito.ComponentTest;
     import org.xwiki.test.junit5.mockito.InjectMockComponents;
     import org.xwiki.test.junit5.mockito.MockComponent;
    +import org.xwiki.url.URLConfiguration;
     import org.xwiki.url.internal.URLExecutionContextInitializer;
     
     import static org.junit.jupiter.api.Assertions.assertEquals;
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/test/java/org/xwiki/url/internal/URLStringEntityReferenceResolverTest.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-default/src/test/java/org/xwiki/url/internal/URLStringEntityReferenceSerializerTest.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-filesystem/pom.xml+1 1 modified
    @@ -39,7 +39,7 @@
       <dependencies>
         <dependency>
           <groupId>org.xwiki.platform</groupId>
    -      <artifactId>xwiki-platform-url-api</artifactId>
    +      <artifactId>xwiki-platform-url-default</artifactId>
           <version>${project.version}</version>
         </dependency>
     
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-reference/pom.xml+1 1 modified
    @@ -38,7 +38,7 @@
       <dependencies>
         <dependency>
           <groupId>org.xwiki.platform</groupId>
    -      <artifactId>xwiki-platform-url-api</artifactId>
    +      <artifactId>xwiki-platform-url-default</artifactId>
           <version>${project.version}</version>
         </dependency>
         <dependency>
    
  • xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/pom.xml+1 1 modified
    @@ -46,7 +46,7 @@
         </dependency>
         <dependency>
           <groupId>org.xwiki.platform</groupId>
    -      <artifactId>xwiki-platform-url-api</artifactId>
    +      <artifactId>xwiki-platform-url-default</artifactId>
           <version>${project.version}</version>
         </dependency>
         <dependency>
    
  • xwiki-platform-tools/xwiki-platform-tool-configuration-resources/src/main/resources/xwiki.properties.vm+19 0 modified
    @@ -744,6 +744,25 @@ extension.versioncheck.environment.enabled=$xwikiPropertiesEnvironmentVersionChe
     #-# The default is:
     # url.useResourceLastModificationDate=true
     
    +#-# [Since 13.3RC1]
    +#-# [Since 12.10.7]
    +#-# Define a list of trusted domains that can be used in the wiki for performing requests or redirections even if
    +#-# the wiki does not use it. Domains are listed without http and separated with a comma in the list. Subdomains can be
    +#-# specified.
    +#-# Example of accepted value: foo.acme.org,enterprise.org
    +#-#
    +#-# By default the list of trusted domains is empty:
    +# url.trustedDomains=
    +
    +#-# [Since 13.3RC1]
    +#-# [Since 12.10.7]
    +#-# Allow to enable or disable checks performed on domains by taking into account the list of trusted domains.
    +#-# Disable this property only if you experienced some issues on your wiki: some security check won't be performed when
    +#-# this property is set to false.
    +#-#
    +#-# By default this property is set to true:
    +# url.trustedDomainsEnabled=true
    +
     #-------------------------------------------------------------------------------------
     # Attachment
     #-------------------------------------------------------------------------------------
    

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

5

News mentions

0

No linked articles in our index yet.