emptySet());
+
}
}
diff --git a/magnolia-core/src/main/java/info/magnolia/cms/util/SelectorUtil.java b/magnolia-core/src/main/java/info/magnolia/cms/util/SelectorUtil.java
index 88c821e..73e3864 100644
--- a/magnolia-core/src/main/java/info/magnolia/cms/util/SelectorUtil.java
+++ b/magnolia-core/src/main/java/info/magnolia/cms/util/SelectorUtil.java
@@ -36,9 +36,12 @@ package info.magnolia.cms.util;
import info.magnolia.context.MgnlContext;
/**
- * Util class to handle selectors. A selector is the part between the first {@link info.magnolia.cms.core.Path#SELECTOR_DELIMITER} and the extension of an URI.
+ * Util class to handle selectors. A selector is the part between the first {@link #SELECTOR_DELIMITER} and the extension of an URI.
*/
public class SelectorUtil {
+
+ public static final String SELECTOR_DELIMITER = "~";
+
/**
*
* get selector as requested from the URI. The selector is the part between the handle and the extension.
diff --git a/magnolia-core/src/main/java/info/magnolia/init/MagnoliaConfigurationProperties.java b/magnolia-core/src/main/java/info/magnolia/init/MagnoliaConfigurationProperties.java
index b8f2ad9..acf43db 100644
--- a/magnolia-core/src/main/java/info/magnolia/init/MagnoliaConfigurationProperties.java
+++ b/magnolia-core/src/main/java/info/magnolia/init/MagnoliaConfigurationProperties.java
@@ -72,7 +72,35 @@ package info.magnolia.init;
*/
public interface MagnoliaConfigurationProperties extends PropertySource {
+ String MAGNOLIA_REPOSITORIES_HOME = "magnolia.repositories.home";
+
+ String MAGNOLIA_REPOSITORIES_CONFIG = "magnolia.repositories.config";
+
+ String MAGNOLIA_REPOSITORIES_CLUSTER_CONFIG = "magnolia.repositories.jackrabbit.cluster.config";
+
+ String MAGNOLIA_REPOSITORIES_CLUSTER_MASTER = "magnolia.repositories.jackrabbit.cluster.master";
+
+ String MAGNOLIA_EXCHANGE_HISTORY = "magnolia.exchange.history";
+
+ String MAGNOLIA_UPLOAD_TMPDIR = "magnolia.upload.tmpdir";
+
+ String MAGNOLIA_CACHE_STARTDIR = "magnolia.cache.startdir";
+
+ String MAGNOLIA_APP_ROOTDIR = "magnolia.app.rootdir";
+
+ String MAGNOLIA_BOOTSTRAP_ROOTDIR = "magnolia.bootstrap.dir";
+
+ String MAGNOLIA_BOOTSTRAP_SAMPLES = "magnolia.bootstrap.samples";
+
+ String MAGNOLIA_UTF8_ENABLED = "magnolia.utf8.enabled";
+
+ String MAGNOLIA_WEBAPP = "magnolia.webapp";
+
+ String MAGNOLIA_SERVERNAME = "magnolia.servername";
+
+ String MAGNOLIA_CONTEXTPATH = "magnolia.contextpath";
+
PropertySource getPropertySource(String key);
void init() throws Exception;
-}
+}
\ No newline at end of file
diff --git a/magnolia-core/src/main/java/info/magnolia/jcr/util/NodeNameHelper.java b/magnolia-core/src/main/java/info/magnolia/jcr/util/NodeNameHelper.java
new file mode 100644
index 0000000..96f37df
--- /dev/null
+++ b/magnolia-core/src/main/java/info/magnolia/jcr/util/NodeNameHelper.java
@@ -0,0 +1,267 @@
+/**
+ * This file Copyright (c) 2017 Magnolia International
+ * Ltd. (http://www.magnolia-cms.com). All rights reserved.
+ *
+ *
+ * This file is dual-licensed under both the Magnolia
+ * Network Agreement and the GNU General Public License.
+ * You may elect to use one or the other of these licenses.
+ *
+ * This file is distributed in the hope that it will be
+ * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
+ * Redistribution, except as permitted by whichever of the GPL
+ * or MNA you select, is prohibited.
+ *
+ * 1. For the GPL license (GPL), you can redistribute and/or
+ * modify this file under the terms of the GNU General
+ * Public License, Version 3, as published by the Free Software
+ * Foundation. You should have received a copy of the GNU
+ * General Public License, Version 3 along with this program;
+ * if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 2. For the Magnolia Network Agreement (MNA), this file
+ * and the accompanying materials are made available under the
+ * terms of the MNA which accompanies this distribution, and
+ * is available at http://www.magnolia-cms.com/mna.html
+ *
+ * Any modifications to this file must keep this entire header
+ * intact.
+ *
+ */
+package info.magnolia.jcr.util;
+
+import info.magnolia.cms.util.SelectorUtil;
+import info.magnolia.init.MagnoliaConfigurationProperties;
+
+import java.nio.charset.StandardCharsets;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Util component for creation of an unique and validated node name.
+ */
+@Singleton
+public class NodeNameHelper {
+
+ private final String DEFAULT_UNTITLED_NODE_NAME = "untitled";
+
+ private final MagnoliaConfigurationProperties magnoliaConfigurationProperties;
+
+ @Inject
+ public NodeNameHelper(MagnoliaConfigurationProperties magnoliaConfigurationProperties) {
+ this.magnoliaConfigurationProperties = magnoliaConfigurationProperties;
+ }
+
+ /**
+ * Checks if an item already exists with given name in JCR, and returns a unique name;
+ * if necessary, an increment is appended to the name.
+ *
+ *
Given the following tree:
+ *
+ * /
+ * ├── a
+ * ├── b
+ * └── b0
+ *
+ * NodeUtil.getUniqueName(session, "/", "a") = "a0"
+ * NodeUtil.getUniqueName(session, "/", "b") = "b1"
+ * NodeUtil.getUniqueName(session, "/", "b0") = "b1"
+ * NodeUtil.getUniqueName(session, "/", "c") = "c"
+ *
+ */
+ public String getUniqueName(Session session, String parentPath, String name) throws RepositoryException {
+ if (parentPath.equals("/")) {
+ parentPath = StringUtils.EMPTY;
+ }
+ while (session.itemExists(parentPath + "/" + name)) {
+ name = createUniqueName(name);
+ }
+ return name;
+ }
+
+ /**
+ * Checks if an item already exists with given name in JCR, and returns a unique name;
+ * if necessary, an increment is inserted into the name, before the given extension.
+ *
+ * Given the following tree:
+ *
+ * /
+ * ├── a.txt
+ * ├── b.txt
+ * └── b0.txt
+ *
+ * NodeUtil.getUniqueName(session, "/", "a.txt", "txt") = "a0.txt"
+ * NodeUtil.getUniqueName(session, "/", "b.txt", "txt") = "b1.txt"
+ * NodeUtil.getUniqueName(session, "/", "b0.txt", "txt") = "b1.txt"
+ * NodeUtil.getUniqueName(session, "/", "c.txt", "txt") = "c.txt"
+ * NodeUtil.getUniqueName(session, "/", "a.foo", "txt") = "a.foo"
+ *
+ */
+ public String getUniqueName(Session session, String parentPath, String name, String extension) throws RepositoryException {
+ if (StringUtils.isNotEmpty(extension) && extension.equals(FilenameUtils.getExtension(name))) {
+ parentPath = "/".equals(parentPath) ? StringUtils.EMPTY : parentPath;
+ String basename = FilenameUtils.getBaseName(name);
+ String fullName = name;
+
+ while (session.itemExists(parentPath + "/" + fullName)) {
+ basename = createUniqueName(basename);
+ fullName = basename + FilenameUtils.EXTENSION_SEPARATOR + extension;
+ }
+ return fullName;
+ }
+
+ return getUniqueName(session, parentPath, name);
+ }
+
+ public String getUniqueName(Node parent, String name) throws RepositoryException {
+ while (parent.hasNode(name) || parent.hasProperty(name)) {
+ name = createUniqueName(name);
+ }
+ return name;
+ }
+
+ /**
+ * Replace illegal characters based on magnolia property magnolia.ut8.enabled.
+ *
+ * @return validated label
+ */
+ public String getValidatedName(String name) {
+ String charset = StringUtils.EMPTY;
+ if (magnoliaConfigurationProperties.getBooleanProperty(MagnoliaConfigurationProperties.MAGNOLIA_UTF8_ENABLED)) {
+ charset = StandardCharsets.UTF_8.name();
+ }
+ return getValidatedName(name, charset);
+ }
+
+ /**
+ * If charset equals UTF-8
, replaces the following characters with a dash -
:
+ *
+ * Jackrabbit not allowed {@code 32: [ ] 91: [[] 93: []] 42: [*] 34: ["] 58 [:] 92: [\] 39 :[']}
+ *
+ * URL not valid {@code 59: [;] 47: [/] 63: [?] 43: [+] 37: [%] 33: [!] 35:[#] 94: [^]}.
+ *
+ * Otherwise, replaces illegal characters with a dash -
except for {@code [_] [0-9], [A-Z], [a-z], [-], [_], [.]}.
+ *
+ * Please notice that a valid name can not begin with dot or period [.]
.
+ *
+ * @return a validated name for a node.
+ */
+ public String getValidatedName(String name, String charset) {
+ if (StringUtils.isEmpty(name)) {
+ return DEFAULT_UNTITLED_NODE_NAME;
+ }
+ final StringBuilder newLabel = new StringBuilder(name.length());
+
+ // name cannot begin with . (dot)
+ int ch = name.charAt(0);
+ if (!isCharValid(ch, charset) || ch == 46) {
+ newLabel.append("-");
+ } else {
+ newLabel.append(name.charAt(0));
+ }
+
+ for (int i = 1; i < name.length(); i++) {
+ int charCode = name.charAt(i);
+ if (isCharValid(charCode, charset)) {
+ newLabel.append(name.charAt(i));
+ } else {
+ newLabel.append("-");
+ }
+ }
+ if (newLabel.length() == 0) {
+ newLabel.append(DEFAULT_UNTITLED_NODE_NAME);
+ }
+ return newLabel.toString();
+ }
+
+ private boolean isCharValid(int charCode, String charset) {
+ // TODO fgrilli: we now allow dots (.) in JR local names but actually in JR 2.0 other chars could be allowed as well
+ // (see http://www.day.com/specs/jcr/2.0/3_Repository_Model.html paragraph 2.2 and org.apache.jackrabbit.util.XMLChar.isValid()).
+ // Also, now that we're on java 6 and JR 2.0 should the check for the charset be dropped?
+
+ // http://www.ietf.org/rfc/rfc1738.txt
+ // safe = "$" | "-" | "_" | "." | "+"
+ // extra = "!" | "*" | "'" | "(" | ")" | ","
+ // national = "{" | "}" | "|" | "\" | "^" | "~" | "[" | "]" | "`"
+ // punctuation = "<" | ">" | "#" | "%" | <">
+ // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "="
+
+ if (StandardCharsets.UTF_8.name().equals(charset)) {
+ // jackrabbit not allowed 32: [ ] 91: [[] 93: []] 42: [*] 34: ["] 46: [.] 58 [:] 92: [\] 39 :[']
+ // url not valid 59: [;] 47: [/] 63: [?] 43: [+] 37: [%] 33: [!] 35:[#]
+ if (charCode != 32
+ && charCode != '['
+ && charCode != ']'
+ && charCode != '*'
+ && charCode != '"'
+ && charCode != ':'
+ && charCode != 92
+ && charCode != 39
+ && charCode != ';'
+ && charCode != '/'
+ && charCode != '?'
+ && charCode != '+'
+ && charCode != '%'
+ && charCode != '!'
+ && charCode != '#'
+ && charCode != '@'
+ && charCode != '='
+ && charCode != '&'
+ && charCode != SelectorUtil.SELECTOR_DELIMITER.charAt(0)) {
+ return true;
+ }
+ } else {
+ // charCodes: 48-57: [0-9]; 65-90: [A-Z]; 97-122: [a-z]; 45: [-]; 95:[_]
+ if (((charCode >= 48) && (charCode <= 57))
+ || ((charCode >= 65) && (charCode <= 90))
+ || ((charCode >= 97) && (charCode <= 122))
+ || charCode == 45
+ || charCode == 46
+ || charCode == 95) {
+ return true;
+ }
+
+ }
+ return false;
+ }
+
+ private String createUniqueName(String baseName) {
+ int pos;
+ for (pos = baseName.length() - 1; pos >= 0; pos--) {
+ char c = baseName.charAt(pos);
+ if (c < '0' || c > '9') {
+ break;
+ }
+ }
+ String base;
+ int cnt;
+ if (pos == -1) {
+ if (baseName.length() > 1) {
+ pos = baseName.length() - 2;
+ }
+ }
+ if (pos == -1) {
+ base = baseName;
+ cnt = -1;
+ } else {
+ pos++;
+ base = baseName.substring(0, pos);
+ if (pos == baseName.length()) {
+ cnt = -1;
+ } else {
+ cnt = Integer.parseInt(baseName.substring(pos));
+ }
+ }
+ return (base + ++cnt);
+ }
+}
diff --git a/magnolia-core/src/main/resources/META-INF/magnolia/core.xml b/magnolia-core/src/main/resources/META-INF/magnolia/core.xml
index ee95789..e8281e2 100644
--- a/magnolia-core/src/main/resources/META-INF/magnolia/core.xml
+++ b/magnolia-core/src/main/resources/META-INF/magnolia/core.xml
@@ -188,6 +188,11 @@
info.magnolia.cms.core.version.CopyUtil
singleton
+
+ info.magnolia.jcr.util.NodeNameHelper
+ info.magnolia.jcr.util.NodeNameHelper
+ singleton
+
info.magnolia.voting.Voting
diff --git a/magnolia-core/src/test/java/info/magnolia/cms/security/MgnlGroupTest.java b/magnolia-core/src/test/java/info/magnolia/cms/security/MgnlGroupTest.java
index d2056e9..897faa3 100644
--- a/magnolia-core/src/test/java/info/magnolia/cms/security/MgnlGroupTest.java
+++ b/magnolia-core/src/test/java/info/magnolia/cms/security/MgnlGroupTest.java
@@ -35,8 +35,9 @@ package info.magnolia.cms.security;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
-
import info.magnolia.context.MgnlContext;
+import info.magnolia.init.MagnoliaConfigurationProperties;
+import info.magnolia.jcr.util.NodeNameHelper;
import info.magnolia.module.InstallContextImpl;
import info.magnolia.module.InstallStatus;
import info.magnolia.repository.RepositoryConstants;
@@ -51,12 +52,13 @@ import org.junit.Test;
public class MgnlGroupTest {
private MgnlGroupManager gman;
-
+
@Before
public void setUp() throws Exception {
final SecuritySupportImpl sec = new SecuritySupportImpl();
- sec.setGroupManager(new MgnlGroupManager());
- sec.setRoleManager(new MgnlRoleManager());
+ final NodeNameHelper nodeNameHelper = new NodeNameHelper(mock(MagnoliaConfigurationProperties.class));
+ sec.setGroupManager(new MgnlGroupManager(nodeNameHelper));
+ sec.setRoleManager(new MgnlRoleManager(nodeNameHelper));
ComponentsTestUtil.setInstance(SecuritySupport.class, sec);
MockUtil.initMockContext();
MockUtil.createAndSetHierarchyManager(RepositoryConstants.USERS, getClass().getResourceAsStream("sample-users.properties"));
@@ -66,7 +68,7 @@ public class MgnlGroupTest {
final InstallContextImpl context = mock(InstallContextImpl.class);
when(context.getStatus()).thenReturn(InstallStatus.installDone);
ComponentsTestUtil.setInstance(InstallContextImpl.class, context);
- gman = new MgnlGroupManager();
+ gman = new MgnlGroupManager(nodeNameHelper);
}
@After
diff --git a/magnolia-core/src/test/java/info/magnolia/cms/security/MgnlUserManagerTest.java b/magnolia-core/src/test/java/info/magnolia/cms/security/MgnlUserManagerTest.java
index a958058..3dca5e2 100644
--- a/magnolia-core/src/test/java/info/magnolia/cms/security/MgnlUserManagerTest.java
+++ b/magnolia-core/src/test/java/info/magnolia/cms/security/MgnlUserManagerTest.java
@@ -38,10 +38,11 @@ import static info.magnolia.test.hamcrest.NodeMatchers.hasNode;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
-
import info.magnolia.context.MgnlContext;
import info.magnolia.context.SystemContext;
+import info.magnolia.init.MagnoliaConfigurationProperties;
import info.magnolia.jcr.nodebuilder.NodeBuilderUtil;
+import info.magnolia.jcr.util.NodeNameHelper;
import info.magnolia.jcr.util.NodeTypes;
import info.magnolia.module.InstallContextImpl;
import info.magnolia.module.InstallStatus;
@@ -72,11 +73,13 @@ public class MgnlUserManagerTest {
private MgnlUserManager userManager;
private SystemContext ctx;
private MockSession session;
+ private NodeNameHelper nodeNameHelper;
@Before
public void setUp() throws Exception {
this.ctx = mock(SystemContext.class);
- this.userManager = new MgnlUserManager();
+ this.nodeNameHelper = new NodeNameHelper(mock(MagnoliaConfigurationProperties.class));
+ this.userManager = new MgnlUserManager(nodeNameHelper);
this.session = new MockSession(RepositoryConstants.USERS);
SecuritySupport securitySupport = mock(SecuritySupport.class);
@@ -102,7 +105,7 @@ public class MgnlUserManagerTest {
@Test
public void testUsernameIsValidatedUponCreation() {
final String justCheckingIfValidateUsernameIsCalledMessage = "Yes! I wanted this method to be called !";
- final MgnlUserManager hm = new MgnlUserManager() {
+ final MgnlUserManager hm = new MgnlUserManager(nodeNameHelper) {
@Override
protected void validateUsername(String name) {
throw new IllegalArgumentException(justCheckingIfValidateUsernameIsCalledMessage);
@@ -133,7 +136,7 @@ public class MgnlUserManagerTest {
@Test
public void testUsernameCantBeNull() {
try {
- new MgnlUserManager().validateUsername(null);
+ new MgnlUserManager(nodeNameHelper).validateUsername(null);
fail("should have failed");
} catch (IllegalArgumentException e) {
assertEquals("null is not a valid username.", e.getMessage());
@@ -143,7 +146,7 @@ public class MgnlUserManagerTest {
@Test
public void testUsernameCantBeEmpty() {
try {
- new MgnlUserManager().validateUsername("");
+ new MgnlUserManager(nodeNameHelper).validateUsername("");
fail("should have failed");
} catch (IllegalArgumentException e) {
assertEquals(" is not a valid username.", e.getMessage());
@@ -153,7 +156,7 @@ public class MgnlUserManagerTest {
@Test
public void testUsernameCantBeBlank() {
try {
- new MgnlUserManager().validateUsername(" ");
+ new MgnlUserManager(nodeNameHelper).validateUsername(" ");
fail("should have failed");
} catch (IllegalArgumentException e) {
assertEquals(" is not a valid username.", e.getMessage());
@@ -164,7 +167,7 @@ public class MgnlUserManagerTest {
public void testFindPrincipalNode() throws RepositoryException {
// GIVEN
final String userName = "test";
- MgnlUserManager um = new MgnlUserManager();
+ MgnlUserManager um = new MgnlUserManager(nodeNameHelper);
um.setRealmName(Realm.REALM_ALL.getName());
diff --git a/magnolia-core/src/test/java/info/magnolia/cms/security/MgnlUserTest.java b/magnolia-core/src/test/java/info/magnolia/cms/security/MgnlUserTest.java
index 5ef629d..604ddda 100644
--- a/magnolia-core/src/test/java/info/magnolia/cms/security/MgnlUserTest.java
+++ b/magnolia-core/src/test/java/info/magnolia/cms/security/MgnlUserTest.java
@@ -35,8 +35,9 @@ package info.magnolia.cms.security;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
-
import info.magnolia.context.MgnlContext;
+import info.magnolia.init.MagnoliaConfigurationProperties;
+import info.magnolia.jcr.util.NodeNameHelper;
import info.magnolia.module.InstallContextImpl;
import info.magnolia.module.InstallStatus;
import info.magnolia.repository.RepositoryConstants;
@@ -54,12 +55,14 @@ import com.google.common.collect.ImmutableMap;
public class MgnlUserTest {
private UserManager uman;
private SecuritySupportImpl sec;
+ private NodeNameHelper nodeNameHelper;
@Before
public void setUp() throws Exception {
sec = new SecuritySupportImpl();
- sec.setGroupManager(new MgnlGroupManager());
- sec.setRoleManager(new MgnlRoleManager());
+ nodeNameHelper = new NodeNameHelper(mock(MagnoliaConfigurationProperties.class));
+ sec.setGroupManager(new MgnlGroupManager(nodeNameHelper));
+ sec.setRoleManager(new MgnlRoleManager(nodeNameHelper));
createAndSetMgnlUserManager("test", RepositoryConstants.USERS);
ComponentsTestUtil.setInstance(SecuritySupport.class, sec);
@@ -181,7 +184,7 @@ public class MgnlUserTest {
}
private void createAndSetMgnlUserManager(final String realmName, final String repositoryName) {
- uman = new MgnlUserManager() {
+ uman = new MgnlUserManager(nodeNameHelper) {
{
setRealmName(realmName);
}
diff --git a/magnolia-core/src/test/java/info/magnolia/cms/security/RescueSecuritySupportTest.java b/magnolia-core/src/test/java/info/magnolia/cms/security/RescueSecuritySupportTest.java
index 6a97909..616cd39 100644
--- a/magnolia-core/src/test/java/info/magnolia/cms/security/RescueSecuritySupportTest.java
+++ b/magnolia-core/src/test/java/info/magnolia/cms/security/RescueSecuritySupportTest.java
@@ -35,9 +35,9 @@ package info.magnolia.cms.security;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.*;
-
import info.magnolia.cms.security.RescueSecuritySupport.RescueUserManager;
import info.magnolia.repository.RepositoryConstants;
+import info.magnolia.test.ComponentsTestUtil;
import info.magnolia.test.MgnlTestCase;
import info.magnolia.test.mock.MockUtil;
@@ -55,6 +55,7 @@ public class RescueSecuritySupportTest extends MgnlTestCase {
public void setUp() throws Exception {
super.setUp();
securitySupport = new RescueSecuritySupport();
+ ComponentsTestUtil.setInstance(SecuritySupport.class, securitySupport);
MockUtil.createAndSetHierarchyManager(RepositoryConstants.USERS, getClass().getResourceAsStream("sample-users.properties"));
MockUtil.createAndSetHierarchyManager(RepositoryConstants.USER_GROUPS, getClass().getResourceAsStream("sample-usergroups.properties"));
MockUtil.createAndSetHierarchyManager(RepositoryConstants.USER_ROLES, getClass().getResourceAsStream("sample-userroles.properties"));
diff --git a/magnolia-core/src/test/java/info/magnolia/cms/security/SecuritySupportObservedComponentFactoryTest.java b/magnolia-core/src/test/java/info/magnolia/cms/security/SecuritySupportObservedComponentFactoryTest.java
index bb769c1..08f0e1c 100644
--- a/magnolia-core/src/test/java/info/magnolia/cms/security/SecuritySupportObservedComponentFactoryTest.java
+++ b/magnolia-core/src/test/java/info/magnolia/cms/security/SecuritySupportObservedComponentFactoryTest.java
@@ -34,9 +34,11 @@
package info.magnolia.cms.security;
import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
import info.magnolia.context.MgnlContext;
import info.magnolia.context.SystemContext;
+import info.magnolia.init.MagnoliaConfigurationProperties;
import info.magnolia.jcr.node2bean.Node2BeanProcessor;
import info.magnolia.jcr.node2bean.Node2BeanTransformer;
import info.magnolia.jcr.node2bean.TypeMapping;
@@ -65,6 +67,7 @@ public class SecuritySupportObservedComponentFactoryTest {
final SystemContext ctx = new MockContext();
MgnlContext.setInstance(ctx);
ComponentsTestUtil.setInstance(SystemContext.class, ctx);
+ ComponentsTestUtil.setInstance(MagnoliaConfigurationProperties.class, mock(MagnoliaConfigurationProperties.class));
MockUtil.createAndSetHierarchyManager(RepositoryConstants.CONFIG, "/foo");
MockUtil.createAndSetHierarchyManager(RepositoryConstants.USERS, "/foo");
@@ -76,6 +79,8 @@ public class SecuritySupportObservedComponentFactoryTest {
ComponentsTestUtil.setImplementation(Node2BeanProcessor.class, Node2BeanProcessorImpl.class);
ComponentsTestUtil.setImplementation(Node2BeanTransformer.class, Node2BeanTransformerImpl.class);
+ ComponentsTestUtil.setImplementation(SecuritySupport.class, SecuritySupportImpl.class);
+
factory = new SecuritySupportObservedComponentFactory();
}
@@ -111,4 +116,4 @@ public class SecuritySupportObservedComponentFactoryTest {
// THEN
assertTrue(securitySupport instanceof SecuritySupportImpl);
}
-}
+}
\ No newline at end of file
diff --git a/magnolia-core/src/test/java/info/magnolia/cms/security/SecurityTest.java b/magnolia-core/src/test/java/info/magnolia/cms/security/SecurityTest.java
index 7a6eeea..a4b8f9a 100644
--- a/magnolia-core/src/test/java/info/magnolia/cms/security/SecurityTest.java
+++ b/magnolia-core/src/test/java/info/magnolia/cms/security/SecurityTest.java
@@ -33,11 +33,14 @@
*/
package info.magnolia.cms.security;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;
-import info.magnolia.cms.security.auth.PrincipalCollectionImpl;
+import info.magnolia.cms.security.auth.PrincipalCollection;
import info.magnolia.context.MgnlContext;
+import info.magnolia.init.MagnoliaConfigurationProperties;
+import info.magnolia.jcr.util.NodeNameHelper;
import info.magnolia.module.InstallContextImpl;
import info.magnolia.module.InstallStatus;
import info.magnolia.repository.RepositoryConstants;
@@ -45,10 +48,12 @@ import info.magnolia.test.ComponentsTestUtil;
import info.magnolia.test.mock.MockUtil;
import java.security.Principal;
-import java.util.Iterator;
import javax.security.auth.Subject;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -57,6 +62,10 @@ public class SecurityTest {
private final class DummyUserManager extends MgnlUserManager {
+ private DummyUserManager(NodeNameHelper nodeNameHelper) {
+ super(nodeNameHelper);
+ }
+
@Override
public User getAnonymousUser() {
return getUser("anonymous");
@@ -71,8 +80,9 @@ public class SecurityTest {
@Before
public void setUp() throws Exception {
final SecuritySupportImpl sec = new SecuritySupportImpl();
- sec.addUserManager(Realm.REALM_SYSTEM.getName(), new DummyUserManager());
- sec.setRoleManager(new MgnlRoleManager());
+ NodeNameHelper nodeNameHelper = new NodeNameHelper(mock(MagnoliaConfigurationProperties.class));
+ sec.addUserManager(Realm.REALM_SYSTEM.getName(), new DummyUserManager(nodeNameHelper));
+ sec.setRoleManager(new MgnlRoleManager(nodeNameHelper));
ComponentsTestUtil.setInstance(SecuritySupport.class, sec);
MockUtil.initMockContext();
MockUtil.createAndSetHierarchyManager(RepositoryConstants.USERS, getClass().getResourceAsStream("anonymous-user.properties"));
@@ -90,15 +100,31 @@ public class SecurityTest {
}
@Test
- public void testMergePrincipals() throws AccessDeniedException {
+ public void mergePrincipals() throws Exception {
Subject subject = Security.getAnonymousSubject();
- assertEquals("anonymous", subject.getPrincipals(User.class).iterator().next().getName());
-
- Iterator principalCollectionIter = subject.getPrincipals(PrincipalCollectionImpl.class).iterator();
- Iterator principalIter = principalCollectionIter.next().iterator();
- assertEquals("website", principalIter.next().getName());
- assertEquals("data", principalIter.next().getName());
- assertEquals("imaging", principalIter.next().getName());
- assertFalse(principalIter.hasNext());
+ assertThat(subject.getPrincipals(User.class).iterator().next().getName(), equalTo("anonymous"));
+
+ PrincipalCollection principals = subject.getPrincipals(PrincipalCollection.class).iterator().next();
+
+ assertThat(principals, containsInAnyOrder(aclNamed("website"), aclNamed("data"), aclNamed("imaging")));
+ }
+
+ private Matcher aclNamed(final String name) {
+ return new TypeSafeMatcher() {
+ @Override
+ public void describeTo(final Description description) {
+ description.appendText("getName should return ").appendValue(name);
+ }
+
+ @Override
+ protected void describeMismatchSafely(final Principal item, final Description mismatchDescription) {
+ mismatchDescription.appendText(" was ").appendValue(item.getName());
+ }
+
+ @Override
+ protected boolean matchesSafely(final Principal item) {
+ return item.getName().equals(name);
+ }
+ };
}
-}
+}
\ No newline at end of file
diff --git a/magnolia-core/src/test/java/info/magnolia/jcr/util/NodeNameHelperTest.java b/magnolia-core/src/test/java/info/magnolia/jcr/util/NodeNameHelperTest.java
new file mode 100644
index 0000000..2aa676e
--- /dev/null
+++ b/magnolia-core/src/test/java/info/magnolia/jcr/util/NodeNameHelperTest.java
@@ -0,0 +1,151 @@
+/**
+ * This file Copyright (c) 2017 Magnolia International
+ * Ltd. (http://www.magnolia-cms.com). All rights reserved.
+ *
+ *
+ * This file is dual-licensed under both the Magnolia
+ * Network Agreement and the GNU General Public License.
+ * You may elect to use one or the other of these licenses.
+ *
+ * This file is distributed in the hope that it will be
+ * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
+ * Redistribution, except as permitted by whichever of the GPL
+ * or MNA you select, is prohibited.
+ *
+ * 1. For the GPL license (GPL), you can redistribute and/or
+ * modify this file under the terms of the GNU General
+ * Public License, Version 3, as published by the Free Software
+ * Foundation. You should have received a copy of the GNU
+ * General Public License, Version 3 along with this program;
+ * if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 2. For the Magnolia Network Agreement (MNA), this file
+ * and the accompanying materials are made available under the
+ * terms of the MNA which accompanies this distribution, and
+ * is available at http://www.magnolia-cms.com/mna.html
+ *
+ * Any modifications to this file must keep this entire header
+ * intact.
+ *
+ */
+package info.magnolia.jcr.util;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.*;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+
+import info.magnolia.init.MagnoliaConfigurationProperties;
+import info.magnolia.repository.RepositoryConstants;
+import info.magnolia.test.mock.jcr.MockSession;
+
+import javax.jcr.Node;
+import javax.jcr.Session;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class NodeNameHelperTest {
+
+ private NodeNameHelper nodeNameHelper;
+ private Session session;
+
+ @Before
+ public void setUp() {
+ // GIVEN
+ nodeNameHelper = new NodeNameHelper(mock(MagnoliaConfigurationProperties.class));
+ session = new MockSession(RepositoryConstants.CONFIG);
+ }
+
+ @Test
+ public void getValidatedName() throws Exception {
+ // WHEN-THEN
+ // plain chars tests
+ assertEquals("f", nodeNameHelper.getValidatedName("f", null));
+ assertEquals("fo", nodeNameHelper.getValidatedName("fo", null));
+ assertEquals("foo", nodeNameHelper.getValidatedName("foo", null));
+
+ // dot tests
+ assertEquals("foo.bar", nodeNameHelper.getValidatedName("foo.bar", null));
+ assertEquals("foo..bar", nodeNameHelper.getValidatedName("foo..bar", null));
+ // local names beginning with dot are not allowed
+ assertEquals("-foo", nodeNameHelper.getValidatedName(".foo", null));
+ assertEquals("-.foo", nodeNameHelper.getValidatedName("..foo", null));
+
+ // invalid or special chars tests
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f$oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f*oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f[oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f]oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f;oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f:oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f\"oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f'oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f#oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f!oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f+oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f?oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f/oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f%oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f oo", null)); // if you can't see it, that's a space (ascii code 32)
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f-oo", null));
+ assertEquals("f_oo", nodeNameHelper.getValidatedName("f_oo", null));
+ assertEquals("f-oo", nodeNameHelper.getValidatedName("f~oo", null));
+
+ // (alpha)numeric chars tests
+ assertEquals("0", nodeNameHelper.getValidatedName("0", null));
+ assertEquals("0foo", nodeNameHelper.getValidatedName("0foo", null));
+ assertEquals("123", nodeNameHelper.getValidatedName("123", null));
+ assertEquals("foo0", nodeNameHelper.getValidatedName("foo0", null));
+
+ // uppercase test
+ assertEquals("FOO", nodeNameHelper.getValidatedName("FOO", null));
+
+ // empty or blank labels
+ assertEquals("untitled", nodeNameHelper.getValidatedName(null, null));
+ assertEquals("untitled", nodeNameHelper.getValidatedName("", null));
+ assertEquals("----", nodeNameHelper.getValidatedName(" ", null));
+ }
+
+ @Test
+ public void getUniqueName() throws Exception {
+ // GIVEN
+ Node parent = session.getRootNode();
+ parent.addNode("a");
+ parent.addNode("b");
+ parent.addNode("b0");
+
+ // WHEN-THEN
+ // from node
+ assertThat(nodeNameHelper.getUniqueName(parent, "a"), equalTo("a0"));
+ assertThat(nodeNameHelper.getUniqueName(parent, "b"), equalTo("b1"));
+ assertThat(nodeNameHelper.getUniqueName(parent, "b0"), equalTo("b1"));
+ assertThat(nodeNameHelper.getUniqueName(parent, "c"), equalTo("c"));
+
+ // from session
+ assertThat(nodeNameHelper.getUniqueName(session, parent.getPath(), "a"), equalTo("a0"));
+ assertThat(nodeNameHelper.getUniqueName(session, parent.getPath(), "b"), equalTo("b1"));
+ assertThat(nodeNameHelper.getUniqueName(session, parent.getPath(), "b0"), equalTo("b1"));
+ assertThat(nodeNameHelper.getUniqueName(session, parent.getPath(), "c"), equalTo("c"));
+ }
+
+ @Test
+ public void getUniqueNameWithExtension() throws Exception {
+ // GIVEN
+ Node parent = session.getRootNode();
+ parent.addNode("a.txt");
+ parent.addNode("b.txt");
+ parent.addNode("b0.txt");
+
+ // WHEN-THEN
+ assertThat(nodeNameHelper.getUniqueName(session, parent.getPath(), "a.txt", "txt"), equalTo("a0.txt"));
+ assertThat(nodeNameHelper.getUniqueName(session, parent.getPath(), "b.txt", "txt"), equalTo("b1.txt"));
+ assertThat(nodeNameHelper.getUniqueName(session, parent.getPath(), "b0.txt", "txt"), equalTo("b1.txt"));
+ assertThat(nodeNameHelper.getUniqueName(session, parent.getPath(), "c.txt", "txt"), equalTo("c.txt"));
+ assertThat(nodeNameHelper.getUniqueName(session, parent.getPath(), "a.foo", "txt"), equalTo("a.foo"));
+ assertThat(nodeNameHelper.getUniqueName(session, parent.getPath(), "a.txt", "bar"), equalTo("a.txt0"));
+ }
+}
\ No newline at end of file
diff --git a/magnolia-core/src/test/java/info/magnolia/module/delta/RemoveDuplicatePermissionTaskTest.java b/magnolia-core/src/test/java/info/magnolia/module/delta/RemoveDuplicatePermissionTaskTest.java
index ea77fd3..f6f5b85 100644
--- a/magnolia-core/src/test/java/info/magnolia/module/delta/RemoveDuplicatePermissionTaskTest.java
+++ b/magnolia-core/src/test/java/info/magnolia/module/delta/RemoveDuplicatePermissionTaskTest.java
@@ -35,13 +35,14 @@ package info.magnolia.module.delta;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
-
import info.magnolia.cms.security.MgnlRoleManager;
import info.magnolia.cms.security.Security;
import info.magnolia.cms.security.SecuritySupport;
import info.magnolia.cms.security.SecuritySupportImpl;
import info.magnolia.context.MgnlContext;
+import info.magnolia.init.MagnoliaConfigurationProperties;
import info.magnolia.jcr.iterator.SameChildNodeTypeIterator;
+import info.magnolia.jcr.util.NodeNameHelper;
import info.magnolia.module.InstallContextImpl;
import info.magnolia.module.InstallStatus;
import info.magnolia.module.ModuleRegistryImpl;
@@ -63,7 +64,8 @@ public class RemoveDuplicatePermissionTaskTest {
@Before
public void setUp() throws Exception {
final SecuritySupportImpl sec = new SecuritySupportImpl();
- sec.setRoleManager(new MgnlRoleManager());
+ final NodeNameHelper nodeNameHelper = new NodeNameHelper(mock(MagnoliaConfigurationProperties.class));
+ sec.setRoleManager(new MgnlRoleManager(nodeNameHelper));
ComponentsTestUtil.setInstance(SecuritySupport.class, sec);
MockUtil.initMockContext();
MockUtil.createAndSetHierarchyManager(RepositoryConstants.USER_ROLES, getClass().getResourceAsStream("sample-userroles.properties"));
diff --git a/magnolia-freemarker-support/pom.xml b/magnolia-freemarker-support/pom.xml
index 681c82d..719cd04 100644
--- a/magnolia-freemarker-support/pom.xml
+++ b/magnolia-freemarker-support/pom.xml
@@ -4,7 +4,7 @@
info.magnolia
magnolia-project
- 5.4.14
+ 5.4.14-MAGNOLIA-7028
../pom.xml
info.magnolia.core
diff --git a/magnolia-i18n/pom.xml b/magnolia-i18n/pom.xml
index 1fa9fb1..a408924 100644
--- a/magnolia-i18n/pom.xml
+++ b/magnolia-i18n/pom.xml
@@ -3,7 +3,7 @@
magnolia-project
info.magnolia
- 5.4.14
+ 5.4.14-MAGNOLIA-7028
../pom.xml
4.0.0
diff --git a/magnolia-jaas/pom.xml b/magnolia-jaas/pom.xml
index bfcb338..21d0503 100644
--- a/magnolia-jaas/pom.xml
+++ b/magnolia-jaas/pom.xml
@@ -3,7 +3,7 @@
magnolia-project
info.magnolia
- 5.4.14
+ 5.4.14-MAGNOLIA-7028
../pom.xml
4.0.0
diff --git a/magnolia-rendering/pom.xml b/magnolia-rendering/pom.xml
index 7993812..4eb3b85 100644
--- a/magnolia-rendering/pom.xml
+++ b/magnolia-rendering/pom.xml
@@ -3,7 +3,7 @@
magnolia-project
info.magnolia
- 5.4.14
+ 5.4.14-MAGNOLIA-7028
../pom.xml
4.0.0
diff --git a/magnolia-resource-loader/pom.xml b/magnolia-resource-loader/pom.xml
index 2358427..9fd22b6 100644
--- a/magnolia-resource-loader/pom.xml
+++ b/magnolia-resource-loader/pom.xml
@@ -4,7 +4,7 @@
magnolia-project
info.magnolia
- 5.4.14
+ 5.4.14-MAGNOLIA-7028
../pom.xml
diff --git a/magnolia-templating-jsp/pom.xml b/magnolia-templating-jsp/pom.xml
index 52e991d..4787d08 100644
--- a/magnolia-templating-jsp/pom.xml
+++ b/magnolia-templating-jsp/pom.xml
@@ -4,7 +4,7 @@
magnolia-project
info.magnolia
- 5.4.14
+ 5.4.14-MAGNOLIA-7028
../pom.xml
magnolia-templating-jsp
diff --git a/magnolia-templating/pom.xml b/magnolia-templating/pom.xml
index 7cc38bf..ca50143 100644
--- a/magnolia-templating/pom.xml
+++ b/magnolia-templating/pom.xml
@@ -4,7 +4,7 @@
magnolia-project
info.magnolia
- 5.4.14
+ 5.4.14-MAGNOLIA-7028
../pom.xml
magnolia-templating
diff --git a/pom.xml b/pom.xml
index e3ecf7f..37e88d4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
magnolia-project
pom
Magnolia Main Project (Parent)
- 5.4.14
+ 5.4.14-MAGNOLIA-7028
Magnolia is an open-source enterprise class Content Management System
developed by Magnolia International Ltd., based on the standard API