Skip to content

Commit

Permalink
Merge branch 'master' into defect/reports/fixing-QueryReportConfigMod…
Browse files Browse the repository at this point in the history
…el-3295
  • Loading branch information
davidjgonzalez authored Mar 22, 2024
2 parents 066e111 + 7047719 commit 95c2b25
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 108 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com)
### Changed

- #3267 - Remove JSR305 dependency
- #3262 - Allow to configure Component/BundleDisabler via Configuration Factories
- #3296 - Add image cropping customisation

### Fixed

- #3270 - Re-enable accidentally disabled JUnit3/4 tests
- #3200 - Remove useless public interface in Cloud Bundle to get javadocs to be built
- #3295 - Updated the annotations in QueryReportConfig fixing the query manager issue due to empty query language
- #3284 - Allow anonymous to read redirect caconfig options

## 6.4.0 - 2024-02-22

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ end
# web requests need read access to redirect configurations, e.g. /conf/global/settings/redirects
set ACL for anonymous
allow jcr:read on /conf restriction(rep:glob,/*/settings/redirects)
allow jcr:read on /conf restriction(rep:glob,/*/settings/redirects/*)
end

create service user acs-commons-automatic-package-replicator-service with path system/acs-commons
Expand Down
5 changes: 5 additions & 0 deletions bundle/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,11 @@
<artifactId>org.osgi.service.cm</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.service.event</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,53 +17,73 @@
*/
package com.adobe.acs.commons.util.impl;

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.PropertiesUtil;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.osgi.service.event.propertytypes.EventTopics;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
* Component disabler service
* OSGi bundle disabler service
* <p>
* In the AEM security checklist, there are some bundles which should be disabled in production environents.
* In the AEM security checklist, there are some bundles which should be disabled in production environments.
* Whilst these bundles can be manually stopped, this component will do that as part of a deployment. It will also
* ensure that if they are manually started once more, then they will be immediately stopped.
*/
@org.apache.felix.scr.annotations.Component(immediate = true, metatype = true,
label = "ACS AEM Commons - OSGI Bundle Disabler", description = "Disables bundles by configuration",
policy = ConfigurationPolicy.REQUIRE)
@Service()
@Property(name = "event.topics", value = { "org/osgi/framework/BundleEvent/STARTED" }, propertyPrivate = true)
@Component(immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE)
@EventTopics(value = { "org/osgi/framework/BundleEvent/STARTED"} )
@Designate(ocd = BundleDisabler.Config.class)
public class BundleDisabler implements EventHandler {

private static final Logger log = LoggerFactory.getLogger(BundleDisabler.class);
@ObjectClassDefinition(name = "ACS AEM Commons - OSGI Bundle Disabler", description = "Disables OSGi bundles by configuration")
static @interface Config {
@AttributeDefinition(name = "Disabled bundles", description = "The symbolic names of the bundles you want to disable", cardinality = Integer.MAX_VALUE)
String[] bundles();
}

@Property(label = "Disabled bundles", description = "The symbolic names of the bundles you want to disable",
cardinality = Integer.MAX_VALUE)
private static final String DISABLED_BUNDLES = "bundles";
@Component(service = ConfigAmendment.class, property = "webconsole.configurationFactory.nameHint={bundles}")
@Designate(factory = true, ocd = BundleDisabler.Config.class)
public static final class ConfigAmendment {
private final Config config;

private BundleContext bundleContext;
@Activate
public ConfigAmendment(Config config) {
this.config = config;
}

private List<String> disabledBundles = Collections.emptyList();
public Config getConfig() {
return config;
}
}

private static final Logger log = LoggerFactory.getLogger(BundleDisabler.class);

private final BundleContext bundleContext;

private final Set<String> disabledBundles;

@Activate
protected void activate(ComponentContext componentContext, Map<String, Object> properties) {
this.bundleContext = componentContext.getBundleContext();
this.disabledBundles = getDisabledBundles(properties);
public BundleDisabler(BundleContext bundleContext, Config config, @Reference(policyOption = ReferencePolicyOption.GREEDY) List<ConfigAmendment> configAmendments) {
this.bundleContext = bundleContext;
this.disabledBundles = new HashSet<>();
this.disabledBundles.addAll(Arrays.asList(config.bundles()));
configAmendments.stream().forEach(amendment -> disabledBundles.addAll(Arrays.asList(amendment.getConfig().bundles())));
disableBundles();
}

Expand Down Expand Up @@ -93,17 +113,12 @@ private void disableBundles() {

private void disableBundle(final Bundle bundle) throws BundleException {
if (isBundleStoppable(bundle) && isNotOwnBundle(bundle)) {
log.info("Bundle {} disabled by configuration (name={}) ",
log.info("Bundle {} disabled by configuration (id={}) ",
bundle.getSymbolicName(), bundle.getBundleId());
bundle.stop();
}
}

private List<String> getDisabledBundles(final Map<String, Object> properties) {
final String[] bundlesProperty = PropertiesUtil.toStringArray(properties.get(DISABLED_BUNDLES), new String[0]);
return Arrays.asList(PropertiesUtil.toStringArray(bundlesProperty, new String[0]));
}

private boolean isOnBundleStopList(final Bundle bundle) {
return disabledBundles.contains(bundle.getSymbolicName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,76 +18,99 @@
package com.adobe.acs.commons.util.impl;

import java.util.Arrays;
import java.util.Map;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferencePolicyOption;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.osgi.service.component.runtime.ServiceComponentRuntime;
import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.osgi.service.event.propertytypes.EventTopics;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Component disabler service
* OSGi DS Component disabler service.
*
* In Apache Felix the state of components and services is not persisted across restarts of its containing bundle.
* For example, when you have a Bundle S containing a service S, and you manually stop the service S; after a
* deactivate and activate of the bundle the service S is up again.
*
* This service allows you to specify the names of components, which shouldn't be running. Whenever an OSGI service event is
* In Apache Felix the state of DS components is not persisted across restarts of its containing bundle.
* For example, when you have a Bundle S containing a component S, and you manually stop the component S; after a
* deactivate and activate of the bundle the component S is up again.
* <p>
* This service allows you to specify the names of DS components, which shouldn't be running. Whenever an OSGi service event is
* fired, which services checks the status of this components and stops them if required.
*
* <p>
* Note 1: The component is always started, but this service takes care, that it is stopped immediately after. So if a behaviour
* you don't like already happens during the activation of this service, you cannot prevent it using the mechanism here.
*
* Particularly components not implementing an OSGi service may be running for a long time until a service registered or bundle
* started event finally stops them.
* <p>
* Note 2: Using this service should always be considered as a workaround. The primary focus should be to fix the component
* you want to disable, so it's no longer required to disable it. If this component is part of Adobe AEM please raise a Daycare
* you want to disable, so it's no longer required to disable it. If this component is part of Adobe AEM please raise a Support
* ticket for it.
*
*
* @see <a href="https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.component.html#service.component-introspection">OSGi Declarative Services 1.4, Service Component Runtime, Introspection</a>
* @see ServiceComponentRuntime#disableComponent(ComponentDescriptionDTO)
*/
@org.apache.felix.scr.annotations.Component(immediate = true, metatype = true,
label = "ACS AEM Commons - OSGI Component Disabler", description = "Disables components by configuration",
policy = ConfigurationPolicy.REQUIRE)
@Service()
@Property(name = "event.topics", value = { "org/osgi/framework/BundleEvent/STARTED",
"org/osgi/framework/ServiceEvent/REGISTERED" }, propertyPrivate = true)
@Component(immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE)
@EventTopics(value = { "org/osgi/framework/BundleEvent/STARTED", "org/osgi/framework/ServiceEvent/REGISTERED"} )
@Designate(ocd = ComponentDisabler.Config.class)
public class ComponentDisabler implements EventHandler {

private static final Logger log = LoggerFactory.getLogger(ComponentDisabler.class);
@ObjectClassDefinition(name = "ACS AEM Commons - OSGi DS Component Disabler", description = "Disables OSGi DS components by configuration")
static @interface Config {
@AttributeDefinition(name = "Disabled components", description = "The names of the components you want to disable (usually their fully class name)", cardinality = Integer.MAX_VALUE)
String[] components();
}

@Property(label = "Disabled components", description = "The names of the components/services you want to disable",
cardinality = Integer.MAX_VALUE)
private static final String DISABLED_COMPONENTS = "components";
@Component(service = ConfigAmendment.class, property = "webconsole.configurationFactory.nameHint={components}")
@Designate(factory = true, ocd = ComponentDisabler.Config.class)
public static final class ConfigAmendment {
private final Config config;

private String[] disabledComponents;
@Activate
public ConfigAmendment(Config config) {
this.config = config;
}

public Config getConfig() {
return config;
}
}

private static final Logger log = LoggerFactory.getLogger(ComponentDisabler.class);

@Reference
private ServiceComponentRuntime scr;
private final BundleContext bundleContext;

private BundleContext bundleContext;
private final ServiceComponentRuntime scr;

private final Set<String> disabledComponents;

@Activate
protected void activate(BundleContext bundleContext, Map<String, Object> properties) {
disabledComponents = PropertiesUtil.toStringArray(properties.get(DISABLED_COMPONENTS), new String[0]);
public ComponentDisabler(BundleContext bundleContext, Config config, @Reference ServiceComponentRuntime scr, @Reference(policyOption = ReferencePolicyOption.GREEDY) List<ConfigAmendment> configAmendments) {
this.bundleContext = bundleContext;
// merge amendments
disabledComponents = new HashSet<>();
disabledComponents.addAll(Arrays.asList(config.components()));
configAmendments.stream().forEach(amendment -> disabledComponents.addAll(Arrays.asList(amendment.getConfig().components())));
this.scr = scr;
handleEvent(null);
}

@Override
public void handleEvent(Event event) {
// We don't care about the event, we just need iterate all configured
// components and try to disable them
log.trace("Disabling components and services {}", Arrays.toString(disabledComponents));
log.trace("Disabling OSGi DS components {}", String.join(",", disabledComponents));

for (String component : disabledComponents) {
disable(component);
Expand All @@ -98,7 +121,7 @@ public void disable(String componentName) {
for (Bundle bundle : bundleContext.getBundles()) {
ComponentDescriptionDTO dto = scr.getComponentDescriptionDTO(bundle, componentName);
if (dto != null && scr.isComponentEnabled(dto)) {
log.info("Component {} disabled by configuration.", dto.implementationClass);
log.info("Disabling OSGi DS Component {}.", dto.implementationClass);
scr.disableComponent(dto);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
Expand Down Expand Up @@ -273,7 +274,7 @@ private DescriptorList parseJar(InputStream is, boolean checkNs) throws Exceptio
while (entry != null) {
if (!entry.isDirectory() && entry.getName().endsWith(".xml")) {
if (entry.getName().startsWith("OSGI-INF/metatype")) {
metatypeDescriptors.add(parseMetatype(new InputStreamFacade(zis), entry.getName()));
metatypeDescriptors.addAll(parseMetatype(new InputStreamFacade(zis), entry.getName()));
} else if (entry.getName().startsWith("OSGI-INF/")) {
result.merge(parseScr(new InputStreamFacade(zis), entry.getName(), checkNs));
}
Expand Down Expand Up @@ -308,7 +309,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
}
} else if ("metatype".equals(parentDirectoryName)) {
try (InputStream input = Files.newInputStream(file)) {
metatypeDescriptors.add(parseMetatype(input, file.getFileName().toString()));
metatypeDescriptors.addAll(parseMetatype(input, file.getFileName().toString()));
}
}
}
Expand Down Expand Up @@ -360,8 +361,9 @@ private Descriptor parseScr(InputStream is, String name, boolean checkNs) throws
return result;
}

private Descriptor parseMetatype(InputStream is, String name) throws IOException {
Descriptor result = new Descriptor();
private Collection<Descriptor> parseMetatype(InputStream is, String name) throws IOException {
List<Descriptor> descriptors = new ArrayList<>();
List<Property> properties = new ArrayList<>();
try {
XMLEventReader reader = xmlInputFactory.createXMLEventReader(is);
while (reader.hasNext()) {
Expand All @@ -370,36 +372,40 @@ private Descriptor parseMetatype(InputStream is, String name) throws IOException
StartElement start = event.asStartElement();
String elementName = start.getName().getLocalPart();
if (elementName.equals("Designate")) {
// each designate defines a mapping between SCR component and metatype, the same metatype may be bound to multiple components
Attribute pidAttribute = start.getAttributeByName(new QName("pid"));
Descriptor descriptor = new Descriptor();
descriptor.properties = properties;
if (pidAttribute != null) {
result.name = pidAttribute.getValue();
descriptor.name = pidAttribute.getValue();
} else {
pidAttribute = start.getAttributeByName(new QName("factoryPid"));
if (pidAttribute != null) {
result.name = pidAttribute.getValue();
descriptor.name = pidAttribute.getValue();
}
result.factory = true;
descriptor.factory = true;
}
if (descriptor.name == null) {
throw new IllegalArgumentException("Could not identify (factory)pid for " + name);
}
descriptors.add(descriptor);
} else if (elementName.equals("AD")) {
String propName = start.getAttributeByName(new QName("id")).getValue();
Attribute value = start.getAttributeByName(new QName("default"));
Attribute typeAttr = start.getAttributeByName(new QName("type"));
String type = typeAttr == null ? "String" : typeAttr.getValue();
if (value == null) {
result.properties.add(new Property(propName, "(metatype)", type));
properties.add(new Property(propName, "(metatype)", type));
} else {
result.properties.add(new Property(propName, "(metatype)" + value.getValue(), type));
properties.add(new Property(propName, "(metatype)" + value.getValue(), type));
}
}
}
}
} catch (XMLStreamException e) {
throw new IOException("Error parsing XML", e);
}
if (result.name == null) {
throw new IllegalArgumentException("Could not identify pid for " + name);
}
return result;
return descriptors;
}

private String cleanText(String input) {
Expand Down
Loading

0 comments on commit 95c2b25

Please sign in to comment.