From 0e8bbb431de6a2f59acdd9e9bf80775c60c2f6b2 Mon Sep 17 00:00:00 2001 From: Bartosz Wesolowski Date: Mon, 4 Mar 2019 12:57:03 +0100 Subject: [PATCH 1/9] #31: Added post processor that encrypts passwords + added separate passwords fields to global configuration dialog. https://github.com/Cognifide/SecureCQ/issues/31 --- pom.xml | 12 +++ .../renderers/mainRenderer/dialog.xml | 14 +++ .../AuthorPasswordFieldEncryptFilter.java | 15 +++ .../password/PasswordFiledEncryptFilter.java | 12 +++ .../PasswordPropertySavePostProcessor.java | 101 ++++++++++++++++++ .../PublishPasswordFieldEncryptFilter.java | 15 +++ 6 files changed, 169 insertions(+) create mode 100644 src/main/java/com/cognifide/secureaem/sling/password/AuthorPasswordFieldEncryptFilter.java create mode 100644 src/main/java/com/cognifide/secureaem/sling/password/PasswordFiledEncryptFilter.java create mode 100644 src/main/java/com/cognifide/secureaem/sling/password/PasswordPropertySavePostProcessor.java create mode 100644 src/main/java/com/cognifide/secureaem/sling/password/PublishPasswordFieldEncryptFilter.java diff --git a/pom.xml b/pom.xml index 9d17dca..9f6459d 100644 --- a/pom.xml +++ b/pom.xml @@ -264,7 +264,19 @@ com.google.code.gson gson 2.7 + + + org.apache.sling + org.apache.sling.servlets.post + 2.3.24 + provided + + + com.adobe.granite + com.adobe.granite.crypto + 0.0.24 + diff --git a/src/main/aem/jcr_root/apps/cognifide/secureaem/renderers/mainRenderer/dialog.xml b/src/main/aem/jcr_root/apps/cognifide/secureaem/renderers/mainRenderer/dialog.xml index 2b448d7..2ccd727 100644 --- a/src/main/aem/jcr_root/apps/cognifide/secureaem/renderers/mainRenderer/dialog.xml +++ b/src/main/aem/jcr_root/apps/cognifide/secureaem/renderers/mainRenderer/dialog.xml @@ -32,6 +32,13 @@ name="./authorCredentials" defaultValue="admin:admin" xtype="textfield"/> + + diff --git a/src/main/java/com/cognifide/secureaem/sling/password/AuthorPasswordFieldEncryptFilter.java b/src/main/java/com/cognifide/secureaem/sling/password/AuthorPasswordFieldEncryptFilter.java new file mode 100644 index 0000000..b54f355 --- /dev/null +++ b/src/main/java/com/cognifide/secureaem/sling/password/AuthorPasswordFieldEncryptFilter.java @@ -0,0 +1,15 @@ +package com.cognifide.secureaem.sling.password; + +import org.apache.commons.lang3.StringUtils; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; + +@Service +@Component +public class AuthorPasswordFieldEncryptFilter implements PasswordFiledEncryptFilter { + @Override + public boolean isSupported(String propertyPath) { + return StringUtils.startsWith(propertyPath, "/etc/secureaem") + && StringUtils.endsWith(propertyPath, "authorPassword"); + } +} diff --git a/src/main/java/com/cognifide/secureaem/sling/password/PasswordFiledEncryptFilter.java b/src/main/java/com/cognifide/secureaem/sling/password/PasswordFiledEncryptFilter.java new file mode 100644 index 0000000..a0f056c --- /dev/null +++ b/src/main/java/com/cognifide/secureaem/sling/password/PasswordFiledEncryptFilter.java @@ -0,0 +1,12 @@ +package com.cognifide.secureaem.sling.password; + +public interface PasswordFiledEncryptFilter { + + /** + * Checks whether property given by propertyPath parameter should be encrypted + * @param propertyPath absolute path to property + * @return true if property should be encrypted, false otherwise + */ + boolean isSupported(String propertyPath); + +} diff --git a/src/main/java/com/cognifide/secureaem/sling/password/PasswordPropertySavePostProcessor.java b/src/main/java/com/cognifide/secureaem/sling/password/PasswordPropertySavePostProcessor.java new file mode 100644 index 0000000..b8b3dc0 --- /dev/null +++ b/src/main/java/com/cognifide/secureaem/sling/password/PasswordPropertySavePostProcessor.java @@ -0,0 +1,101 @@ +package com.cognifide.secureaem.sling.password; + +import com.adobe.granite.crypto.CryptoException; +import com.adobe.granite.crypto.CryptoSupport; +import org.apache.commons.lang3.StringUtils; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.ReferencePolicy; +import org.apache.felix.scr.annotations.Service; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.servlets.post.Modification; +import org.apache.sling.servlets.post.SlingPostProcessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jcr.Property; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + + +@Component +@Service +public class PasswordPropertySavePostProcessor implements SlingPostProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(PasswordPropertySavePostProcessor.class); + + private static final String PATH_SEPARATOR = "/"; + + @Reference( + bind = "bind", + unbind = "unbind", + cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, + referenceInterface = PasswordFiledEncryptFilter.class, + policy = ReferencePolicy.DYNAMIC) + private Collection encryptionFilters = ConcurrentHashMap.newKeySet(); + + + @Reference + private CryptoSupport cryptoSupport; + + @Override + public void process(SlingHttpServletRequest slingHttpServletRequest, List list) { + List stringStream = list.stream() + .filter(this::isSupported) + .map(Modification::getSource) + .collect(Collectors.toList()); + + for (String propertyPath : stringStream) { + try { + this.encryptProperty(slingHttpServletRequest.getResourceResolver(), propertyPath); + } catch (CryptoException | RepositoryException e) { + LOGGER.error("Failed to encrypt property {}", propertyPath, e); + } + } + + } + + private boolean isSupported(Modification modification) { + return encryptionFilters + .stream() + .filter(filter -> filter.isSupported(modification.getSource())) + .findFirst() + .isPresent(); + } + + + private void encryptProperty(ResourceResolver resourceResolver, String propertyPath) throws CryptoException, RepositoryException { + Session session = resourceResolver.adaptTo(Session.class); + Property propertyToBeProtected = session.getProperty(propertyPath); + if (propertyToBeProtected != null) { + String propertyValue = propertyToBeProtected.getString(); + if (!cryptoSupport.isProtected(propertyValue)) { + String encryptedPropertyValue = cryptoSupport.protect(propertyValue); + propertyToBeProtected.setValue(encryptedPropertyValue); + } + } + + } + + private String getPropertyNodePath(String propertyPath) { + return StringUtils.substringBeforeLast(propertyPath, PATH_SEPARATOR); + } + + private String getPropertyName(String propertyPath) { + return StringUtils.substringAfterLast(propertyPath, PATH_SEPARATOR); + } + + protected void bind(PasswordFiledEncryptFilter filter) { + encryptionFilters.add(filter); + } + + protected void unbind(PasswordFiledEncryptFilter filter) { + encryptionFilters.remove(filter); + } +} diff --git a/src/main/java/com/cognifide/secureaem/sling/password/PublishPasswordFieldEncryptFilter.java b/src/main/java/com/cognifide/secureaem/sling/password/PublishPasswordFieldEncryptFilter.java new file mode 100644 index 0000000..1798e4c --- /dev/null +++ b/src/main/java/com/cognifide/secureaem/sling/password/PublishPasswordFieldEncryptFilter.java @@ -0,0 +1,15 @@ +package com.cognifide.secureaem.sling.password; + +import org.apache.commons.lang3.StringUtils; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; + +@Service +@Component +public class PublishPasswordFieldEncryptFilter implements PasswordFiledEncryptFilter { + @Override + public boolean isSupported(String propertyPath) { + return StringUtils.startsWith(propertyPath, "/etc/secureaem") + && StringUtils.endsWith(propertyPath, "publishPassword"); + } +} From c524eb73d23ffd6d0ac27f10cfa2b401ebfafbfa Mon Sep 17 00:00:00 2001 From: Bartosz Wesolowski Date: Mon, 4 Mar 2019 17:02:54 +0100 Subject: [PATCH 2/9] #31: Extracted separate interfaces for global configuration and particular test configuration --- .../secureaem/GlobalConfiguration.java | 17 +++++++++++++++++ .../cognifide/secureaem/TestConfiguration.java | 11 +++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/main/java/com/cognifide/secureaem/GlobalConfiguration.java create mode 100644 src/main/java/com/cognifide/secureaem/TestConfiguration.java diff --git a/src/main/java/com/cognifide/secureaem/GlobalConfiguration.java b/src/main/java/com/cognifide/secureaem/GlobalConfiguration.java new file mode 100644 index 0000000..cf59860 --- /dev/null +++ b/src/main/java/com/cognifide/secureaem/GlobalConfiguration.java @@ -0,0 +1,17 @@ +package com.cognifide.secureaem; + +public interface GlobalConfiguration { + String getDispatcherUrl(); + + String getAuthor(); + + String getAuthorLogin(); + + String getAuthorPassword(); + + String getPublish(); + + String getPublishLogin(); + + String getPublishPassword(); +} diff --git a/src/main/java/com/cognifide/secureaem/TestConfiguration.java b/src/main/java/com/cognifide/secureaem/TestConfiguration.java new file mode 100644 index 0000000..6cb73d3 --- /dev/null +++ b/src/main/java/com/cognifide/secureaem/TestConfiguration.java @@ -0,0 +1,11 @@ +package com.cognifide.secureaem; + +/** + * Configuration of particular test + */ +public interface TestConfiguration { + + String getStringValue(String name, String defaultValue); + + String[] getStringList(String name); +} From 158a4eb44734342047e096a26a10cb4c6660eec9 Mon Sep 17 00:00:00 2001 From: Bartosz Wesolowski Date: Mon, 4 Mar 2019 17:07:41 +0100 Subject: [PATCH 3/9] #31: Implementations for global and test configurations --- .../sling/ResourceGlobalConfiguration.java | 96 +++++++++++++++++++ .../sling/ResourceTestConfiguration.java | 29 ++++++ 2 files changed, 125 insertions(+) create mode 100644 src/main/java/com/cognifide/secureaem/sling/ResourceGlobalConfiguration.java create mode 100644 src/main/java/com/cognifide/secureaem/sling/ResourceTestConfiguration.java diff --git a/src/main/java/com/cognifide/secureaem/sling/ResourceGlobalConfiguration.java b/src/main/java/com/cognifide/secureaem/sling/ResourceGlobalConfiguration.java new file mode 100644 index 0000000..9d59037 --- /dev/null +++ b/src/main/java/com/cognifide/secureaem/sling/ResourceGlobalConfiguration.java @@ -0,0 +1,96 @@ +package com.cognifide.secureaem.sling; + +import com.adobe.granite.crypto.CryptoException; +import com.adobe.granite.crypto.CryptoSupport; +import com.cognifide.secureaem.GlobalConfiguration; +import com.cognifide.secureaem.cli.CliConfiguration; +import org.apache.commons.lang3.StringUtils; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ValueMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ResourceGlobalConfiguration implements GlobalConfiguration { + + private static final Logger LOG = LoggerFactory.getLogger(ResourceConfiguration.class); + + private ValueMap globalConfig; + + private CryptoSupport cryptoSupport; + + public ResourceGlobalConfiguration(SlingHttpServletRequest request, CryptoSupport cryptoSupport) { + this.cryptoSupport = cryptoSupport; + Resource globalConfigRes = findGlobalConfig(request); + if (globalConfigRes != null) { + globalConfig = globalConfigRes.adaptTo(ValueMap.class); + } + } + + @Override + public String getDispatcherUrl() { + return StringUtils.removeEnd(getGlobalConfigParam("dispatcher"), "/"); + } + + @Override + public String getAuthor() { + return StringUtils.removeEnd(getGlobalConfigParam("author"), "/"); + } + + @Override public String getAuthorLogin() { + return getGlobalConfigParam("authorLogin"); + } + + @Override public String getAuthorPassword() { + return getPassword("authorPassword"); + } + + @Override + public String getPublish() { + return StringUtils.removeEnd(getGlobalConfigParam("publish"), "/"); + } + + @Override public String getPublishLogin() { + return getGlobalConfigParam("publishLogin"); + } + + @Override public String getPublishPassword() { + return getPassword("publishPassword"); + } + + private String getPassword(String paramName) { + String password = StringUtils.defaultString(getGlobalConfigParam(paramName)); + String decryptedPassword = password; + if (cryptoSupport.isProtected(password)) { + try { + decryptedPassword = cryptoSupport.unprotect(password); + } catch (CryptoException e) { + LOG.error("Failed to decrypt password {}", paramName, e); + } + } + return decryptedPassword; + } + + + private String getGlobalConfigParam(String name) { + if (globalConfig == null) { + return null; + } + return globalConfig.get(name, String.class); + } + + private Resource findGlobalConfig(SlingHttpServletRequest request) { + Resource resource = request.getResource(); + while (resource != null) { + if (resource.isResourceType("cq:Page")) { + Resource content = resource.getChild("jcr:content"); + String resourceType = content.adaptTo(ValueMap.class).get("sling:resourceType", String.class); + if ("cognifide/secureaem/renderers/mainRenderer".equals(resourceType)) { + return content.getChild("globalConfig"); + } + } + resource = resource.getParent(); + } + return null; + } +} diff --git a/src/main/java/com/cognifide/secureaem/sling/ResourceTestConfiguration.java b/src/main/java/com/cognifide/secureaem/sling/ResourceTestConfiguration.java new file mode 100644 index 0000000..1b47a7a --- /dev/null +++ b/src/main/java/com/cognifide/secureaem/sling/ResourceTestConfiguration.java @@ -0,0 +1,29 @@ +package com.cognifide.secureaem.sling; + +import com.cognifide.secureaem.TestConfiguration; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.ValueMap; + +public class ResourceTestConfiguration implements TestConfiguration { + + private final ValueMap valueMap; + + public ResourceTestConfiguration(SlingHttpServletRequest request) { + this.valueMap = request.getResource().adaptTo(ValueMap.class); + } + + @Override + public String getStringValue(String name, String defaultValue) { + return getLocalConfig(name, defaultValue); + } + + @Override + public String[] getStringList(String name) { + return getLocalConfig(name, ArrayUtils.EMPTY_STRING_ARRAY); + } + + private T getLocalConfig(String name, T defaultValue) { + return this.valueMap.get(name, defaultValue); + } +} From 3c5dd0ce46d4bbc1f2c19d25c762bc348b2b17e1 Mon Sep 17 00:00:00 2001 From: Bartosz Wesolowski Date: Mon, 4 Mar 2019 17:09:33 +0100 Subject: [PATCH 4/9] #31: Test invoker as Sling Servlet with configuration extracted via OSGI service --- .../components/abstractTest/json.java | 4 -- .../sling/ConfigurationProvider.java | 31 ++++++++++ .../secureaem/sling/ConfigurationWrapper.java | 62 +++++++++++++++++++ .../secureaem/sling/TestInvoker.java | 13 +++- 4 files changed, 105 insertions(+), 5 deletions(-) delete mode 100644 src/main/aem/jcr_root/apps/cognifide/secureaem/components/abstractTest/json.java create mode 100644 src/main/java/com/cognifide/secureaem/sling/ConfigurationProvider.java create mode 100644 src/main/java/com/cognifide/secureaem/sling/ConfigurationWrapper.java diff --git a/src/main/aem/jcr_root/apps/cognifide/secureaem/components/abstractTest/json.java b/src/main/aem/jcr_root/apps/cognifide/secureaem/components/abstractTest/json.java deleted file mode 100644 index e36d8b6..0000000 --- a/src/main/aem/jcr_root/apps/cognifide/secureaem/components/abstractTest/json.java +++ /dev/null @@ -1,4 +0,0 @@ -package apps.cognifide.secureaem.components.abstractTest; - -public class json extends com.cognifide.secureaem.sling.TestInvoker { -} diff --git a/src/main/java/com/cognifide/secureaem/sling/ConfigurationProvider.java b/src/main/java/com/cognifide/secureaem/sling/ConfigurationProvider.java new file mode 100644 index 0000000..8762ab0 --- /dev/null +++ b/src/main/java/com/cognifide/secureaem/sling/ConfigurationProvider.java @@ -0,0 +1,31 @@ +package com.cognifide.secureaem.sling; + +import com.adobe.granite.crypto.CryptoSupport; +import com.cognifide.secureaem.Configuration; +import com.cognifide.secureaem.GlobalConfiguration; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.apache.sling.api.SlingHttpServletRequest; + +import java.util.Optional; + +@Component +@Service(ConfigurationProvider.class) +public class ConfigurationProvider { + + @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY) + private GlobalConfiguration globalConfiguration; + + @Reference + private CryptoSupport cryptoSupport; + + public Configuration createConfiguration(SlingHttpServletRequest request) { + ResourceTestConfiguration testConfiguration = new ResourceTestConfiguration(request); + GlobalConfiguration globalConfig = Optional.ofNullable(this.globalConfiguration) + .orElseGet(() -> new ResourceGlobalConfiguration(request, cryptoSupport)); + return new ConfigurationWrapper(globalConfig, testConfiguration); + } + +} diff --git a/src/main/java/com/cognifide/secureaem/sling/ConfigurationWrapper.java b/src/main/java/com/cognifide/secureaem/sling/ConfigurationWrapper.java new file mode 100644 index 0000000..8137461 --- /dev/null +++ b/src/main/java/com/cognifide/secureaem/sling/ConfigurationWrapper.java @@ -0,0 +1,62 @@ +package com.cognifide.secureaem.sling; + +import com.cognifide.secureaem.Configuration; +import com.cognifide.secureaem.GlobalConfiguration; +import com.cognifide.secureaem.TestConfiguration; + +public class ConfigurationWrapper implements Configuration { + + private GlobalConfiguration globalConfiguration; + + private TestConfiguration testConfiguration; + + public ConfigurationWrapper(GlobalConfiguration globalConfiguration, TestConfiguration testConfiguration) { + this.globalConfiguration = globalConfiguration; + this.testConfiguration = testConfiguration; + } + + @Override + public String getDispatcherUrl() { + return globalConfiguration.getDispatcherUrl(); + } + + @Override + public String getAuthor() { + return globalConfiguration.getAuthor(); + } + + @Override + public String getAuthorLogin() { + return globalConfiguration.getAuthorLogin(); + } + + @Override + public String getAuthorPassword() { + return globalConfiguration.getAuthorPassword(); + } + + @Override + public String getPublish() { + return globalConfiguration.getPublish(); + } + + @Override + public String getPublishLogin() { + return globalConfiguration.getPublishLogin(); + } + + @Override + public String getPublishPassword() { + return globalConfiguration.getPublishPassword(); + } + + @Override + public String getStringValue(String name, String defaultValue) { + return testConfiguration.getStringValue(name, defaultValue); + } + + @Override + public String[] getStringList(String name) { + return testConfiguration.getStringList(name); + } +} diff --git a/src/main/java/com/cognifide/secureaem/sling/TestInvoker.java b/src/main/java/com/cognifide/secureaem/sling/TestInvoker.java index 07f9fbd..75a3be1 100644 --- a/src/main/java/com/cognifide/secureaem/sling/TestInvoker.java +++ b/src/main/java/com/cognifide/secureaem/sling/TestInvoker.java @@ -5,6 +5,8 @@ import javax.servlet.ServletException; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.sling.SlingServlet; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.resource.Resource; @@ -14,15 +16,24 @@ import com.cognifide.secureaem.AbstractTest; import com.cognifide.secureaem.Configuration; +@SlingServlet( + methods = {"GET"}, + extensions = "json", + resourceTypes = "cognifide/secureaem/components/abstractTest" +) public class TestInvoker extends SlingSafeMethodsServlet { private static final long serialVersionUID = 1334083614379709964L; + @Reference + private ConfigurationProvider configurationPrivder; + @Override public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException, ServletException { String testClassName = getTestClassName(request); - Configuration config = new ResourceConfiguration(request); + Configuration config = configurationPrivder.createConfiguration(request); + AbstractTest test; try { Class clazz = Class.forName(testClassName); From cbb648fe1cf04570a721aaf863f90060341b8022 Mon Sep 17 00:00:00 2001 From: Bartosz Wesolowski Date: Mon, 4 Mar 2019 17:10:10 +0100 Subject: [PATCH 5/9] #31: Global configuration dialog definition updated - separated author and login properties --- .../secureaem/renderers/mainRenderer/dialog.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/aem/jcr_root/apps/cognifide/secureaem/renderers/mainRenderer/dialog.xml b/src/main/aem/jcr_root/apps/cognifide/secureaem/renderers/mainRenderer/dialog.xml index 2ccd727..24f6111 100644 --- a/src/main/aem/jcr_root/apps/cognifide/secureaem/renderers/mainRenderer/dialog.xml +++ b/src/main/aem/jcr_root/apps/cognifide/secureaem/renderers/mainRenderer/dialog.xml @@ -25,12 +25,12 @@ fieldLabel="Author URL" name="./author" xtype="textfield"/> - - Date: Mon, 4 Mar 2019 17:10:58 +0100 Subject: [PATCH 6/9] #31: Single Session creation, added info logs --- .../PasswordPropertySavePostProcessor.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/cognifide/secureaem/sling/password/PasswordPropertySavePostProcessor.java b/src/main/java/com/cognifide/secureaem/sling/password/PasswordPropertySavePostProcessor.java index b8b3dc0..31cabc9 100644 --- a/src/main/java/com/cognifide/secureaem/sling/password/PasswordPropertySavePostProcessor.java +++ b/src/main/java/com/cognifide/secureaem/sling/password/PasswordPropertySavePostProcessor.java @@ -40,20 +40,27 @@ public class PasswordPropertySavePostProcessor implements SlingPostProcessor { policy = ReferencePolicy.DYNAMIC) private Collection encryptionFilters = ConcurrentHashMap.newKeySet(); - @Reference private CryptoSupport cryptoSupport; @Override public void process(SlingHttpServletRequest slingHttpServletRequest, List list) { - List stringStream = list.stream() + List propertiesToEncrypt = list.stream() .filter(this::isSupported) .map(Modification::getSource) .collect(Collectors.toList()); - for (String propertyPath : stringStream) { + ResourceResolver resourceResolver = slingHttpServletRequest.getResourceResolver(); + Session session = resourceResolver.adaptTo(Session.class); + + if (session == null) { + LOGGER.error("Failed to create session."); + return; + } + + for (String propertyPath : propertiesToEncrypt) { try { - this.encryptProperty(slingHttpServletRequest.getResourceResolver(), propertyPath); + this.encryptProperty(session, propertyPath); } catch (CryptoException | RepositoryException e) { LOGGER.error("Failed to encrypt property {}", propertyPath, e); } @@ -70,14 +77,15 @@ private boolean isSupported(Modification modification) { } - private void encryptProperty(ResourceResolver resourceResolver, String propertyPath) throws CryptoException, RepositoryException { - Session session = resourceResolver.adaptTo(Session.class); + private void encryptProperty(Session session, String propertyPath) throws CryptoException, RepositoryException { Property propertyToBeProtected = session.getProperty(propertyPath); if (propertyToBeProtected != null) { - String propertyValue = propertyToBeProtected.getString(); + String propertyValue = StringUtils.defaultString(propertyToBeProtected.getString()); if (!cryptoSupport.isProtected(propertyValue)) { + LOGGER.info("Encrypting property: '{}'", propertyPath); String encryptedPropertyValue = cryptoSupport.protect(propertyValue); propertyToBeProtected.setValue(encryptedPropertyValue); + LOGGER.info("Property '{}' encrypted", propertyPath); } } From 9f46903bafc6a9671a1fd8c3989e25614652bdc4 Mon Sep 17 00:00:00 2001 From: Bartosz Wesolowski Date: Wed, 6 Mar 2019 09:42:32 +0100 Subject: [PATCH 7/9] #24: Enabled global configuration via OSGI service https://github.com/Cognifide/SecureCQ/issues/24 --- .gitignore | 1 + pom.xml | 700 +++++++++--------- .../sling/ConfigurationProvider.java | 23 +- .../sling/SecureAemGlobalConfiguration.java | 116 +++ 4 files changed, 489 insertions(+), 351 deletions(-) create mode 100644 src/main/java/com/cognifide/secureaem/sling/SecureAemGlobalConfiguration.java diff --git a/.gitignore b/.gitignore index 310c07f..dfb8072 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ target .project .settings .idea/ +/*.iml diff --git a/pom.xml b/pom.xml index 9f6459d..659c94f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,348 +1,358 @@ - - - org.sonatype.oss - oss-parent - 7 - - 4.0.0 - com.cognifide.secureaem - secure-aem - 1.3.3-SNAPSHOT - ${packaging.type} - Secure AEM - This application provides detailed security report for your AEM installation. After installation it's available in the 'Tools' page. - https://github.com/Cognifide/SecureCQ - - - The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - - 2013 - - UTF-8 - UTF-8 - yyyyMMdd-HHmmss - http://localhost:4502 - admin - admin - secure-aem - - - scm:git:https://github.com/Cognifide/SecureCQ.git - scm:git:https://github.com/Cognifide/SecureCQ.git - https://github.com/Cognifide/SecureCQ.git - - - Cognifide - http://www.cognifide.com - - - - Tomasz Rękawek - tomasz.rekawek@cognifide.com - Cognifide - - - - - adobe-public-releases - http://repo.adobe.com/nexus/content/groups/public - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - - - maven-compiler-plugin - 3.5.1 - - 1.8 - 1.8 - - - - org.apache.felix - maven-scr-plugin - 1.22.0 - - - generate-scr-scrdescriptor - - scr - - - - - - org.apache.felix - maven-bundle-plugin - 3.2.0 - true - - - cq5 - ${project.artifactId} - ${project.name} - ${project.organization.name} - *;artifactId=httpclient|httpcore|gson|commons-lang3|commons-cli - - - - - maven-assembly-plugin - 2.6 - - ${assembly.name}-${project.version} - false - - src/main/assembly/${assembly.descriptor}.xml - - - - com.cognifide.secureaem.cli.Main - - - - - - package - - single - - - - - - com.cognifide.maven.plugins - maven-crx-plugin - 1.0.3 - - - - ${instance.url} - ${instance.username} - ${instance.password} - - - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.4 - - - attach-javadocs - - jar - - - - - - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.apache.felix - maven-scr-plugin - [1.7.2,) - - scr - - - - - - - - - - - - - - - - - org.apache.sling - org.apache.sling.api - 2.2.0 - provided - - - org.apache.felix - org.apache.felix.scr.annotations - 1.9.0 - provided - - - - javax.servlet - servlet-api - 2.4 - provided - - - javax.jcr - jcr - 2.0 - provided - - - - com.day.cq - cq-replication - 5.4.2 - provided - - - com.day.cq - cq-commons - 5.4.6 - provided - - - - org.apache.commons - commons-lang3 - 3.4 - - - commons-cli - commons-cli - 1.2 - - - org.apache.httpcomponents - httpclient - 4.2.3 - - - org.apache.httpcomponents - httpcore - 4.2.3 - - - - com.google.code.gson - gson - 2.7 - - - org.apache.sling - org.apache.sling.servlets.post - 2.3.24 - provided - - - com.adobe.granite - com.adobe.granite.crypto - 0.0.24 - + + + org.sonatype.oss + oss-parent + 7 + + 4.0.0 + com.cognifide.secureaem + secure-aem + 1.3.3-SNAPSHOT + ${packaging.type} + Secure AEM + This application provides detailed security report for your AEM installation. After installation it's + available in the 'Tools' page. + + https://github.com/Cognifide/SecureCQ + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + 2013 + + UTF-8 + UTF-8 + yyyyMMdd-HHmmss + http://localhost:4502 + admin + admin + secure-aem + + + scm:git:https://github.com/Cognifide/SecureCQ.git + scm:git:https://github.com/Cognifide/SecureCQ.git + https://github.com/Cognifide/SecureCQ.git + + + Cognifide + http://www.cognifide.com + + + + Tomasz Rękawek + tomasz.rekawek@cognifide.com + Cognifide + + + + + adobe-public-releases + http://repo.adobe.com/nexus/content/groups/public + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + org.apache.felix + maven-scr-plugin + 1.22.0 + + + generate-scr-scrdescriptor + + scr + + + + + + org.apache.felix + maven-bundle-plugin + 3.2.0 + true + + + cq5 + ${project.artifactId} + ${project.name} + ${project.organization.name} + *;artifactId=httpclient|httpcore|gson|commons-lang3|commons-cli + + + + + + maven-assembly-plugin + 2.6 + + ${assembly.name}-${project.version} + false + + src/main/assembly/${assembly.descriptor}.xml + + + + com.cognifide.secureaem.cli.Main + + + + + + package + + single + + + + + + com.cognifide.maven.plugins + maven-crx-plugin + 1.0.3 + + + + ${instance.url} + ${instance.username} + ${instance.password} + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + + attach-javadocs + + jar + + + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.apache.felix + maven-scr-plugin + [1.7.2,) + + scr + + + + + + + + + + + + + + + + + org.apache.sling + org.apache.sling.api + 2.2.0 + provided + + + org.apache.sling + org.apache.sling.commons.osgi + 2.4.0 + provided + + + org.apache.felix + org.apache.felix.scr.annotations + 1.9.0 + provided + + + + javax.servlet + servlet-api + 2.4 + provided + + + javax.jcr + jcr + 2.0 + provided + + + + com.day.cq + cq-replication + 5.4.2 + provided + + + com.day.cq + cq-commons + 5.4.6 + provided + + + + org.apache.commons + commons-lang3 + 3.4 + + + commons-cli + commons-cli + 1.2 + + + org.apache.httpcomponents + httpclient + 4.2.3 + + + org.apache.httpcomponents + httpcore + 4.2.3 + + + + com.google.code.gson + gson + 2.7 + + + org.apache.sling + org.apache.sling.servlets.post + 2.3.24 + provided + + + com.adobe.granite + com.adobe.granite.crypto + 0.0.24 + - - - - aem - - true - - - aem - bundle - - - - org.slf4j - slf4j-api - 1.5.8 - provided - - - - - cli - - - performRelease - true - - - - cli - jar - - - - org.slf4j - slf4j-simple - 1.7.21 - - - - - release-sign-artifacts - - - performRelease - true - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - - - - - + + + + aem + + true + + + aem + bundle + + + + org.slf4j + slf4j-api + 1.5.8 + provided + + + + + cli + + + performRelease + true + + + + cli + jar + + + + org.slf4j + slf4j-simple + 1.7.21 + + + + + release-sign-artifacts + + + performRelease + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + + diff --git a/src/main/java/com/cognifide/secureaem/sling/ConfigurationProvider.java b/src/main/java/com/cognifide/secureaem/sling/ConfigurationProvider.java index 8762ab0..01a530e 100644 --- a/src/main/java/com/cognifide/secureaem/sling/ConfigurationProvider.java +++ b/src/main/java/com/cognifide/secureaem/sling/ConfigurationProvider.java @@ -6,26 +6,37 @@ import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.ReferencePolicy; import org.apache.felix.scr.annotations.Service; import org.apache.sling.api.SlingHttpServletRequest; -import java.util.Optional; - @Component @Service(ConfigurationProvider.class) public class ConfigurationProvider { - @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY) - private GlobalConfiguration globalConfiguration; + @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, + policy = ReferencePolicy.DYNAMIC, + referenceInterface = SecureAemGlobalConfiguration.class, + bind = "bind", unbind = "unbind") + private SecureAemGlobalConfiguration globalConfiguration; @Reference private CryptoSupport cryptoSupport; public Configuration createConfiguration(SlingHttpServletRequest request) { ResourceTestConfiguration testConfiguration = new ResourceTestConfiguration(request); - GlobalConfiguration globalConfig = Optional.ofNullable(this.globalConfiguration) - .orElseGet(() -> new ResourceGlobalConfiguration(request, cryptoSupport)); + GlobalConfiguration globalConfig = globalConfiguration; + if (globalConfig == null) { + globalConfig = new ResourceGlobalConfiguration(request, cryptoSupport); + } return new ConfigurationWrapper(globalConfig, testConfiguration); } + public void bind(SecureAemGlobalConfiguration globalConfiguration) { + this.globalConfiguration = globalConfiguration; + } + + public void unbind(SecureAemGlobalConfiguration globalConfiguration) { + this.globalConfiguration = null; + } } diff --git a/src/main/java/com/cognifide/secureaem/sling/SecureAemGlobalConfiguration.java b/src/main/java/com/cognifide/secureaem/sling/SecureAemGlobalConfiguration.java new file mode 100644 index 0000000..5f11262 --- /dev/null +++ b/src/main/java/com/cognifide/secureaem/sling/SecureAemGlobalConfiguration.java @@ -0,0 +1,116 @@ +package com.cognifide.secureaem.sling; + +import com.adobe.granite.crypto.CryptoException; +import com.adobe.granite.crypto.CryptoSupport; +import com.cognifide.secureaem.GlobalConfiguration; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +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.Service; +import org.apache.sling.commons.osgi.PropertiesUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +@Service(SecureAemGlobalConfiguration.class) +@Component(label = "Global Configuration for Secure Aem", + description = "This configuration is used instead of the global configuration provided in the content. To use values configured in content please disable this " + + "Component or remove configuration file.", + policy = ConfigurationPolicy.REQUIRE, + metatype = true, + immediate = true) +public class SecureAemGlobalConfiguration implements GlobalConfiguration { + + private static final Logger LOGGER = LoggerFactory.getLogger(SecureAemGlobalConfiguration.class); + + @Reference + private CryptoSupport cryptoSupport; + + @Property(label = "Dispatcher url") + private static final String DISPATCHER_URL = "dispatcher.url"; + + @Property(label = "Author url", value = "http://localhost:4502") + private static final String AUTHOR_URL = "author.url"; + + @Property(label = "Author login", value = "admin") + private static final String AUTHOR_LOGIN = "author.login"; + + @Property(label = "Author password", value = "admin", + description = "Should be encrypted with tool available through /system/console/crypto. Plain text supported but not recommended.") + private static final String AUTHOR_PASSOWRD = "author.password"; + + @Property(label = "Publish url", value = "http://localhost:4503") + private static final String PUBLISH_URL = "publish.url"; + + @Property(label = "Publish login", value = "admin") + private static final String PUBLISH_LOGIN = "publish.login"; + + @Property(label = "Publish password", value = "admin", + description = "Should be encrypted with tool available through /system/console/crypto. Plain text supported but not recommended.") + private static final String PUBLISH_PASSOWRD = "publish.password"; + + private String dispatcherUrl; + + private String authorUrl; + + private String authorLogin; + + private String authorPassowrd; + + private String publishUrl; + + private String publishLogin; + + private String publishPassword; + + @Activate + protected void activate(Map properties) { + LOGGER.info("Activating service."); + dispatcherUrl = PropertiesUtil.toString(properties.get(DISPATCHER_URL), ""); + authorUrl = PropertiesUtil.toString(properties.get(AUTHOR_URL), ""); + authorLogin = PropertiesUtil.toString(properties.get(AUTHOR_LOGIN), ""); + authorPassowrd = PropertiesUtil.toString(properties.get(AUTHOR_PASSOWRD), ""); + publishUrl = PropertiesUtil.toString(properties.get(PUBLISH_URL), ""); + publishLogin = PropertiesUtil.toString(properties.get(PUBLISH_LOGIN), ""); + publishPassword = PropertiesUtil.toString(properties.get(PUBLISH_PASSOWRD), ""); + } + + @Override + public String getDispatcherUrl() { + return dispatcherUrl; + } + + @Override + public String getAuthor() { + return authorUrl; + } + + @Override + public String getAuthorLogin() { + return authorLogin; + } + + @Override + public String getAuthorPassword() { + return authorPassowrd; + } + + @Override + public String getPublish() { + return publishUrl; + } + + @Override + public String getPublishLogin() { + return publishLogin; + } + + @Override + public String getPublishPassword() { + return publishPassword; + } + +} From 377f2a1d9acd2b13fe6d8e22ce2bd786678b0cb5 Mon Sep 17 00:00:00 2001 From: Bartosz Wesolowski Date: Wed, 6 Mar 2019 10:06:27 +0100 Subject: [PATCH 8/9] #24: Updated configuration description. --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c2a0a00..a77650e 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,22 @@ Otherwise you may enter address and credentials explicitly: ## Configuration After installation, go to the AEM *Tools* page and choose *Secure AEM* from the list on the left. The application tries to find author, publish and dispatcher URLs automatically, but you may want to confirm that they have been recognized correctly. In order to do that click *Edit* on the Settings bar and optionally correct addresses. That's it. Wait for a moment until the tests are done and check the results. - +####Osgi configuration +Application also allows Osgi configuration. To enable this option configuration for `SecureAemGlobalConfiguration` Osgi service needs to be provided (this will automatically take precedence over global config available on Secure Aem page configuration). Here is an example configuration file: +File name: `com.cognifide.secureaem.sling.SecureAemGlobalConfiguration.xml` +``` + +``` + +`author.password` and `publish.password` properties can be provided as a plain text or as encrypted values created via `/system/console/crypto` console (which is a recommended way). ## CLI version Sometimes you may want to check remote AEM instance. *Secure AEM* may be compiled in the standalone mode and used from the CLI, without any additional dependencies. In order to build application this way, enter: From 0da7a2c2ff713be894e7cd01da74a00c3441da86 Mon Sep 17 00:00:00 2001 From: Bartosz Wesolowski Date: Wed, 6 Mar 2019 15:29:39 +0100 Subject: [PATCH 9/9] #31:Preserved compatibility with AEM 6.1-6.4 --- pom.xml | 4 ++-- .../sling/SecureAemGlobalConfiguration.java | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 659c94f..d9c0834 100644 --- a/pom.xml +++ b/pom.xml @@ -213,7 +213,7 @@ org.apache.sling org.apache.sling.commons.osgi - 2.4.0 + 2.2.0 provided @@ -278,7 +278,7 @@ org.apache.sling org.apache.sling.servlets.post - 2.3.24 + 2.3.6 provided diff --git a/src/main/java/com/cognifide/secureaem/sling/SecureAemGlobalConfiguration.java b/src/main/java/com/cognifide/secureaem/sling/SecureAemGlobalConfiguration.java index 5f11262..6bbcd89 100644 --- a/src/main/java/com/cognifide/secureaem/sling/SecureAemGlobalConfiguration.java +++ b/src/main/java/com/cognifide/secureaem/sling/SecureAemGlobalConfiguration.java @@ -3,6 +3,7 @@ import com.adobe.granite.crypto.CryptoException; import com.adobe.granite.crypto.CryptoSupport; import com.cognifide.secureaem.GlobalConfiguration; +import org.apache.commons.lang3.StringUtils; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.ConfigurationPolicy; @@ -95,7 +96,7 @@ public String getAuthorLogin() { @Override public String getAuthorPassword() { - return authorPassowrd; + return getPassword(authorPassowrd); } @Override @@ -110,7 +111,19 @@ public String getPublishLogin() { @Override public String getPublishPassword() { - return publishPassword; + return getPassword(publishPassword); } + + private String getPassword(String passwordToDecrypt) { + String password = StringUtils.defaultString(passwordToDecrypt); + if (cryptoSupport.isProtected(password)) { + try { + password = cryptoSupport.unprotect(password); + } catch (CryptoException e) { + LOGGER.error("Failed to decrypt password", e); + } + } + return password; + } }