You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2022/06/19 14:20:06 UTC

[doris] branch master updated: [fix](auth) Authentication exception when the name of database or table contains an underscore in grant statement. (#10213)

This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new f728fd4933 [fix](auth) Authentication exception when the name of database or table contains an underscore in grant statement. (#10213)
f728fd4933 is described below

commit f728fd49330e08a2fa23e6018b4e4f8d4a4fcc9d
Author: Ashin Gau <As...@users.noreply.github.com>
AuthorDate: Sun Jun 19 22:20:01 2022 +0800

    [fix](auth) Authentication exception when the name of database or table contains an underscore in grant statement. (#10213)
---
 .../org/apache/doris/common/PatternMatcher.java    | 61 ++++++++++++++++++----
 .../apache/doris/mysql/privilege/DbPrivEntry.java  |  5 +-
 .../doris/mysql/privilege/GlobalPrivEntry.java     |  2 +-
 .../apache/doris/mysql/privilege/PrivBitSet.java   |  2 +-
 .../doris/mysql/privilege/TablePrivEntry.java      | 10 ++--
 .../doris/mysql/privilege/PrivEntryTest.java       | 48 +++++++++++++++++
 6 files changed, 109 insertions(+), 19 deletions(-)

diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/PatternMatcher.java b/fe/fe-core/src/main/java/org/apache/doris/common/PatternMatcher.java
index a9eddc1b5e..5b5f3f0903 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/PatternMatcher.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/PatternMatcher.java
@@ -20,27 +20,70 @@ package org.apache.doris.common;
 import com.google.common.base.Strings;
 import com.google.common.collect.Sets;
 
+import java.util.Locale;
 import java.util.Set;
 import java.util.regex.Pattern;
 
 // Wrap for Java pattern and matcher
 public class PatternMatcher {
+    public static final PatternMatcher MATCH_ANY = new PatternMatcher(Pattern.compile(".*"));
     private Pattern pattern;
+    // The name of 'user', 'database' and 'table' don't support complex matching in grant statement.
+    // Only using '%' to match any string. In other cases, it's string case-sensitive(or not) equivalent matching,
+    // so using the origin string to determine whether it matches.
+    private String originString;
+    private boolean caseSensitive;
 
     private static final Set<Character> FORBIDDEN_CHARS = Sets.newHashSet('<', '(', '[', '{', '^', '=',
                                                                           '$', '!', '|', ']', '}', ')',
                                                                           '?', '*', '+', '>', '@');
 
+    public PatternMatcher(Pattern pattern) {
+        this.pattern = pattern;
+    }
+
+    public PatternMatcher(String originString, boolean caseSensitive) {
+        this.originString = caseSensitive ? originString : originString.toLowerCase(Locale.ROOT);
+        this.caseSensitive = caseSensitive;
+    }
+
     public boolean match(String candidate) {
-        if (pattern == null || candidate == null) {
-            // No pattern, how can I explain this? Return false now.
-            // No candidate, return false.
+        if (candidate == null) {
             return false;
         }
-        if (pattern.matcher(candidate).matches()) {
-            return true;
+        if (pattern != null) {
+            return pattern.matcher(candidate).matches();
+        }
+        if (caseSensitive) {
+            return candidate.equals(originString);
+        } else {
+            return candidate.toLowerCase(Locale.ROOT).equals(originString);
+        }
+    }
+
+    /**
+     * Use in grant statement to support case-sensitive(or not) equivalent matching.
+     *
+     * @param originString The string to match.
+     * @param caseSensitive Case sensitive.
+     */
+    public static PatternMatcher createFlatPattern(String originString, boolean caseSensitive) {
+        return createFlatPattern(originString, caseSensitive, false);
+    }
+
+    /**
+     * Use in grant statement to support case-sensitive(or not) equivalent matching, or arbitrary matching.
+     *
+     * @param originString The string to match. If matchAny = true, this parameter has no effect.
+     * @param caseSensitive Case sensitive.
+     * @param matchAny match any string.
+     */
+    public static PatternMatcher createFlatPattern(
+            String originString, boolean caseSensitive, boolean matchAny) {
+        if (matchAny) {
+            return MATCH_ANY;
         }
-        return false;
+        return new PatternMatcher(originString, caseSensitive);
     }
 
     /*
@@ -149,7 +192,7 @@ public class PatternMatcher {
 
     public static PatternMatcher createMysqlPattern(String mysqlPattern, boolean caseSensitive)
             throws AnalysisException {
-        PatternMatcher matcher = new PatternMatcher();
+        PatternMatcher matcher;
 
         // Match nothing
         String newMysqlPattern = Strings.nullToEmpty(mysqlPattern);
@@ -157,9 +200,9 @@ public class PatternMatcher {
         String javaPattern = convertMysqlPattern(newMysqlPattern);
         try {
             if (caseSensitive) {
-                matcher.pattern = Pattern.compile(javaPattern);
+                matcher = new PatternMatcher(Pattern.compile(javaPattern));
             } else {
-                matcher.pattern = Pattern.compile(javaPattern, Pattern.CASE_INSENSITIVE);
+                matcher = new PatternMatcher(Pattern.compile(javaPattern, Pattern.CASE_INSENSITIVE));
             }
         } catch (Exception e) {
             throw new AnalysisException("Bad pattern in SQL: " + e.getMessage());
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/DbPrivEntry.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/DbPrivEntry.java
index 06a37b1942..a8f1337df7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/DbPrivEntry.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/DbPrivEntry.java
@@ -54,7 +54,7 @@ public class DbPrivEntry extends PrivEntry {
 
         PatternMatcher dbPattern = createDbPatternMatcher(db);
 
-        PatternMatcher userPattern = PatternMatcher.createMysqlPattern(user, CaseSensibility.USER.getCaseSensibility());
+        PatternMatcher userPattern = PatternMatcher.createFlatPattern(user, CaseSensibility.USER.getCaseSensibility());
 
         if (privs.containsNodePriv() || privs.containsResourcePriv()) {
             throw new AnalysisException("Db privilege can not contains global or resource privileges: " + privs);
@@ -70,8 +70,7 @@ public class DbPrivEntry extends PrivEntry {
             dbCaseSensibility = false;
         }
 
-        PatternMatcher dbPattern = PatternMatcher.createMysqlPattern(db.equals(ANY_DB) ? "%" : db, dbCaseSensibility);
-        return dbPattern;
+        return PatternMatcher.createFlatPattern(db, dbCaseSensibility, db.equals(ANY_DB));
     }
 
     public PatternMatcher getDbPattern() {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/GlobalPrivEntry.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/GlobalPrivEntry.java
index ba74d280b2..6444d6b8e2 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/GlobalPrivEntry.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/GlobalPrivEntry.java
@@ -53,7 +53,7 @@ public class GlobalPrivEntry extends PrivEntry {
     public static GlobalPrivEntry create(String host, String user, boolean isDomain, byte[] password, PrivBitSet privs)
             throws AnalysisException {
         PatternMatcher hostPattern = PatternMatcher.createMysqlPattern(host, CaseSensibility.HOST.getCaseSensibility());
-        PatternMatcher userPattern = PatternMatcher.createMysqlPattern(user, CaseSensibility.USER.getCaseSensibility());
+        PatternMatcher userPattern = PatternMatcher.createFlatPattern(user, CaseSensibility.USER.getCaseSensibility());
         return new GlobalPrivEntry(hostPattern, host, userPattern, user, isDomain, password, privs);
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PrivBitSet.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PrivBitSet.java
index 58fd169c59..9b47c69ebd 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PrivBitSet.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PrivBitSet.java
@@ -47,7 +47,7 @@ public class PrivBitSet implements Writable {
 
     public void unset(int index) {
         Preconditions.checkState(index < PaloPrivilege.privileges.length, index);
-        set &= ~set;
+        set &= 1 << index;
     }
 
     public boolean get(int index) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/TablePrivEntry.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/TablePrivEntry.java
index 82752c7ba3..c85a1f2912 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/TablePrivEntry.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/TablePrivEntry.java
@@ -50,12 +50,12 @@ public class TablePrivEntry extends DbPrivEntry {
     public static TablePrivEntry create(String host, String db, String user, String tbl, boolean isDomain,
             PrivBitSet privs) throws AnalysisException {
         PatternMatcher hostPattern = PatternMatcher.createMysqlPattern(host, CaseSensibility.HOST.getCaseSensibility());
-        PatternMatcher dbPattern = PatternMatcher.createMysqlPattern(db.equals(ANY_DB) ? "%" : db,
-                                                                     CaseSensibility.DATABASE.getCaseSensibility());
-        PatternMatcher userPattern = PatternMatcher.createMysqlPattern(user, CaseSensibility.USER.getCaseSensibility());
+        PatternMatcher dbPattern = PatternMatcher.createFlatPattern(
+                db, CaseSensibility.DATABASE.getCaseSensibility(), db.equals(ANY_DB));
+        PatternMatcher userPattern = PatternMatcher.createFlatPattern(user, CaseSensibility.USER.getCaseSensibility());
 
-        PatternMatcher tblPattern = PatternMatcher.createMysqlPattern(tbl.equals(ANY_TBL) ? "%" : tbl,
-                                                                      CaseSensibility.TABLE.getCaseSensibility());
+        PatternMatcher tblPattern = PatternMatcher.createFlatPattern(
+                tbl, CaseSensibility.TABLE.getCaseSensibility(), tbl.equals(ANY_TBL));
 
         if (privs.containsNodePriv() || privs.containsResourcePriv()) {
             throw new AnalysisException("Table privilege can not contains global or resource privileges: " + privs);
diff --git a/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/PrivEntryTest.java b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/PrivEntryTest.java
new file mode 100644
index 0000000000..71f6990191
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/PrivEntryTest.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.doris.mysql.privilege;
+
+import org.apache.doris.analysis.UserIdentity;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PrivEntryTest {
+    @Test
+    public void testNameWithUnderscores() throws Exception {
+        TablePrivEntry tablePrivEntry = TablePrivEntry.create(
+                "127.%", "db_db1", "user1", "tbl_tbl1", false,
+                PrivBitSet.of(PaloPrivilege.SELECT_PRIV, PaloPrivilege.DROP_PRIV));
+        // pattern match
+        Assert.assertFalse(tablePrivEntry.getDbPattern().match("db-db1"));
+        Assert.assertFalse(tablePrivEntry.getTblPattern().match("tbl-tbl1"));
+        // create TablePrivTable
+        TablePrivTable tablePrivTable = new TablePrivTable();
+        tablePrivTable.addEntry(tablePrivEntry, false, false);
+        UserIdentity userIdentity = new UserIdentity("user1", "127.%", false);
+        userIdentity.setIsAnalyzed();
+
+        PrivBitSet privs1 = PrivBitSet.of();
+        tablePrivTable.getPrivs(userIdentity, "db#db1", "tbl#tbl1", privs1);
+        Assert.assertFalse(PaloPrivilege.satisfy(privs1, PrivPredicate.DROP));
+
+        PrivBitSet privs2 = PrivBitSet.of();
+        tablePrivTable.getPrivs(userIdentity, "db_db1", "tbl_tbl1", privs2);
+        Assert.assertTrue(PaloPrivilege.satisfy(privs2, PrivPredicate.DROP));
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org