Add comprehensive cross-platform compatibility integration test Co-authored-by: nomeguy <85475922+nomeguy@users.noreply.github.com>
diff --git a/src/test/java/org/casbin/jcasbin/main/EvalCrossPlatformTest.java b/src/test/java/org/casbin/jcasbin/main/EvalCrossPlatformTest.java new file mode 100644 index 0000000..f1cdd0c --- /dev/null +++ b/src/test/java/org/casbin/jcasbin/main/EvalCrossPlatformTest.java
@@ -0,0 +1,181 @@ +// Copyright 2024 The casbin Authors. All Rights Reserved. +// +// Licensed 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.casbin.jcasbin.main; + +import org.casbin.jcasbin.util.ExpressionEvaluator; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Integration test to demonstrate the fix for the eval() function issue. + * This test validates that the expression evaluator prevents the use of + * aviatorscript-specific syntax mentioned in the issue, ensuring + * cross-platform compatibility. + */ +public class EvalCrossPlatformTest { + + /** + * Test that aviatorscript-specific syntax mentioned in the issue is blocked. + * Issue mentioned: seq.list(), string.startsWith(), string.endsWith(), include(seq.list(),xx) + */ + @Test + public void testAviatorScriptSyntaxFromIssue_IsBlocked() { + // All these expressions from the issue description should be blocked + + // 1. seq.list() syntax + try { + ExpressionEvaluator.validateExpression("seq.list('A', 'B')"); + fail("seq.list() should be blocked"); + } catch (IllegalArgumentException e) { + assertTrue("Should mention non-standard operations", + e.getMessage().contains("non-standard Casbin operations")); + } + + // 2. string.startsWith() syntax + try { + ExpressionEvaluator.validateExpression("string.startsWith(r.obj, '/data')"); + fail("string.startsWith() should be blocked"); + } catch (IllegalArgumentException e) { + assertTrue("Should mention non-standard operations", + e.getMessage().contains("non-standard Casbin operations")); + } + + // 3. string.endsWith() syntax + try { + ExpressionEvaluator.validateExpression("string.endsWith(r.obj, '.txt')"); + fail("string.endsWith() should be blocked"); + } catch (IllegalArgumentException e) { + assertTrue("Should mention non-standard operations", + e.getMessage().contains("non-standard Casbin operations")); + } + + // 4. include(seq.list(),xx) syntax + try { + ExpressionEvaluator.validateExpression("include(seq.list('admin', 'user'), r.sub.role)"); + fail("include(seq.list(),xx) should be blocked"); + } catch (IllegalArgumentException e) { + assertTrue("Should mention non-standard operations", + e.getMessage().contains("non-standard Casbin operations")); + } + } + + /** + * Test that standard Casbin expressions work correctly. + * These should be portable across all Casbin implementations. + */ + @Test + public void testStandardCasbinExpressions_AreAllowed() { + // All these standard expressions should work + String[] standardExpressions = { + // Property access + "r.sub.name == 'alice'", + "r.sub.age > 18", + "r.obj == '/data1'", + "r.act == 'read'", + + // Logical operators + "r.sub.age > 18 && r.sub.age < 60", + "r.sub.name == 'alice' || r.sub.name == 'bob'", + "!(r.sub.blocked == true)", + + // Comparison operators + "r.sub.level >= 5", + "r.sub.score != 0", + "r.domain == 'domain1'", + + // Arithmetic operations + "r.sub.age + 10 > 28", + "r.sub.count * 2 <= 100", + + // Registered functions (these are part of standard Casbin) + "keyMatch(r.obj, '/api/*')", + "regexMatch(r.obj, '^/data[0-9]+$')", + "custom(r.obj)" + }; + + for (String expr : standardExpressions) { + try { + ExpressionEvaluator.validateExpression(expr); + // Success - standard expression is allowed + } catch (IllegalArgumentException e) { + fail("Standard expression should be allowed: " + expr + " - Error: " + e.getMessage()); + } + } + } + + /** + * Test that the solution achieves cross-platform compatibility. + * The same expressions should work identically on Go, Node.js, Python, etc. + */ + @Test + public void testCrossPlatformCompatibility() { + // These expressions use only standard operators that are available + // in all Casbin implementations + + String[] crossPlatformExpressions = { + // Instead of seq.list('A', 'B'), use standard comparisons: + "r.sub.role == 'admin' || r.sub.role == 'moderator'", + + // Instead of string.startsWith(), use keyMatch or regexMatch: + "keyMatch(r.obj, '/api/*')", + "regexMatch(r.obj, '^/api/')", + + // Instead of string.endsWith(), use regexMatch: + "regexMatch(r.obj, '\\\\.txt$')", + + // Instead of include(seq.list(),xx), use logical OR: + "r.sub.dept == 'engineering' || r.sub.dept == 'sales'" + }; + + for (String expr : crossPlatformExpressions) { + try { + ExpressionEvaluator.validateExpression(expr); + // Success - cross-platform compatible expression + } catch (IllegalArgumentException e) { + fail("Cross-platform expression should be allowed: " + expr); + } + } + } + + /** + * Test that security is improved by blocking operations beyond Casbin spec. + */ + @Test + public void testSecurityImprovement_BlocksUnsafeOperations() { + // These operations go beyond Casbin specification and could be security risks + String[] unsafeOperations = { + "new java.io.File('/etc/passwd')", + "import java.lang.System", + "let x = System.getProperty('user.home')", + "fn hack() { return 'exploit' }", + "lambda(x) -> System.exit(0)", + "for (i = 0; i < 1000000; i++)", // potential DoS + "while (true)", // infinite loop + "math.random()" // non-deterministic + }; + + for (String expr : unsafeOperations) { + try { + ExpressionEvaluator.validateExpression(expr); + fail("Unsafe operation should be blocked: " + expr); + } catch (IllegalArgumentException e) { + // Success - unsafe operation is blocked + assertTrue("Should indicate non-standard operations", + e.getMessage().contains("non-standard Casbin operations")); + } + } + } +}