This is an automated email from the ASF dual-hosted git repository. jochen pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push: new 3322d9748 Adding the @Insecure, and @Safe annotations. 3322d9748 is described below commit 3322d974876b8d4f934d3544967103ebbcaef726 Author: Jochen Wiedmann <jochen.wiedm...@gmail.com> AuthorDate: Fri May 17 00:28:39 2024 +0200 Adding the @Insecure, and @Safe annotations. --- src/changes/changes.xml | 1 + .../apache/commons/lang3/annotations/Insecure.java | 48 ++++++++ .../org/apache/commons/lang3/annotations/Safe.java | 61 +++++++++++ .../commons/lang3/annotations/package-info.java | 37 +++++++ .../commons/lang3/annotations/AnnotationsTest.java | 122 +++++++++++++++++++++ 5 files changed, 269 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 34841687a..b69e1f8a2 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -140,6 +140,7 @@ The <action> type attribute can be add,update,fix,remove. <action type="update" dev="ggregory" due-to="Dependabot">Bump org.apache.commons:commons-text from 1.11.0 to 1.12.0 #1200.</action> <!-- REMOVE --> <action type="remove" dev="ggregory" due-to="Paranoïd User">Drop obsolete JDK 13 Maven profile #1142.</action> + <action type="add" dev="jochen">Added the annotations package, including the Insecure, and Safe annotations.</action> </release> <release version="3.14.0" date="2023-11-18" description="New features and bug fixes (Java 8 or above)."> <!-- FIX --> diff --git a/src/main/java/org/apache/commons/lang3/annotations/Insecure.java b/src/main/java/org/apache/commons/lang3/annotations/Insecure.java new file mode 100644 index 000000000..2802f1189 --- /dev/null +++ b/src/main/java/org/apache/commons/lang3/annotations/Insecure.java @@ -0,0 +1,48 @@ +/* + * 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.lang3.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation is used to indicate, that a constructor, or method + * is insecure to use, unless the input parameters contain safe ("trusted") + * values. + * + * For example, consider a method like <pre> + * {@literal @Insecure} + * public void runCommand(String pCmdLine) { + * } + * </pre> + * + * The example method would invoke {@code /bin/sh} (Linux, Unix, or MacOS), or + * {@code cmd} (Windows) to run an external command, as given by the parameter + * {@code pCmdLine}. Obviously, depending on the value of the parameter, + * this can be dangerous, unless the API user (downstream developer) + * <em>knows</em>, that the parameter value is safe (for example, because it + * is hard coded, or because it has been compared to a white list of + * permissible values). + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.CONSTRUCTOR, ElementType.METHOD}) +@Documented +public @interface Insecure { +} diff --git a/src/main/java/org/apache/commons/lang3/annotations/Safe.java b/src/main/java/org/apache/commons/lang3/annotations/Safe.java new file mode 100644 index 000000000..4b5212c71 --- /dev/null +++ b/src/main/java/org/apache/commons/lang3/annotations/Safe.java @@ -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.lang3.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation is used to indicate, that a variable, field, or parameter + * contains a safe value. If so, the annotated element may be used in an + * invocation of a constructor, or method, which is annotated with + * {@code @Trusted}. + * + * For example, suggest the following method declaration: + * <pre> + * {@literal @Insecure} + * public void runCommand(String pCmdLine) { + * } + * </pre> + * + * Based on the example, this piece of source code would be invalid: + * <pre>{@code + * String cmdLine = "echo" + " " + "okay"; + * // It is unknown, whether the {@code cmdLine} variable contains a safe value. + * // Thus, the following should be considered dangerous: + * runCommand(cmdLine); + * }</pre> + * + * In the following example, however, the value of {@code cmdLine} is + * supposed to be safe, so it may be used when invoking the {@code runCommand} + * method. + * <pre> + * {@literal @Safe} String cmdLine = "echo" + " " + "okay"; + * // It is unknown, whether the {@code cmdLine} variable contains a safe value. + * // Thus, the following should be considered dangerous: + * runCommand(cmdLine); + * </pre> + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.LOCAL_VARIABLE, ElementType.FIELD, ElementType.PARAMETER}) +@Documented +public @interface Safe { + +} diff --git a/src/main/java/org/apache/commons/lang3/annotations/package-info.java b/src/main/java/org/apache/commons/lang3/annotations/package-info.java new file mode 100644 index 000000000..43d54d606 --- /dev/null +++ b/src/main/java/org/apache/commons/lang3/annotations/package-info.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +/** + * Provides annotations, that are designed to aim in static code analysis, + * and other areas of self-describing code. As of this writing, the following + * annotations are available: + * <dl> + * <dt>{@link Insecure}</dt> + * <dd>Indicates, that a constructor, method, or parameter should only + * take input, that can be considered as <em>safe</em>. + * The API user (the downstream developer) is supposed to ensure, by + * whatever means, that the input is safe, and doesn't trigger any + * security related issues.</dd> + * <dt>{@link Safe}</dt> + * <dd>By annotating a variable with {@code @Safe}, the API user + * declares, that the variable contains trusted input, that can be + * used as a parameter in an invocation of a constructor, or method, + * that is annotated with {@code @Trusted}.</dd> + * </dl> + * @since 3.15 + */ +package org.apache.commons.lang3.annotations; diff --git a/src/test/java/org/apache/commons/lang3/annotations/AnnotationsTest.java b/src/test/java/org/apache/commons/lang3/annotations/AnnotationsTest.java new file mode 100644 index 000000000..df1aa70f3 --- /dev/null +++ b/src/test/java/org/apache/commons/lang3/annotations/AnnotationsTest.java @@ -0,0 +1,122 @@ +/* + * 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.lang3.annotations; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import java.lang.annotation.Target; +import java.util.function.Function; + +import org.junit.jupiter.api.Test; + + +/** This class ensures, that the annotations are properly configured + * with regard to {@link Target}. + * + * The so-called test methods are not actually testing anything, because + * an invalid configuration would be detected by the compiler. However, + * we have the unit test framework in place, and it is running anyways, + * so there's no harm in a few additional methods. + */ +public class AnnotationsTest { + public static class Wrapper { + private final Object wrappedObject; + + @Insecure + public Wrapper(Object wrappedObject) { + this.wrappedObject = wrappedObject; + } + + Object getWrappedObject() { + return wrappedObject; + } + } + + private static Wrapper newWrapper(Object wrappedObject) { + return new Wrapper(wrappedObject); + } + + /** Test, whether we can have an @Insecure annotation on a constructor. + */ + @Test + public void testConstructorAnnotatableAsInsecure() { + final Object unsafeObject = new Object(); + // Static code analysis should reject this, because the + // parameter (the newly created instance of Object) isn't known + // to be safe. + final Wrapper wrapper = new Wrapper(unsafeObject); + assertNotNull(wrapper); + assertSame(unsafeObject, wrapper.getWrappedObject()); + } + + /** Test, whether we can have an @Insecure annotation on a method. + */ + @Test + public void testMethodAnnotatableAsInsecure() { + final Object unsafeObject = new Object(); + // Static code analysis should reject this, because the + // parameter (the newly created instance of Object) isn't known + // to be safe. + final Wrapper wrapper = newWrapper(unsafeObject); + assertNotNull(wrapper); + assertSame(unsafeObject, wrapper.getWrappedObject()); + } + + /** Test, whether we can have a @Safe annotation on a local variable. + */ + @Test + public void testLocalVariablesAnnotatableAsSafe() { + @Safe final String wrappedString = "Hello, world!"; + // Static code analysis should accept this, because the variable + // is annotated with @Safe. + final Wrapper wrapper = newWrapper(wrappedString); + assertNotNull(wrapper); + assertSame(wrappedString, wrapper.getWrappedObject()); + } + + /** Test, whether we can have a @Safe annotation on a field. + */ + @Test + public void testFieldsAnnotatableAsSafe() { + // Static code analysis should accept this, because the field + // is annotated with @Safe. + final Wrapper wrapper = newWrapper(wrappedStringField); + assertNotNull(wrapper); + assertSame(wrappedStringField, wrapper.getWrappedObject()); + } + @Safe private String wrappedStringField = "Hello, world!"; + + /** Test, whether we can have a @Safe annotation on a field. + */ + @Test + public void testParametersAnnotatableAsSafe() { + // Static code analysis should accept this, because the parameter + // is annotated with @Safe. + final Function<String, Wrapper> wrapperCreator = + new Function<String, Wrapper>() { + @Override + public Wrapper apply(@Safe String wrappedObject) { + return newWrapper(wrappedObject); + } + }; + final String helloWorldString = "Hello, world!"; + final Wrapper wrapper = wrapperCreator.apply(helloWorldString); + assertNotNull(wrapper); + assertSame(helloWorldString, wrapper.getWrappedObject()); + } +}