You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bd...@apache.org on 2015/11/19 18:08:23 UTC
svn commit: r1715217 - in /commons/proper/io/trunk/src:
main/java/org/apache/commons/io/serialization/
test/java/org/apache/commons/io/serialization/
Author: bdelacretaz
Date: Thu Nov 19 17:08:23 2015
New Revision: 1715217
URL: http://svn.apache.org/viewvc?rev=1715217&view=rev
Log:
IO-487 - ValidatingObjectInputStream, restricts which classes can be deserialized
Added:
commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/
commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ClassNameMatcher.java
commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/FullClassNameMatcher.java
commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/RegexpClassNameMatcher.java
commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java
commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/WildcardClassNameMatcher.java
commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/
commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/FullClassNameMatcherTest.java
commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/OurTestClass.java
commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/RegexpClassNameMatcherTest.java
commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/ValidatingObjectInputStreamTest.java
commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/WildcardClassNameMatcherTest.java
Added: commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ClassNameMatcher.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ClassNameMatcher.java?rev=1715217&view=auto
==============================================================================
--- commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ClassNameMatcher.java (added)
+++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ClassNameMatcher.java Thu Nov 19 17:08:23 2015
@@ -0,0 +1,29 @@
+/*
+ * 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.commons.io.serialization;
+
+/** Match a Class name */
+public interface ClassNameMatcher {
+
+ /** True if the supplied class names matches.
+ * @param className fully qualified class name
+ * @return true if the class name matches this object's condition
+ */
+ boolean matches(String className);
+}
\ No newline at end of file
Added: commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/FullClassNameMatcher.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/FullClassNameMatcher.java?rev=1715217&view=auto
==============================================================================
--- commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/FullClassNameMatcher.java (added)
+++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/FullClassNameMatcher.java Thu Nov 19 17:08:23 2015
@@ -0,0 +1,44 @@
+/*
+ * 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.commons.io.serialization;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/** {@link ClassNameMatcher} that matches on full class names */
+final class FullClassNameMatcher implements ClassNameMatcher {
+
+ private final Set<String> classesSet;
+
+ /**
+ * Constructs an object based on the specified class names.
+ *
+ * @param classes a list of class names
+ */
+ public FullClassNameMatcher(String... classes) {
+ classesSet = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(classes)));
+ }
+
+ @Override
+ public boolean matches(String className) {
+ return classesSet.contains(className);
+ }
+}
\ No newline at end of file
Added: commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/RegexpClassNameMatcher.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/RegexpClassNameMatcher.java?rev=1715217&view=auto
==============================================================================
--- commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/RegexpClassNameMatcher.java (added)
+++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/RegexpClassNameMatcher.java Thu Nov 19 17:08:23 2015
@@ -0,0 +1,53 @@
+/*
+ * 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.commons.io.serialization;
+
+import java.util.regex.Pattern;
+
+/** {@link ClassNameMatcher} that uses regular expressions */
+final class RegexpClassNameMatcher implements ClassNameMatcher {
+
+ private final Pattern pattern; // Class is thread-safe
+
+ /**
+ * Constructs an object based on the specified regular expression.
+ *
+ * @param regex a regular expression for evaluating acceptable class names
+ */
+ public RegexpClassNameMatcher(String regex) {
+ this(Pattern.compile(regex));
+ }
+
+ /**
+ * Constructs an object based on the specified pattern.
+ *
+ * @param pattern a pattern for evaluating acceptable class names
+ */
+ public RegexpClassNameMatcher(Pattern pattern) {
+ if(pattern == null) {
+ throw new IllegalArgumentException("Null pattern");
+ }
+ this.pattern = pattern;
+ }
+
+ @Override
+ public boolean matches(String className) {
+ return pattern.matcher(className).matches();
+ }
+}
\ No newline at end of file
Added: commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java?rev=1715217&view=auto
==============================================================================
--- commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java (added)
+++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java Thu Nov 19 17:08:23 2015
@@ -0,0 +1,194 @@
+/*
+ * 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.commons.io.serialization;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidClassException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * <p>
+ * An <code>ObjectInputStream</code> that's restricted to deserialize
+ * a limited set of classes.
+ * </p>
+ *
+ * <p>
+ * Various accept/reject methods allow for specifying which classes
+ * can be deserialized.
+ * </p>
+ *
+ * <p>
+ * Design inspired by <a
+ * href="http://www.ibm.com/developerworks/library/se-lookahead/">IBM
+ * DeveloperWorks Article</a>.
+ * </p>
+ */
+public class ValidatingObjectInputStream extends ObjectInputStream {
+ private final List<ClassNameMatcher> acceptMatchers = new ArrayList<ClassNameMatcher>();
+ private final List<ClassNameMatcher> rejectMatchers = new ArrayList<ClassNameMatcher>();
+
+ /**
+ * Constructs an object to deserialize the specified input stream.
+ * At least one accept method needs to be called to specify which
+ * classes can be deserialized, as by default no classes are
+ * accepted.
+ *
+ * @param input an input stream
+ * @param acceptor a class acceptor
+ * @throws IOException if an I/O error occurs while reading stream header
+ */
+ public ValidatingObjectInputStream(InputStream input) throws IOException {
+ super(input);
+ }
+
+ private void validateClassName(String name) throws InvalidClassException {
+ // Reject has precedence over accept
+ for(ClassNameMatcher m : rejectMatchers) {
+ if(m.matches(name)) {
+ invalidClassNameFound(name);
+ }
+ }
+
+ boolean ok = false;
+ for(ClassNameMatcher m : acceptMatchers) {
+ if(m.matches(name)) {
+ ok = true;
+ break;
+ }
+ }
+ if(!ok) {
+ invalidClassNameFound(name);
+ }
+ }
+
+ /** Called to throw InvalidClassException (by default) if an invalid
+ * class name is found in deserialization. Can be overridden, for example
+ * to log those class names.
+ * By default the name of the invalid class is not included in the
+ * exception thrown, as that might give too much information from a
+ * security point of view.
+ *
+ * @param className name of the invalid class
+ * @throws InvalidClassException
+ */
+ protected void invalidClassNameFound(String className) throws InvalidClassException{
+ throw new InvalidClassException("Class name not accepted");
+ }
+
+ @Override
+ protected Class<?> resolveClass(ObjectStreamClass osc) throws IOException, ClassNotFoundException {
+ validateClassName(osc.getName());
+ return super.resolveClass(osc);
+ }
+
+ /** Accept the specified classes for deserialization, unless they
+ * are otherwise rejected.
+ * @param classes Classes to accept
+ * @return this object
+ */
+ public ValidatingObjectInputStream accept(Class<?>... classes) {
+ for(Class<?> c : classes) {
+ acceptMatchers.add(new FullClassNameMatcher(c.getName()));
+ }
+ return this;
+ }
+
+ /** Reject the specified classes for deserialization, even if they
+ * are otherwise accepted.
+ * @param classes Classes to reject
+ * @return this object
+ */
+ public ValidatingObjectInputStream reject(Class<?>... classes) {
+ for(Class<?> c : classes) {
+ rejectMatchers.add(new FullClassNameMatcher(c.getName()));
+ }
+ return this;
+ }
+
+ /** Accept the wildcard specified classes for deserialization,
+ * unless they are otherwise rejected.
+ * @param patterns Wildcard filename patterns as defined by
+ * {@link FilenameUtils.wildcardMatch}
+ * @return this object
+ */
+ public ValidatingObjectInputStream accept(String ... patterns) {
+ for(String pattern : patterns) {
+ acceptMatchers.add(new WildcardClassNameMatcher(pattern));
+ }
+ return this;
+ }
+
+ /** Reject the wildcard specified classes for deserialization,
+ * even if they are otherwise accepted.
+ * @param patterns Wildcard filename patterns as defined by
+ * {@link FilenameUtils.wildcardMatch}
+ * @return this object
+ */
+ public ValidatingObjectInputStream reject(String ... patterns) {
+ for(String pattern : patterns) {
+ rejectMatchers.add(new WildcardClassNameMatcher(pattern));
+ }
+ return this;
+ }
+
+ /** Accept class names that match the supplied pattern for
+ * deserialization, unless they are otherwise rejected.
+ * @param pattern standard Java regexp
+ * @return this object
+ */
+ public ValidatingObjectInputStream accept(Pattern pattern) {
+ acceptMatchers.add(new RegexpClassNameMatcher(pattern));
+ return this;
+ }
+
+ /** Reject class names that match the supplied pattern for
+ * deserialization, even if they are otherwise accepted.
+ * @param pattern standard Java regexp
+ * @return this object
+ */
+ public ValidatingObjectInputStream reject(Pattern pattern) {
+ rejectMatchers.add(new RegexpClassNameMatcher(pattern));
+ return this;
+ }
+
+ /** Accept class names where the supplied ClassNameMatcher matches for
+ * deserialization, unless they are otherwise rejected.
+ * @param m the matcher to use
+ * @return this object
+ */
+ public ValidatingObjectInputStream accept(ClassNameMatcher m) {
+ acceptMatchers.add(m);
+ return this;
+ }
+
+ /** Reject class names where the supplied ClassNameMatcher matches for
+ * deserialization, even if they are otherwise accepted.
+ * @param m the matcher to use
+ * @return this object
+ */
+ public ValidatingObjectInputStream reject(ClassNameMatcher m) {
+ rejectMatchers.add(m);
+ return this;
+ }
+}
\ No newline at end of file
Added: commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/WildcardClassNameMatcher.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/WildcardClassNameMatcher.java?rev=1715217&view=auto
==============================================================================
--- commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/WildcardClassNameMatcher.java (added)
+++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/WildcardClassNameMatcher.java Thu Nov 19 17:08:23 2015
@@ -0,0 +1,41 @@
+/*
+ * 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.commons.io.serialization;
+
+import org.apache.commons.io.FilenameUtils;
+
+/** {@link ClassNameMatcher} that uses simplified regular expressions
+ * provided by {@link FilenameUtils#wildcardMatch} */
+final class WildcardClassNameMatcher implements ClassNameMatcher {
+
+ private final String pattern;
+
+ /**
+ * Constructs an object based on the specified simplified regular expression.
+ * @param regex a {@link FilenameUtils#wildcardMatch} pattern.
+ */
+ public WildcardClassNameMatcher(String pattern) {
+ this.pattern = pattern;
+ }
+
+ @Override
+ public boolean matches(String className) {
+ return FilenameUtils.wildcardMatch(className, pattern);
+ }
+}
\ No newline at end of file
Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/FullClassNameMatcherTest.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/FullClassNameMatcherTest.java?rev=1715217&view=auto
==============================================================================
--- commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/FullClassNameMatcherTest.java (added)
+++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/FullClassNameMatcherTest.java Thu Nov 19 17:08:23 2015
@@ -0,0 +1,42 @@
+/*
+ * 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.commons.io.serialization;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class FullClassNameMatcherTest {
+
+ private static final String [] NAMES_ARRAY = { Integer.class.getName(), Long.class.getName() };
+
+ @Test
+ public void noNames() throws Exception {
+ final FullClassNameMatcher m = new FullClassNameMatcher();
+ assertFalse(m.matches(Integer.class.getName()));
+ }
+
+ @Test
+ public void withNames() throws Exception {
+ final FullClassNameMatcher m = new FullClassNameMatcher(NAMES_ARRAY);
+ assertTrue(m.matches(Integer.class.getName()));
+ assertFalse(m.matches(String.class.getName()));
+ }
+}
\ No newline at end of file
Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/OurTestClass.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/OurTestClass.java?rev=1715217&view=auto
==============================================================================
--- commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/OurTestClass.java (added)
+++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/OurTestClass.java Thu Nov 19 17:08:23 2015
@@ -0,0 +1,44 @@
+/*
+ * 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.commons.io.serialization;
+
+import java.io.Serializable;
+
+public class OurTestClass implements Serializable {
+ private static final long serialVersionUID = 2139985988735372175L;
+
+ private final String str;
+
+ OurTestClass(String str) {
+ this.str = str;
+ }
+
+ @Override
+ public int hashCode() {
+ return str.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if(!(obj instanceof OurTestClass)) {
+ return false;
+ }
+ return str.equals(((OurTestClass)obj).str);
+ }
+}
\ No newline at end of file
Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/RegexpClassNameMatcherTest.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/RegexpClassNameMatcherTest.java?rev=1715217&view=auto
==============================================================================
--- commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/RegexpClassNameMatcherTest.java (added)
+++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/RegexpClassNameMatcherTest.java Thu Nov 19 17:08:23 2015
@@ -0,0 +1,61 @@
+/*
+ * 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.commons.io.serialization;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+
+public class RegexpClassNameMatcherTest {
+
+ @Test
+ public void testSimplePatternFromString() {
+ ClassNameMatcher ca = new RegexpClassNameMatcher("foo.*");
+ assertTrue(ca.matches("foo.should.match"));
+ assertFalse(ca.matches("bar.should.not.match"));
+ }
+
+ @Test
+ public void testSimplePatternFromPattern() {
+ ClassNameMatcher ca = new RegexpClassNameMatcher(Pattern.compile("foo.*"));
+ assertTrue(ca.matches("foo.should.match"));
+ assertFalse(ca.matches("bar.should.not.match"));
+ }
+
+ @Test
+ public void testOrPattern() {
+ ClassNameMatcher ca = new RegexpClassNameMatcher("foo.*|bar.*");
+ assertTrue(ca.matches("foo.should.match"));
+ assertTrue(ca.matches("bar.should.match"));
+ assertFalse(ca.matches("zoo.should.not.match"));
+ }
+
+ @Test(expected=NullPointerException.class)
+ public void testNullStringPattern() {
+ new RegexpClassNameMatcher((String)null);
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testNullPatternPattern() {
+ new RegexpClassNameMatcher((Pattern)null);
+ }
+}
\ No newline at end of file
Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/ValidatingObjectInputStreamTest.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/ValidatingObjectInputStreamTest.java?rev=1715217&view=auto
==============================================================================
--- commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/ValidatingObjectInputStreamTest.java (added)
+++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/ValidatingObjectInputStreamTest.java Thu Nov 19 17:08:23 2015
@@ -0,0 +1,231 @@
+/*
+ * 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.commons.io.serialization;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidClassException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ValidatingObjectInputStreamTest {
+ private List<Closeable> toClose;
+ private OurTestClass testObject;
+ private InputStream testStream;
+
+ static private final ClassNameMatcher ALWAYS_TRUE = new ClassNameMatcher() {
+ @Override
+ public boolean matches(String className) {
+ return true;
+ }
+ };
+
+ private <T extends Closeable> T willClose(T t) {
+ toClose.add(t);
+ return t;
+ }
+
+ @Before
+ public void setup() throws IOException {
+ toClose = new ArrayList<Closeable>();
+ testObject = new OurTestClass(UUID.randomUUID().toString());
+ final ByteArrayOutputStream bos = willClose(new ByteArrayOutputStream());
+ final ObjectOutputStream oos = willClose(new ObjectOutputStream(bos));
+ oos.writeObject(testObject);
+ testStream = willClose(new ByteArrayInputStream(bos.toByteArray()));
+ }
+
+ @After
+ public void cleanup() {
+ for (Closeable c : toClose) {
+ try {
+ c.close();
+ } catch (IOException ignored) {
+ }
+ }
+ }
+
+ private void assertSerialization(ObjectInputStream ois) throws ClassNotFoundException, IOException {
+ final OurTestClass result = (OurTestClass) (ois.readObject());
+ assertEquals(testObject, result);
+ }
+
+ @Test(expected = InvalidClassException.class)
+ public void noAccept() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream)));
+ }
+
+ @Test
+ public void acceptCustomMatcher() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept(ALWAYS_TRUE)
+ );
+ }
+
+ @Test(expected = InvalidClassException.class)
+ public void rejectCustomMatcher() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept(OurTestClass.class)
+ .reject(ALWAYS_TRUE)
+ );
+ }
+
+ @Test
+ public void acceptPattern() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept(Pattern.compile(".*OurTestClass.*"))
+ );
+ }
+
+ @Test(expected = InvalidClassException.class)
+ public void rejectPattern() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept(OurTestClass.class)
+ .reject(Pattern.compile("org.*"))
+ );
+ }
+
+ @Test
+ public void acceptWildcard() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept("org.apache.commons.io.*")
+ );
+ }
+
+ @Test(expected = InvalidClassException.class)
+ public void rejectWildcard() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept(OurTestClass.class)
+ .reject("org.*")
+ );
+ }
+
+ @Test(expected = InvalidClassException.class)
+ public void ourTestClassNotAccepted() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept(Integer.class)
+ );
+ }
+
+ @Test
+ public void ourTestClassOnlyAccepted() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept(OurTestClass.class)
+ );
+ }
+
+ @Test
+ public void ourTestClassAcceptedFirst() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept(OurTestClass.class, Integer.class)
+ );
+ }
+
+ @Test
+ public void ourTestClassAcceptedSecond() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept(Integer.class, OurTestClass.class)
+ );
+ }
+
+ @Test
+ public void ourTestClassAcceptedFirstWildcard() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept("*OurTestClass","*Integer")
+ );
+ }
+
+ @Test
+ public void ourTestClassAcceptedSecondWildcard() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept("*Integer","*OurTestClass")
+ );
+ }
+
+ @Test(expected = InvalidClassException.class)
+ public void reject() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept(Long.class)
+ .reject(OurTestClass.class, Integer.class)
+ );
+ }
+
+ @Test(expected = InvalidClassException.class)
+ public void rejectPrecedence() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .accept(OurTestClass.class)
+ .reject(OurTestClass.class, Integer.class)
+ );
+ }
+
+ @Test(expected = InvalidClassException.class)
+ public void rejectOnly() throws Exception {
+ assertSerialization(
+ willClose(new ValidatingObjectInputStream(testStream))
+ .reject(Integer.class)
+ );
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void customInvalidMethod() throws Exception {
+ class CustomVOIS extends ValidatingObjectInputStream {
+ CustomVOIS(InputStream is) throws IOException {
+ super(is);
+ }
+
+ @Override
+ protected void invalidClassNameFound(String className) throws InvalidClassException {
+ throw new RuntimeException("Custom exception");
+ }
+ };
+
+ assertSerialization(
+ willClose(new CustomVOIS(testStream))
+ .reject(Integer.class)
+ );
+ }
+}
\ No newline at end of file
Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/WildcardClassNameMatcherTest.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/WildcardClassNameMatcherTest.java?rev=1715217&view=auto
==============================================================================
--- commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/WildcardClassNameMatcherTest.java (added)
+++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/WildcardClassNameMatcherTest.java Thu Nov 19 17:08:23 2015
@@ -0,0 +1,50 @@
+/*
+ * 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.commons.io.serialization;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class WildcardClassNameMatcherTest {
+
+ @Test
+ public void noPattern() {
+ ClassNameMatcher ca = new WildcardClassNameMatcher("org.foo");
+ assertTrue(ca.matches("org.foo"));
+ assertFalse(ca.matches("org.foo.and.more"));
+ assertFalse(ca.matches("org_foo"));
+ }
+
+ @Test
+ public void star() {
+ ClassNameMatcher ca = new WildcardClassNameMatcher("org*");
+ assertTrue(ca.matches("org.foo.should.match"));
+ assertFalse(ca.matches("bar.should.not.match"));
+ }
+
+ @Test
+ public void starAndQuestionMark() {
+ ClassNameMatcher ca = new WildcardClassNameMatcher("org?apache?something*");
+ assertTrue(ca.matches("org.apache_something.more"));
+ assertFalse(ca.matches("org..apache_something.more"));
+ }
+
+}
\ No newline at end of file
Re: svn commit: r1715217 - in /commons/proper/io/trunk/src:
main/java/org/apache/commons/io/serialization/ test/java/org/apache/commons/io/serialization/
Posted by Bertrand Delacretaz <bd...@apache.org>.
On Thu, Nov 19, 2015 at 2:26 PM, Benedikt Ritter <be...@gmail.com> wrote:
> +1
> Very nice to see this happening :-)
Thanks, and thanks to all the contributors to IO-487!
-Bertrand
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org
Re: svn commit: r1715217 - in /commons/proper/io/trunk/src: main/java/org/apache/commons/io/serialization/ test/java/org/apache/commons/io/serialization/
Posted by Benedikt Ritter <be...@gmail.com>.
+1
Very nice to see this happening :-)
Send from my mobile device
> Am 19.11.2015 um 18:08 schrieb bdelacretaz@apache.org:
>
> Author: bdelacretaz
> Date: Thu Nov 19 17:08:23 2015
> New Revision: 1715217
>
> URL: http://svn.apache.org/viewvc?rev=1715217&view=rev
> Log:
> IO-487 - ValidatingObjectInputStream, restricts which classes can be deserialized
>
> Added:
> commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/
> commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ClassNameMatcher.java
> commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/FullClassNameMatcher.java
> commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/RegexpClassNameMatcher.java
> commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java
> commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/WildcardClassNameMatcher.java
> commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/
> commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/FullClassNameMatcherTest.java
> commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/OurTestClass.java
> commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/RegexpClassNameMatcherTest.java
> commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/ValidatingObjectInputStreamTest.java
> commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/WildcardClassNameMatcherTest.java
>
> Added: commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ClassNameMatcher.java
> URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ClassNameMatcher.java?rev=1715217&view=auto
> ==============================================================================
> --- commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ClassNameMatcher.java (added)
> +++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ClassNameMatcher.java Thu Nov 19 17:08:23 2015
> @@ -0,0 +1,29 @@
> +/*
> + * 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.commons.io.serialization;
> +
> +/** Match a Class name */
> +public interface ClassNameMatcher {
> +
> + /** True if the supplied class names matches.
> + * @param className fully qualified class name
> + * @return true if the class name matches this object's condition
> + */
> + boolean matches(String className);
> +}
> \ No newline at end of file
>
> Added: commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/FullClassNameMatcher.java
> URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/FullClassNameMatcher.java?rev=1715217&view=auto
> ==============================================================================
> --- commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/FullClassNameMatcher.java (added)
> +++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/FullClassNameMatcher.java Thu Nov 19 17:08:23 2015
> @@ -0,0 +1,44 @@
> +/*
> + * 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.commons.io.serialization;
> +
> +import java.util.Arrays;
> +import java.util.Collections;
> +import java.util.HashSet;
> +import java.util.Set;
> +
> +/** {@link ClassNameMatcher} that matches on full class names */
> +final class FullClassNameMatcher implements ClassNameMatcher {
> +
> + private final Set<String> classesSet;
> +
> + /**
> + * Constructs an object based on the specified class names.
> + *
> + * @param classes a list of class names
> + */
> + public FullClassNameMatcher(String... classes) {
> + classesSet = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(classes)));
> + }
> +
> + @Override
> + public boolean matches(String className) {
> + return classesSet.contains(className);
> + }
> +}
> \ No newline at end of file
>
> Added: commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/RegexpClassNameMatcher.java
> URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/RegexpClassNameMatcher.java?rev=1715217&view=auto
> ==============================================================================
> --- commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/RegexpClassNameMatcher.java (added)
> +++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/RegexpClassNameMatcher.java Thu Nov 19 17:08:23 2015
> @@ -0,0 +1,53 @@
> +/*
> + * 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.commons.io.serialization;
> +
> +import java.util.regex.Pattern;
> +
> +/** {@link ClassNameMatcher} that uses regular expressions */
> +final class RegexpClassNameMatcher implements ClassNameMatcher {
> +
> + private final Pattern pattern; // Class is thread-safe
> +
> + /**
> + * Constructs an object based on the specified regular expression.
> + *
> + * @param regex a regular expression for evaluating acceptable class names
> + */
> + public RegexpClassNameMatcher(String regex) {
> + this(Pattern.compile(regex));
> + }
> +
> + /**
> + * Constructs an object based on the specified pattern.
> + *
> + * @param pattern a pattern for evaluating acceptable class names
> + */
> + public RegexpClassNameMatcher(Pattern pattern) {
> + if(pattern == null) {
> + throw new IllegalArgumentException("Null pattern");
> + }
> + this.pattern = pattern;
> + }
> +
> + @Override
> + public boolean matches(String className) {
> + return pattern.matcher(className).matches();
> + }
> +}
> \ No newline at end of file
>
> Added: commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java
> URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java?rev=1715217&view=auto
> ==============================================================================
> --- commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java (added)
> +++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java Thu Nov 19 17:08:23 2015
> @@ -0,0 +1,194 @@
> +/*
> + * 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.commons.io.serialization;
> +
> +import java.io.IOException;
> +import java.io.InputStream;
> +import java.io.InvalidClassException;
> +import java.io.ObjectInputStream;
> +import java.io.ObjectStreamClass;
> +import java.util.ArrayList;
> +import java.util.List;
> +import java.util.regex.Pattern;
> +
> +/**
> + * <p>
> + * An <code>ObjectInputStream</code> that's restricted to deserialize
> + * a limited set of classes.
> + * </p>
> + *
> + * <p>
> + * Various accept/reject methods allow for specifying which classes
> + * can be deserialized.
> + * </p>
> + *
> + * <p>
> + * Design inspired by <a
> + * href="http://www.ibm.com/developerworks/library/se-lookahead/">IBM
> + * DeveloperWorks Article</a>.
> + * </p>
> + */
> +public class ValidatingObjectInputStream extends ObjectInputStream {
> + private final List<ClassNameMatcher> acceptMatchers = new ArrayList<ClassNameMatcher>();
> + private final List<ClassNameMatcher> rejectMatchers = new ArrayList<ClassNameMatcher>();
> +
> + /**
> + * Constructs an object to deserialize the specified input stream.
> + * At least one accept method needs to be called to specify which
> + * classes can be deserialized, as by default no classes are
> + * accepted.
> + *
> + * @param input an input stream
> + * @param acceptor a class acceptor
> + * @throws IOException if an I/O error occurs while reading stream header
> + */
> + public ValidatingObjectInputStream(InputStream input) throws IOException {
> + super(input);
> + }
> +
> + private void validateClassName(String name) throws InvalidClassException {
> + // Reject has precedence over accept
> + for(ClassNameMatcher m : rejectMatchers) {
> + if(m.matches(name)) {
> + invalidClassNameFound(name);
> + }
> + }
> +
> + boolean ok = false;
> + for(ClassNameMatcher m : acceptMatchers) {
> + if(m.matches(name)) {
> + ok = true;
> + break;
> + }
> + }
> + if(!ok) {
> + invalidClassNameFound(name);
> + }
> + }
> +
> + /** Called to throw InvalidClassException (by default) if an invalid
> + * class name is found in deserialization. Can be overridden, for example
> + * to log those class names.
> + * By default the name of the invalid class is not included in the
> + * exception thrown, as that might give too much information from a
> + * security point of view.
> + *
> + * @param className name of the invalid class
> + * @throws InvalidClassException
> + */
> + protected void invalidClassNameFound(String className) throws InvalidClassException{
> + throw new InvalidClassException("Class name not accepted");
> + }
> +
> + @Override
> + protected Class<?> resolveClass(ObjectStreamClass osc) throws IOException, ClassNotFoundException {
> + validateClassName(osc.getName());
> + return super.resolveClass(osc);
> + }
> +
> + /** Accept the specified classes for deserialization, unless they
> + * are otherwise rejected.
> + * @param classes Classes to accept
> + * @return this object
> + */
> + public ValidatingObjectInputStream accept(Class<?>... classes) {
> + for(Class<?> c : classes) {
> + acceptMatchers.add(new FullClassNameMatcher(c.getName()));
> + }
> + return this;
> + }
> +
> + /** Reject the specified classes for deserialization, even if they
> + * are otherwise accepted.
> + * @param classes Classes to reject
> + * @return this object
> + */
> + public ValidatingObjectInputStream reject(Class<?>... classes) {
> + for(Class<?> c : classes) {
> + rejectMatchers.add(new FullClassNameMatcher(c.getName()));
> + }
> + return this;
> + }
> +
> + /** Accept the wildcard specified classes for deserialization,
> + * unless they are otherwise rejected.
> + * @param patterns Wildcard filename patterns as defined by
> + * {@link FilenameUtils.wildcardMatch}
> + * @return this object
> + */
> + public ValidatingObjectInputStream accept(String ... patterns) {
> + for(String pattern : patterns) {
> + acceptMatchers.add(new WildcardClassNameMatcher(pattern));
> + }
> + return this;
> + }
> +
> + /** Reject the wildcard specified classes for deserialization,
> + * even if they are otherwise accepted.
> + * @param patterns Wildcard filename patterns as defined by
> + * {@link FilenameUtils.wildcardMatch}
> + * @return this object
> + */
> + public ValidatingObjectInputStream reject(String ... patterns) {
> + for(String pattern : patterns) {
> + rejectMatchers.add(new WildcardClassNameMatcher(pattern));
> + }
> + return this;
> + }
> +
> + /** Accept class names that match the supplied pattern for
> + * deserialization, unless they are otherwise rejected.
> + * @param pattern standard Java regexp
> + * @return this object
> + */
> + public ValidatingObjectInputStream accept(Pattern pattern) {
> + acceptMatchers.add(new RegexpClassNameMatcher(pattern));
> + return this;
> + }
> +
> + /** Reject class names that match the supplied pattern for
> + * deserialization, even if they are otherwise accepted.
> + * @param pattern standard Java regexp
> + * @return this object
> + */
> + public ValidatingObjectInputStream reject(Pattern pattern) {
> + rejectMatchers.add(new RegexpClassNameMatcher(pattern));
> + return this;
> + }
> +
> + /** Accept class names where the supplied ClassNameMatcher matches for
> + * deserialization, unless they are otherwise rejected.
> + * @param m the matcher to use
> + * @return this object
> + */
> + public ValidatingObjectInputStream accept(ClassNameMatcher m) {
> + acceptMatchers.add(m);
> + return this;
> + }
> +
> + /** Reject class names where the supplied ClassNameMatcher matches for
> + * deserialization, even if they are otherwise accepted.
> + * @param m the matcher to use
> + * @return this object
> + */
> + public ValidatingObjectInputStream reject(ClassNameMatcher m) {
> + rejectMatchers.add(m);
> + return this;
> + }
> +}
> \ No newline at end of file
>
> Added: commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/WildcardClassNameMatcher.java
> URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/WildcardClassNameMatcher.java?rev=1715217&view=auto
> ==============================================================================
> --- commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/WildcardClassNameMatcher.java (added)
> +++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/serialization/WildcardClassNameMatcher.java Thu Nov 19 17:08:23 2015
> @@ -0,0 +1,41 @@
> +/*
> + * 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.commons.io.serialization;
> +
> +import org.apache.commons.io.FilenameUtils;
> +
> +/** {@link ClassNameMatcher} that uses simplified regular expressions
> + * provided by {@link FilenameUtils#wildcardMatch} */
> +final class WildcardClassNameMatcher implements ClassNameMatcher {
> +
> + private final String pattern;
> +
> + /**
> + * Constructs an object based on the specified simplified regular expression.
> + * @param regex a {@link FilenameUtils#wildcardMatch} pattern.
> + */
> + public WildcardClassNameMatcher(String pattern) {
> + this.pattern = pattern;
> + }
> +
> + @Override
> + public boolean matches(String className) {
> + return FilenameUtils.wildcardMatch(className, pattern);
> + }
> +}
> \ No newline at end of file
>
> Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/FullClassNameMatcherTest.java
> URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/FullClassNameMatcherTest.java?rev=1715217&view=auto
> ==============================================================================
> --- commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/FullClassNameMatcherTest.java (added)
> +++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/FullClassNameMatcherTest.java Thu Nov 19 17:08:23 2015
> @@ -0,0 +1,42 @@
> +/*
> + * 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.commons.io.serialization;
> +
> +import static org.junit.Assert.assertFalse;
> +import static org.junit.Assert.assertTrue;
> +
> +import org.junit.Test;
> +
> +public class FullClassNameMatcherTest {
> +
> + private static final String [] NAMES_ARRAY = { Integer.class.getName(), Long.class.getName() };
> +
> + @Test
> + public void noNames() throws Exception {
> + final FullClassNameMatcher m = new FullClassNameMatcher();
> + assertFalse(m.matches(Integer.class.getName()));
> + }
> +
> + @Test
> + public void withNames() throws Exception {
> + final FullClassNameMatcher m = new FullClassNameMatcher(NAMES_ARRAY);
> + assertTrue(m.matches(Integer.class.getName()));
> + assertFalse(m.matches(String.class.getName()));
> + }
> +}
> \ No newline at end of file
>
> Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/OurTestClass.java
> URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/OurTestClass.java?rev=1715217&view=auto
> ==============================================================================
> --- commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/OurTestClass.java (added)
> +++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/OurTestClass.java Thu Nov 19 17:08:23 2015
> @@ -0,0 +1,44 @@
> +/*
> + * 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.commons.io.serialization;
> +
> +import java.io.Serializable;
> +
> +public class OurTestClass implements Serializable {
> + private static final long serialVersionUID = 2139985988735372175L;
> +
> + private final String str;
> +
> + OurTestClass(String str) {
> + this.str = str;
> + }
> +
> + @Override
> + public int hashCode() {
> + return str.hashCode();
> + }
> +
> + @Override
> + public boolean equals(Object obj) {
> + if(!(obj instanceof OurTestClass)) {
> + return false;
> + }
> + return str.equals(((OurTestClass)obj).str);
> + }
> +}
> \ No newline at end of file
>
> Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/RegexpClassNameMatcherTest.java
> URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/RegexpClassNameMatcherTest.java?rev=1715217&view=auto
> ==============================================================================
> --- commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/RegexpClassNameMatcherTest.java (added)
> +++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/RegexpClassNameMatcherTest.java Thu Nov 19 17:08:23 2015
> @@ -0,0 +1,61 @@
> +/*
> + * 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.commons.io.serialization;
> +
> +import static org.junit.Assert.assertFalse;
> +import static org.junit.Assert.assertTrue;
> +
> +import java.util.regex.Pattern;
> +
> +import org.junit.Test;
> +
> +public class RegexpClassNameMatcherTest {
> +
> + @Test
> + public void testSimplePatternFromString() {
> + ClassNameMatcher ca = new RegexpClassNameMatcher("foo.*");
> + assertTrue(ca.matches("foo.should.match"));
> + assertFalse(ca.matches("bar.should.not.match"));
> + }
> +
> + @Test
> + public void testSimplePatternFromPattern() {
> + ClassNameMatcher ca = new RegexpClassNameMatcher(Pattern.compile("foo.*"));
> + assertTrue(ca.matches("foo.should.match"));
> + assertFalse(ca.matches("bar.should.not.match"));
> + }
> +
> + @Test
> + public void testOrPattern() {
> + ClassNameMatcher ca = new RegexpClassNameMatcher("foo.*|bar.*");
> + assertTrue(ca.matches("foo.should.match"));
> + assertTrue(ca.matches("bar.should.match"));
> + assertFalse(ca.matches("zoo.should.not.match"));
> + }
> +
> + @Test(expected=NullPointerException.class)
> + public void testNullStringPattern() {
> + new RegexpClassNameMatcher((String)null);
> + }
> +
> + @Test(expected=IllegalArgumentException.class)
> + public void testNullPatternPattern() {
> + new RegexpClassNameMatcher((Pattern)null);
> + }
> +}
> \ No newline at end of file
>
> Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/ValidatingObjectInputStreamTest.java
> URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/ValidatingObjectInputStreamTest.java?rev=1715217&view=auto
> ==============================================================================
> --- commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/ValidatingObjectInputStreamTest.java (added)
> +++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/ValidatingObjectInputStreamTest.java Thu Nov 19 17:08:23 2015
> @@ -0,0 +1,231 @@
> +/*
> + * 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.commons.io.serialization;
> +
> +import static org.junit.Assert.assertEquals;
> +
> +import java.io.ByteArrayInputStream;
> +import java.io.ByteArrayOutputStream;
> +import java.io.Closeable;
> +import java.io.IOException;
> +import java.io.InputStream;
> +import java.io.InvalidClassException;
> +import java.io.ObjectInputStream;
> +import java.io.ObjectOutputStream;
> +import java.util.ArrayList;
> +import java.util.List;
> +import java.util.UUID;
> +import java.util.regex.Pattern;
> +
> +import org.junit.After;
> +import org.junit.Before;
> +import org.junit.Test;
> +
> +public class ValidatingObjectInputStreamTest {
> + private List<Closeable> toClose;
> + private OurTestClass testObject;
> + private InputStream testStream;
> +
> + static private final ClassNameMatcher ALWAYS_TRUE = new ClassNameMatcher() {
> + @Override
> + public boolean matches(String className) {
> + return true;
> + }
> + };
> +
> + private <T extends Closeable> T willClose(T t) {
> + toClose.add(t);
> + return t;
> + }
> +
> + @Before
> + public void setup() throws IOException {
> + toClose = new ArrayList<Closeable>();
> + testObject = new OurTestClass(UUID.randomUUID().toString());
> + final ByteArrayOutputStream bos = willClose(new ByteArrayOutputStream());
> + final ObjectOutputStream oos = willClose(new ObjectOutputStream(bos));
> + oos.writeObject(testObject);
> + testStream = willClose(new ByteArrayInputStream(bos.toByteArray()));
> + }
> +
> + @After
> + public void cleanup() {
> + for (Closeable c : toClose) {
> + try {
> + c.close();
> + } catch (IOException ignored) {
> + }
> + }
> + }
> +
> + private void assertSerialization(ObjectInputStream ois) throws ClassNotFoundException, IOException {
> + final OurTestClass result = (OurTestClass) (ois.readObject());
> + assertEquals(testObject, result);
> + }
> +
> + @Test(expected = InvalidClassException.class)
> + public void noAccept() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream)));
> + }
> +
> + @Test
> + public void acceptCustomMatcher() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept(ALWAYS_TRUE)
> + );
> + }
> +
> + @Test(expected = InvalidClassException.class)
> + public void rejectCustomMatcher() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept(OurTestClass.class)
> + .reject(ALWAYS_TRUE)
> + );
> + }
> +
> + @Test
> + public void acceptPattern() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept(Pattern.compile(".*OurTestClass.*"))
> + );
> + }
> +
> + @Test(expected = InvalidClassException.class)
> + public void rejectPattern() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept(OurTestClass.class)
> + .reject(Pattern.compile("org.*"))
> + );
> + }
> +
> + @Test
> + public void acceptWildcard() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept("org.apache.commons.io.*")
> + );
> + }
> +
> + @Test(expected = InvalidClassException.class)
> + public void rejectWildcard() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept(OurTestClass.class)
> + .reject("org.*")
> + );
> + }
> +
> + @Test(expected = InvalidClassException.class)
> + public void ourTestClassNotAccepted() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept(Integer.class)
> + );
> + }
> +
> + @Test
> + public void ourTestClassOnlyAccepted() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept(OurTestClass.class)
> + );
> + }
> +
> + @Test
> + public void ourTestClassAcceptedFirst() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept(OurTestClass.class, Integer.class)
> + );
> + }
> +
> + @Test
> + public void ourTestClassAcceptedSecond() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept(Integer.class, OurTestClass.class)
> + );
> + }
> +
> + @Test
> + public void ourTestClassAcceptedFirstWildcard() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept("*OurTestClass","*Integer")
> + );
> + }
> +
> + @Test
> + public void ourTestClassAcceptedSecondWildcard() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept("*Integer","*OurTestClass")
> + );
> + }
> +
> + @Test(expected = InvalidClassException.class)
> + public void reject() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept(Long.class)
> + .reject(OurTestClass.class, Integer.class)
> + );
> + }
> +
> + @Test(expected = InvalidClassException.class)
> + public void rejectPrecedence() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .accept(OurTestClass.class)
> + .reject(OurTestClass.class, Integer.class)
> + );
> + }
> +
> + @Test(expected = InvalidClassException.class)
> + public void rejectOnly() throws Exception {
> + assertSerialization(
> + willClose(new ValidatingObjectInputStream(testStream))
> + .reject(Integer.class)
> + );
> + }
> +
> + @Test(expected = RuntimeException.class)
> + public void customInvalidMethod() throws Exception {
> + class CustomVOIS extends ValidatingObjectInputStream {
> + CustomVOIS(InputStream is) throws IOException {
> + super(is);
> + }
> +
> + @Override
> + protected void invalidClassNameFound(String className) throws InvalidClassException {
> + throw new RuntimeException("Custom exception");
> + }
> + };
> +
> + assertSerialization(
> + willClose(new CustomVOIS(testStream))
> + .reject(Integer.class)
> + );
> + }
> +}
> \ No newline at end of file
>
> Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/WildcardClassNameMatcherTest.java
> URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/WildcardClassNameMatcherTest.java?rev=1715217&view=auto
> ==============================================================================
> --- commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/WildcardClassNameMatcherTest.java (added)
> +++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/serialization/WildcardClassNameMatcherTest.java Thu Nov 19 17:08:23 2015
> @@ -0,0 +1,50 @@
> +/*
> + * 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.commons.io.serialization;
> +
> +import static org.junit.Assert.assertFalse;
> +import static org.junit.Assert.assertTrue;
> +
> +import org.junit.Test;
> +
> +public class WildcardClassNameMatcherTest {
> +
> + @Test
> + public void noPattern() {
> + ClassNameMatcher ca = new WildcardClassNameMatcher("org.foo");
> + assertTrue(ca.matches("org.foo"));
> + assertFalse(ca.matches("org.foo.and.more"));
> + assertFalse(ca.matches("org_foo"));
> + }
> +
> + @Test
> + public void star() {
> + ClassNameMatcher ca = new WildcardClassNameMatcher("org*");
> + assertTrue(ca.matches("org.foo.should.match"));
> + assertFalse(ca.matches("bar.should.not.match"));
> + }
> +
> + @Test
> + public void starAndQuestionMark() {
> + ClassNameMatcher ca = new WildcardClassNameMatcher("org?apache?something*");
> + assertTrue(ca.matches("org.apache_something.more"));
> + assertFalse(ca.matches("org..apache_something.more"));
> + }
> +
> +}
> \ No newline at end of file
>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org