jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tri...@apache.org
Subject svn commit: r1582114 - in /jackrabbit/commons/filevault/trunk/vault-core/src: main/java/org/apache/jackrabbit/vault/packaging/ main/java/org/apache/jackrabbit/vault/packaging/impl/ test/java/org/apache/jackrabbit/vault/packaging/integration/
Date Wed, 26 Mar 2014 23:20:47 GMT
Author: tripod
Date: Wed Mar 26 23:20:47 2014
New Revision: 1582114

URL: http://svn.apache.org/r1582114
Log:
JCRVLT-42 Do not allow creation of packages with illegal JCR names

- added checks for valid names when creating or uploading or renaming packages
- filter out packages with illegal names in list

Added:
    jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestPackageCreation.java
Modified:
    jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/PackageId.java
    jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageManagerImpl.java

Modified: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/PackageId.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/PackageId.java?rev=1582114&r1=1582113&r2=1582114&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/PackageId.java
(original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/PackageId.java
Wed Mar 26 23:20:47 2014
@@ -17,6 +17,7 @@
 
 package org.apache.jackrabbit.vault.packaging;
 
+import org.apache.jackrabbit.util.XMLChar;
 import org.apache.jackrabbit.vault.util.Text;
 
 /**
@@ -117,8 +118,8 @@ public class PackageId implements Compar
             this.version = Version.create(str.toString());
         }
         this.str = getString(group, this.name, version);
-
     }
+
     /**
      * Creates a new package id
      * @param path path of the package
@@ -395,4 +396,169 @@ public class PackageId implements Compar
         return b.toString();
     }
 
+    /**
+     * Checks if this package id is valid in respect to JCR names.
+     * @return {@code true} if the names are valid
+     */
+    public boolean isValid() {
+        return PackageId.isValid(group, name, version == null ? null : version.toString());
+    }
+
+    /**
+     * Checks if the package id is valid in respect to JCR names.
+     * @param group the package group name
+     * @param name the package name
+     * @param version the (optional) version
+     * @return {@code true} if the names are valid
+     */
+    public static boolean isValid(String group, String name, String version) {
+        try {
+            assertValidJcrName(name);
+            if (version != null && !version.isEmpty()) {
+                assertValidJcrName(version);
+            }
+            for (String groupSegment: Text.explode(group, '/')) {
+                assertValidJcrName(groupSegment);
+            }
+            return true;
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+    }
+
+    // the code below is copied from org.apache.jackrabbit.spi.commons.conversion.NameParser
+
+    // constants for parser
+    private static final int STATE_PREFIX_START = 0;
+    private static final int STATE_PREFIX = 1;
+    private static final int STATE_NAME_START = 2;
+    private static final int STATE_NAME = 3;
+    private static final int STATE_URI_START = 4;
+    private static final int STATE_URI = 5;
+
+    /**
+     * Parses the <code>jcrName</code> (either qualified or expanded) and validates
it.
+     * @throws java.lang.IllegalArgumentException if the name is not valid
+     */
+    private static void assertValidJcrName(String jcrName) throws IllegalArgumentException
{
+        // trivial check
+        int len = jcrName == null ? 0 : jcrName.length();
+        if (len == 0) {
+            throw new IllegalArgumentException("empty name");
+        }
+        if (".".equals(jcrName) || "..".equals(jcrName)) {
+            throw new IllegalArgumentException(jcrName);
+        }
+
+        // parse the name
+        String prefix;
+        int nameStart = 0;
+        int state = STATE_PREFIX_START;
+        boolean trailingSpaces = false;
+
+        for (int i = 0; i < len; i++) {
+            char c = jcrName.charAt(i);
+            if (c == ':') {
+                if (state == STATE_PREFIX_START) {
+                    throw new IllegalArgumentException("Prefix must not be empty");
+                } else if (state == STATE_PREFIX) {
+                    if (trailingSpaces) {
+                        throw new IllegalArgumentException("Trailing spaces not allowed");
+                    }
+                    prefix = jcrName.substring(0, i);
+                    if (!XMLChar.isValidNCName(prefix)) {
+                        throw new IllegalArgumentException("Invalid name prefix: "+ prefix);
+                    }
+                    state = STATE_NAME_START;
+                } else if (state == STATE_URI) {
+                    // ignore -> validation of uri later on.
+                } else {
+                    throw new IllegalArgumentException("'" + c + "' not allowed in name");
+                }
+                trailingSpaces = false;
+            } else if (c == ' ') {
+                if (state == STATE_PREFIX_START || state == STATE_NAME_START) {
+                    throw new IllegalArgumentException("'" + c + "' not valid name start");
+                }
+                trailingSpaces = true;
+            } else if (Character.isWhitespace(c) || c == '[' || c == ']' || c == '*' || c
== '|') {
+                throw new IllegalArgumentException("'" + c + "' not allowed in name");
+            } else if (c == '/') {
+                if (state == STATE_URI_START) {
+                    state = STATE_URI;
+                } else if (state != STATE_URI) {
+                    throw new IllegalArgumentException("'" + c + "' not allowed in name");
+                }
+                trailingSpaces = false;
+            } else if (c == '{') {
+                if (state == STATE_PREFIX_START) {
+                    state = STATE_URI_START;
+                } else if (state == STATE_URI_START || state == STATE_URI) {
+                    // second '{' in the uri-part -> no valid expanded jcr-name.
+                    // therefore reset the nameStart and change state.
+                    state = STATE_NAME;
+                    nameStart = 0;
+                } else if (state == STATE_NAME_START) {
+                    state = STATE_NAME;
+                    nameStart = i;
+                }
+                trailingSpaces = false;
+            } else if (c == '}') {
+                if (state == STATE_URI_START || state == STATE_URI) {
+                    String tmp = jcrName.substring(1, i);
+                    if (tmp.length() == 0 || tmp.indexOf(':') != -1) {
+                        // The leading "{...}" part is empty or contains
+                        // a colon, so we treat it as a valid namespace URI.
+                        // More detailed validity checks (is it well formed,
+                        // registered, etc.) are not needed here.
+                        state = STATE_NAME_START;
+                    } else if (tmp.equals("internal")) {
+                        // As a special Jackrabbit backwards compatibility
+                        // feature, support {internal} as a valid URI prefix
+                        state = STATE_NAME_START;
+                    } else if (tmp.indexOf('/') == -1) {
+                        // The leading "{...}" contains neither a colon nor
+                        // a slash, so we can interpret it as a a part of a
+                        // normal local name.
+                        state = STATE_NAME;
+                        nameStart = 0;
+                    } else {
+                        throw new IllegalArgumentException(
+                                "The URI prefix of the name " + jcrName
+                                        + " is neither a valid URI nor a valid part"
+                                        + " of a local name.");
+                    }
+                } else if (state == STATE_PREFIX_START) {
+                    state = STATE_PREFIX; // prefix start -> validation later on will
fail.
+                } else if (state == STATE_NAME_START) {
+                    state = STATE_NAME;
+                    nameStart = i;
+                }
+                trailingSpaces = false;
+            } else {
+                if (state == STATE_PREFIX_START) {
+                    state = STATE_PREFIX; // prefix start
+                } else if (state == STATE_NAME_START) {
+                    state = STATE_NAME;
+                    nameStart = i;
+                } else if (state == STATE_URI_START) {
+                    state = STATE_URI;
+                }
+                trailingSpaces = false;
+            }
+        }
+
+        // take care of qualified jcrNames starting with '{' that are not having
+        // a terminating '}' -> make sure there are no illegal characters present.
+        if (state == STATE_URI && (jcrName.indexOf(':') > -1 || jcrName.indexOf('/')
> -1)) {
+            throw new IllegalArgumentException("Local name may not contain ':' nor '/'");
+        }
+
+        if (nameStart == len || state == STATE_NAME_START) {
+            throw new IllegalArgumentException("Local name must not be empty");
+        }
+        if (trailingSpaces) {
+            throw new IllegalArgumentException("Trailing spaces not allowed");
+        }
+    }
 }
\ No newline at end of file

Modified: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageManagerImpl.java?rev=1582114&r1=1582113&r2=1582114&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageManagerImpl.java
(original)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageManagerImpl.java
Wed Mar 26 23:20:47 2014
@@ -37,6 +37,8 @@ import javax.jcr.Session;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.spi.commons.conversion.NameParser;
+import org.apache.jackrabbit.spi.commons.conversion.PathParser;
 import org.apache.jackrabbit.vault.fs.api.ProgressTrackerListener;
 import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
 import org.apache.jackrabbit.vault.fs.config.MetaInf;
@@ -208,6 +210,9 @@ public class JcrPackageManagerImpl exten
             bin.dispose();
             throw new IOException("Package does not contain a path specification or valid
package id.");
         }
+        if (!pid.isValid()) {
+            throw new RepositoryException("Unable to create package. Illegal package name.");
+        }
 
         // create parent node
         String path = pid.getInstallationPath() + ".zip";
@@ -285,6 +290,10 @@ public class JcrPackageManagerImpl exten
             }
             pid = new PackageId(nameHint);
         }
+        if (!pid.isValid()) {
+            throw new RepositoryException("Unable to create package. Illegal package name.");
+        }
+
         // create parent node
         String path = pid.getInstallationPath() + ".zip";
         String parentPath = Text.getRelativeParent(path, 1);
@@ -344,6 +353,7 @@ public class JcrPackageManagerImpl exten
             throws RepositoryException, IOException {
         return create(group, name, null);
     }
+
     /**
      * {@inheritDoc}
      */
@@ -354,6 +364,9 @@ public class JcrPackageManagerImpl exten
         if (ext.equals("zip") || ext.equals("jar")) {
             name = name.substring(0, name.length() - 4);
         }
+        if (!PackageId.isValid(group, name, version)) {
+            throw new RepositoryException("Unable to create package. Illegal package name.");
+        }
         PackageId pid = new PackageId(group, name, version);
         Node folder = mkdir(Text.getRelativeParent(pid.getInstallationPath(), 1), false);
         try {
@@ -394,6 +407,10 @@ public class JcrPackageManagerImpl exten
         if (pack.getSize() > 0 && !pack.getDefinition().isUnwrapped()) {
             throw new PackageException("Package definition not unwrapped.");
         }
+        if (!PackageId.isValid(group, name, version)) {
+            throw new RepositoryException("Unable to rename package. Illegal package name.");
+        }
+
         JcrPackageDefinition def = pack.getDefinition();
         PackageId id = def.getId();
         PackageId newId = new PackageId(
@@ -734,6 +751,11 @@ public class JcrPackageManagerImpl exten
                 }
                 JcrPackageImpl pack = new JcrPackageImpl(child);
                 if (pack.isValid()) {
+                    // skip packages with illegal names
+                    JcrPackageDefinition jDef = pack.getDefinition();
+                    if (jDef != null && !jDef.getId().isValid()) {
+                        continue;
+                    }
                     if (filter == null || filter.contains(child.getPath())) {
                         if (!built || pack.getSize() > 0) {
                             packages.add(pack);

Added: jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestPackageCreation.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestPackageCreation.java?rev=1582114&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestPackageCreation.java
(added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/TestPackageCreation.java
Wed Mar 26 23:20:47 2014
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.packaging.integration;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.vault.packaging.PackageException;
+import org.junit.Test;
+
+import static org.junit.Assert.fail;
+
+/**
+ * <code>TestPackageInstall</code>...
+ */
+public class TestPackageCreation extends IntegrationTestBase {
+
+    public static String[] GROUP_NAMES = {"foo", "foo-zoo", "foo.zoo", "jcr:foo", "foo/zoo"};
+    public static String[] ILLEGAL_GROUP_NAMES = {"foo ", " foo", ":foo"};
+
+    public static String[] PACKAGE_NAMES = {"bar", "bar.zar", "bar-zar", "jcr:bar"};
+    public static String[] ILLEGAL_PACKAGE_NAMES = {"bar ", " bar", ":bar", "jcr/bar"};
+
+    public static String[] ILLEGAL_VERSION_NAMES = {"1.0 ", " 1.0", ":1.0", "jcr:1.0", "1/0"};
+
+    @Test
+    public void testCreateGroup() throws RepositoryException, IOException, PackageException
{
+        for (String name: GROUP_NAMES) {
+            packMgr.create(name, "bar");
+            assertNodeExists("/etc/packages/" + name + "/bar.zip");
+        }
+    }
+
+    @Test
+    public void testCreate() throws RepositoryException, IOException, PackageException {
+        for (String name: PACKAGE_NAMES) {
+            packMgr.create("foo", name);
+            assertNodeExists("/etc/packages/foo/" + name + ".zip");
+        }
+    }
+
+    @Test
+    public void testCreateWithVersion() throws RepositoryException, IOException, PackageException
{
+        packMgr.create("foo", "bar", "3.1.2");
+        assertNodeExists("/etc/packages/foo/bar-3.1.2.zip");
+    }
+
+    @Test
+    public void testCreateIllegalGroup() throws RepositoryException, IOException, PackageException
{
+        for (String name: ILLEGAL_GROUP_NAMES) {
+            try {
+                packMgr.create(name, "bar", "3.1.2");
+                fail("Illegal group name must fail: " + name);
+            } catch (RepositoryException e) {
+                // ok
+            }
+        }
+    }
+
+    @Test
+    public void testCreateIllegalName() throws RepositoryException, IOException, PackageException
{
+        for (String name: ILLEGAL_PACKAGE_NAMES) {
+            try {
+                packMgr.create("foo", name, "3.1.2");
+                fail("Illegal package name must fail: " + name);
+            } catch (RepositoryException e) {
+                // ok
+            }
+        }
+    }
+
+    @Test
+    public void testCreateIllegalVersions() throws RepositoryException, IOException, PackageException
{
+        for (String name: ILLEGAL_VERSION_NAMES) {
+            try {
+                packMgr.create("foo", "bar", name);
+                fail("Illegal version must fail: " + name);
+            } catch (RepositoryException e) {
+                // ok
+            }
+        }
+    }
+
+    @Test
+    public void testUploadIllegal() throws RepositoryException, IOException, PackageException
{
+        try {
+            packMgr.upload(getStream("testpackages/tmp_illegal.zip"), false);
+            fail("Uploading a package with an illegal name must fail.");
+        } catch (RepositoryException e) {
+            // ok
+        }
+    }
+
+}
\ No newline at end of file



Mime
View raw message