From fc67929e349ed336d37b9fe766de2b66df02d981 Mon Sep 17 00:00:00 2001 From: zhangdong <493738387@qq.com> Date: Mon, 24 Jul 2023 22:04:37 +0800 Subject: [PATCH] [improvement](catalog) optimize ldap and support more character in user and table name (#21968) - common name support `-` ,reason: MySQL's db name support `-` - table name support `-` - username support `.`,reason:LDAP's username support `.` - ldap doc - ldap support rbac --- .../docs/admin-manual/privilege-ldap/ldap.md | 47 +++- .../docs/admin-manual/privilege-ldap/ldap.md | 47 +++- .../org/apache/doris/common/FeNameFormat.java | 20 +- .../org/apache/doris/ldap/LdapManager.java | 49 ++-- .../apache/doris/ldap/LdapPrivsChecker.java | 160 ------------- .../org/apache/doris/ldap/LdapUserInfo.java | 21 +- .../apache/doris/mysql/privilege/Auth.java | 147 +++++------- .../apache/doris/common/FeNameFormatTest.java | 9 +- .../doris/ldap/LdapAuthenticateTest.java | 5 +- .../apache/doris/ldap/LdapManagerTest.java | 2 +- .../doris/ldap/LdapPrivsCheckerTest.java | 218 ------------------ 11 files changed, 218 insertions(+), 507 deletions(-) delete mode 100644 fe/fe-core/src/main/java/org/apache/doris/ldap/LdapPrivsChecker.java delete mode 100644 fe/fe-core/src/test/java/org/apache/doris/ldap/LdapPrivsCheckerTest.java diff --git a/docs/en/docs/admin-manual/privilege-ldap/ldap.md b/docs/en/docs/admin-manual/privilege-ldap/ldap.md index 9cbe243c17c1e6..68e0ba264bc052 100644 --- a/docs/en/docs/admin-manual/privilege-ldap/ldap.md +++ b/docs/en/docs/admin-manual/privilege-ldap/ldap.md @@ -38,6 +38,30 @@ LDAP group authorization, is to map the group in LDAP to the Role in Doris, if t * Privilege: Permissions act on nodes, databases or tables. Different permissions represent different permission to operate. * Role: Doris can create custom named roles. A role can be thought of as a collection of permissions. +## LDAP related concepts + +In LDAP, data is organized in a tree structure. + +### Example (the following introduction will be expanded based on this example) +- dc=example,dc=com +- ou = ou1 + - cn = group1 + - cn = user1 +- ou = ou2 + - cn = group2 + - cn = user2 +- cn = user3 + +### Explanation of LDAP Terms +- dc(Domain Component): It can be understood as the domain name of an organization, serving as the root node of a tree +- dn(Distinguished Name): Equivalent to a unique name, for example, the dn of user1 is cn=user1,ou=ou1,dc=example,dc=com the dn of user2 is cn=user2,cn=group2,ou=ou2,dc=example,dc=com +- rdn(Relative Distinguished Name): As part of dn, the four rdns of user1 are cn=user1 ou=ou1 dc=example and dc=com +- ou(Organization Unit): It can be understood as a sub organization, where users can be placed in ou or directly in the example.com domain +- cn(common name):name +- group: Group, which can be understood as the role of Doris +- user: User, equivalent to Doris' user +- objectClass:It can be understood as the type of data in each row, such as how to distinguish whether group1 is a group or a user. Each type of data requires different attributes below, such as CN and member (user list) for group, CN, password, uid, etc. for user + ## Enable LDAP Authentication ### Server-side Configuration @@ -57,7 +81,7 @@ You need to configure the LDAP basic information in the fe/conf/ldap.conf file, LDAP administrator account "Distinguished Name". When a user logs into Doris using LDAP authentication, Doris will bind the administrator account to search for user information in LDAP. * ldap_user_basedn = ou=people,dc=domain,dc=com - Doris base dn when searching for user information in LDAP. + Doris base dn when searching for user information in LDAP,For example, only user2 in the above example is allowed to log in to Doris, which is configured as ou=ou2, dc=example, dc=com. If user1, user2, and user3 in the above example are allowed to log in to Doris, which is configured as dc=example, dc=com * ldap_user_filter = (&(uid={login})) @@ -69,7 +93,7 @@ You need to configure the LDAP basic information in the fe/conf/ldap.conf file, ldap_user_filter = (&(mail={login}@baidu.com))。 * ldap_group_basedn = ou=group,dc=domain,dc=com - base dn when Doris searches for group information in LDAP. if this item is not configured, LDAP group authorization will not be enabled. + base dn when Doris searches for group information in LDAP. if this item is not configured, LDAP group authorization will not be enabled. Same as ldap_ User_ Similar to basedn, it limits the scope of Doris searching for groups. #### Set the LDAP administrator password: After configuring the ldap.conf file, start fe, log in to Doris with the root or admin account, and execute sql: @@ -97,7 +121,7 @@ Client-side LDAP authentication requires the mysql client-side explicit authenti LDAP password authentication and group authorization are complementary to Doris password authentication and authorization. Enabling LDAP functionality does not completely replace Doris password authentication and authorization, but coexists with Doris password authentication and authorization. ### LDAP authentication login details -When LDAP is enabled, users have the following in Doris and DLAP: +When LDAP is enabled, users have the following in Doris and LDAP: |LDAP User|Doris User|Password|Login Status|Login to Doris users| |--|--|--|--|--| @@ -168,9 +192,26 @@ Then the group name is doris_rd. If jack also belongs to the LDAP groups doris_qa, doris_pm; Doris exists roles: doris_rd, doris_qa, doris_pm, after logging in using LDAP authentication, the user will not only have the original permissions of the account, but will also get the roles doris_rd, doris_qa and doris _pm privileges. +>Attention: +> +>The group to which user belongs is not related to the organizational structure of the LDAP tree, and user2 in the example section may not necessarily belong to group2 +> If you want user2 to belong to group2, you need to add user2 to the member attribute of group2 + ### LDAP information cache To avoid frequent access to LDAP service, Doris will cache LDAP information into memory, you can specify the cache time for LDAP users through the `ldap_user_cache_timeout_s` configuration item in ldap.conf, the default is 12 hours; after modifying the information in LDAP service or modifying the After modifying the information in the LDAP service or modifying the Role permissions of the LDAP user group, the cache may not take effect in time because of the cache, so you can refresh the cache with the refresh ldap statement, see [REFRESH-LDAP](... /... /sql-manual/sql-reference/Utility-Statements/REFRESH-LDAP.md). ## Limitations of LDAP authentication * The current LDAP feature of Doris only supports plaintext password authentication, that is, when a user logs in, the password is transmitted in plaintext between client and fe and between fe and LDAP service. + +## FAQ + +- How to determine which roles an LDAP user has in Doris? + + Log in to Doris using an LDAP user, ` show grants` Can view which roles the current user has. Among them, ldapDefaultRole is the default role that every ldap user has in Doris. +- How to troubleshoot when the roles of LDAP users in Doris are less than expected? + + 1. Through 'show roles` Check if the expected role exists in Doris. If it does not exist, you need to use the 'CREATE ROLE role'_ Name` Create a character. + 2. Check if the expected group is in 'ldap'_ Group_ Based on the corresponding organizational structure. + 3. Check if the expected group contains the member attribute. + 4. Check if the member attribute of the expected group contains the current user. \ No newline at end of file diff --git a/docs/zh-CN/docs/admin-manual/privilege-ldap/ldap.md b/docs/zh-CN/docs/admin-manual/privilege-ldap/ldap.md index cf4ffe8508feb1..8c07d934055261 100644 --- a/docs/zh-CN/docs/admin-manual/privilege-ldap/ldap.md +++ b/docs/zh-CN/docs/admin-manual/privilege-ldap/ldap.md @@ -38,6 +38,30 @@ LDAP组授权是将LDAP中的group映射到Doris中的Role,如果用户在LDAP - 权限 Privilege:权限作用的对象是节点、数据库或表。不同的权限代表不同的操作许可。 - 角色 Role:Doris可以创建自定义命名的角色。角色可以被看做是一组权限的集合。 +## LDAP相关概念 + +在LDAP中,数据是按照树型结构组织的。 + +### 示例(下文的介绍都将根据这个例子进行展开) + - dc=example,dc=com + - ou = ou1 + - cn = group1 + - cn = user1 + - ou = ou2 + - cn = group2 + - cn = user2 + - cn = user3 + +### LDAP名词解释 +- dc(Domain Component): 可以理解为一个组织的域名,作为树的根结点 +- dn(Distinguished Name): 相当于唯一名称,例如user1的dn为 cn=user1,ou=ou1,dc=example,dc=com user2的dn为 cn=user2,cn=group2,ou=ou2,dc=example,dc=com +- rdn(Relative Distinguished Name): dn的一部分,user1的四个rdn为cn=user1 ou=ou1 dc=example和dc=com +- ou(Organization Unit): 可以理解为子组织,user可以放在ou中,也可以直接放在example.com域中 +- cn(common name):名字 +- group: 组,可以理解为doris的角色 +- user: 用户,和doris的用户等价 +- objectClass:可以理解为每行数据的类型,比如怎么区分group1是group还是user,每种类型的数据下面要求有不同的属性,比如group要求有cn和member(user列表),user要求有cn,password,uid等 + ## 启用LDAP认证 ### server端配置 @@ -59,7 +83,7 @@ LDAP组授权是将LDAP中的group映射到Doris中的Role,如果用户在LDAP LDAP管理员账户“Distinguished Name”。当用户使用LDAP验证登录Doris时,Doris会绑定该管理员账户在LDAP中搜索用户信息。 - ldap_user_basedn = ou=people,dc=domain,dc=com - Doris在LDAP中搜索用户信息时的base dn。 + Doris在LDAP中搜索用户信息时的base dn,例如只允许上例中的user2登陆doris,此处配置为ou=ou2,dc=example,dc=com 如果允许上例中的user1,user2,user3都能登陆doris,此处配置为dc=example,dc=com - ldap_user_filter = (&(uid={login})) @@ -71,7 +95,7 @@ LDAP组授权是将LDAP中的group映射到Doris中的Role,如果用户在LDAP ldap_user_filter = (&(mail={login}@baidu.com))。 - ldap_group_basedn = ou=group,dc=domain,dc=com - Doris在LDAP中搜索组信息时的base dn。如果不配置该项,将不启用LDAP组授权。 + Doris在LDAP中搜索组信息时的base dn。如果不配置该项,将不启用LDAP组授权。同ldap_user_basedn类似,限制doris搜索group时的范围。 #### 设置LDAP管理员密码: @@ -107,7 +131,7 @@ LDAP密码验证和组授权是Doris密码验证和授权的补充,开启LDAP ### LDAP验证登录详解 -开启LDAP后,用户在Doris和DLAP中存在以下几种情况: +开启LDAP后,用户在Doris和LDAP中存在以下几种情况: | LDAP用户 | Doris用户 | 密码 | 登录情况 | 登录Doris的用户 | | -------- | --------- | --------- | -------- | --------------- | @@ -185,9 +209,26 @@ member: uid=jack,ou=aidp,dc=domain,dc=com 假如jack还属于LDAP组doris_qa、doris_pm;Doris存在role:doris_rd、doris_qa、doris_pm,在使用LDAP验证登录后,用户不但具有该账户原有的权限,还将获得role doris_rd、doris_qa和doris_pm的权限。 +>注意: +> +>user属于哪个group和LDAP树的组织结构无关,示例部分的user2并不一定属于group2 +> 若想让user2属于group2,需要在group2的member属性中添加user2 + ### LDAP信息缓存 为了避免频繁访问LDAP服务,Doris会将LDAP信息缓存到内存中,可以通过ldap.conf中的`ldap_user_cache_timeout_s`配置项指定LDAP用户的缓存时间,默认为12小时;在修改了LDAP服务中的信息或者修改了Doris中LDAP用户组对应的Role权限后,可能因为缓存而没有及时生效,可以通过refresh ldap语句刷新缓存,详细查看[REFRESH-LDAP](../../sql-manual/sql-reference/Utility-Statements/REFRESH-LDAP.md)。 ## LDAP验证的局限 - 目前Doris的LDAP功能只支持明文密码验证,即用户登录时,密码在client与fe之间、fe与LDAP服务之间以明文的形式传输。 + +## 常见问题 + +- 怎么判断LDAP用户在doris中有哪些角色? + + 使用LDAP用户在doris中登陆,`show grants;`能查看当前用户有哪些角色。其中ldapDefaultRole是每个ldap用户在doris中都有的默认角色。 +- LDAP用户在doris中的角色比预期少怎么排查? + + 1. 通过`show roles;`查看预期的角色在doris中是否存在,如果不存在,需要通过` CREATE ROLE rol_name;`创建角色。 + 2. 检查预期的group是否在`ldap_group_basedn`对应的组织结构下。 + 3. 检查预期group是否包含member属性。 + 4. 检查预期group的member属性是否包含当前用户。 diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/FeNameFormat.java b/fe/fe-core/src/main/java/org/apache/doris/common/FeNameFormat.java index 94140e1caea66e..970344f8e6251e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/FeNameFormat.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/FeNameFormat.java @@ -29,13 +29,15 @@ public class FeNameFormat { private static final String LABEL_REGEX = "^[-_A-Za-z0-9:]{1,128}$"; - private static final String COMMON_NAME_REGEX = "^[a-zA-Z][a-zA-Z0-9_]{0,63}$"; - private static final String TABLE_NAME_REGEX = "^[a-zA-Z][a-zA-Z0-9_]*$"; + private static final String COMMON_NAME_REGEX = "^[a-zA-Z][a-zA-Z0-9-_]{0,63}$"; + private static final String TABLE_NAME_REGEX = "^[a-zA-Z][a-zA-Z0-9-_]*$"; + private static final String USER_NAME_REGEX = "^[a-zA-Z][a-zA-Z0-9.-_]*$"; private static final String COLUMN_NAME_REGEX = "^[_a-zA-Z@0-9\\s<>/][.a-zA-Z0-9_+-/> getUserRoles(String fullName) { LdapUserInfo info = getUserInfo(fullName); - return !Objects.isNull(info) && info.isExists() ? info.getPaloRole() : new Role(LDAP_GROUPS_PRIVS_NAME); + return info == null ? Collections.emptySet() : info.getPaloRoles(); } private boolean checkParam(String fullName) { @@ -142,7 +149,7 @@ private LdapUserInfo getUserInfoAndUpdateCache(String fulName) throws DdlExcepti } checkTimeoutCleanCache(); - LdapUserInfo ldapUserInfo = new LdapUserInfo(fulName, false, "", getLdapGroupsPrivs(userName, cluster)); + LdapUserInfo ldapUserInfo = new LdapUserInfo(fulName, false, "", getLdapGroupsRoles(userName, cluster)); writeLock(); try { ldapUserInfoCache.put(ldapUserInfo.getUserName(), ldapUserInfo); @@ -198,26 +205,24 @@ private LdapUserInfo getUserInfoFromCache(String fullName) { /** * Step1: get ldap groups from ldap server; * Step2: get roles by ldap groups; - * Step3: merge the roles; + * Step3: generate default role; */ - private Role getLdapGroupsPrivs(String userName, String clusterName) throws DdlException { + private Set getLdapGroupsRoles(String userName, String clusterName) throws DdlException { //get user ldap group. the ldap group name should be the same as the doris role name List ldapGroups = ldapClient.getGroups(userName); - List rolesNames = Lists.newArrayList(); + Set roles = Sets.newHashSet(); for (String group : ldapGroups) { String qualifiedRole = ClusterNamespace.getFullName(clusterName, group); if (Env.getCurrentEnv().getAuth().doesRoleExist(qualifiedRole)) { - rolesNames.add(qualifiedRole); + roles.add(Env.getCurrentEnv().getAuth().getRoleByName(qualifiedRole)); } } - LOG.debug("get user:{} ldap groups:{} and doris roles:{}", userName, ldapGroups, rolesNames); + LOG.debug("get user:{} ldap groups:{} and doris roles:{}", userName, ldapGroups, roles); - Role ldapGroupsPrivs = new Role(LDAP_GROUPS_PRIVS_NAME); - LdapPrivsChecker.grantDefaultPrivToTempUser(ldapGroupsPrivs, clusterName); - if (!rolesNames.isEmpty()) { - Env.getCurrentEnv().getAuth().mergeRolesNoCheckName(rolesNames, ldapGroupsPrivs); - } - return ldapGroupsPrivs; + Role ldapGroupsPrivs = new Role(LDAP_DEFAULT_ROLE); + grantDefaultPrivToTempUser(ldapGroupsPrivs, clusterName); + roles.add(ldapGroupsPrivs); + return roles; } public void refresh(boolean isAll, String fullName) { @@ -235,4 +240,16 @@ public void refresh(boolean isAll, String fullName) { writeUnlock(); } } + + // Temporary user has information_schema 'Select_priv' priv by default. + public static void grantDefaultPrivToTempUser(Role role, String clusterName) throws DdlException { + TablePattern tblPattern = new TablePattern(InfoSchemaDb.DATABASE_NAME, "*"); + try { + tblPattern.analyze(clusterName); + } catch (AnalysisException e) { + LOG.warn("should not happen.", e); + } + Role newRole = new Role(role.getRoleName(), tblPattern, PrivBitSet.of(Privilege.SELECT_PRIV)); + role.merge(newRole); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/ldap/LdapPrivsChecker.java b/fe/fe-core/src/main/java/org/apache/doris/ldap/LdapPrivsChecker.java deleted file mode 100644 index e86d335864c558..00000000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/ldap/LdapPrivsChecker.java +++ /dev/null @@ -1,160 +0,0 @@ -// 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.ldap; - -import org.apache.doris.analysis.ResourcePattern; -import org.apache.doris.analysis.TablePattern; -import org.apache.doris.analysis.UserIdentity; -import org.apache.doris.catalog.Env; -import org.apache.doris.catalog.InfoSchemaDb; -import org.apache.doris.common.AnalysisException; -import org.apache.doris.common.DdlException; -import org.apache.doris.common.LdapConfig; -import org.apache.doris.mysql.privilege.Auth; -import org.apache.doris.mysql.privilege.Auth.PrivLevel; -import org.apache.doris.mysql.privilege.PrivBitSet; -import org.apache.doris.mysql.privilege.PrivPredicate; -import org.apache.doris.mysql.privilege.Privilege; -import org.apache.doris.mysql.privilege.Role; - -import com.google.common.collect.Maps; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.Map; - -/** - * This class is used for checking current user LDAP group privileges. - */ -public class LdapPrivsChecker { - private static final Logger LOG = LogManager.getLogger(LdapPrivsChecker.class); - - public static boolean hasGlobalPrivFromLdap(UserIdentity currentUser, PrivPredicate wanted) { - return hasLdapPrivs(currentUser) && getUserLdapPrivs(currentUser.getQualifiedUser()).checkGlobalPriv(wanted); - } - - public static boolean hasCatalogPrivFromLdap(UserIdentity currentUser, String ctl, PrivPredicate wanted) { - return hasLdapPrivs(currentUser) && getUserLdapPrivs(currentUser.getQualifiedUser()).checkCtlPriv(ctl, wanted); - } - - public static boolean hasDbPrivFromLdap(UserIdentity currentUser, String ctl, String db, PrivPredicate wanted) { - return hasLdapPrivs(currentUser) && getUserLdapPrivs(currentUser.getQualifiedUser()).checkDbPriv(ctl, db, - wanted); - } - - public static boolean hasTblPrivFromLdap(UserIdentity currentUser, String ctl, String db, String tbl, - PrivPredicate wanted) { - return hasLdapPrivs(currentUser) && getUserLdapPrivs(currentUser.getQualifiedUser()).checkTblPriv(ctl, db, tbl, - wanted); - } - - public static boolean checkHasPriv(UserIdentity currentUser, PrivPredicate priv, PrivLevel[] levels) { - return hasLdapPrivs(currentUser) && getUserLdapPrivs(currentUser.getQualifiedUser()).checkHasPriv(priv, levels); - } - - public static boolean hasResourcePrivFromLdap(UserIdentity currentUser, String resourceName, PrivPredicate wanted) { - return hasLdapPrivs(currentUser) && getUserLdapPrivs(currentUser.getQualifiedUser()).checkResourcePriv( - resourceName, wanted); - } - - public static boolean hasWorkloadGroupPrivFromLdap(UserIdentity currentUser, String workloadGroupName, - PrivPredicate wanted) { - return hasLdapPrivs(currentUser) && getUserLdapPrivs(currentUser.getQualifiedUser()).checkWorkloadGroupPriv( - workloadGroupName, wanted); - } - - public static PrivBitSet getResourcePrivFromLdap(UserIdentity currentUser, String resourceName) { - PrivBitSet savedPrivs = PrivBitSet.of(); - if (hasLdapPrivs(currentUser)) { - getUserLdapPrivs(currentUser.getQualifiedUser()).getResourcePrivTable().getPrivs(resourceName, savedPrivs); - } - return savedPrivs; - } - - public static PrivBitSet getWorkloadGroupPrivFromLdap(UserIdentity currentUser, String workloadGroupName) { - PrivBitSet savedPrivs = PrivBitSet.of(); - if (hasLdapPrivs(currentUser)) { - getUserLdapPrivs(currentUser.getQualifiedUser()).getWorkloadGroupPrivTable() - .getPrivs(workloadGroupName, savedPrivs); - } - return savedPrivs; - } - - public static boolean hasLdapPrivs(UserIdentity userIdent) { - return LdapConfig.ldap_authentication_enabled && Env.getCurrentEnv().getAuth().getLdapManager() - .doesUserExist(userIdent.getQualifiedUser()); - } - - public static Map getLdapAllDbPrivs(UserIdentity userIdentity) { - Map ldapDbPrivs = Maps.newConcurrentMap(); - if (!hasLdapPrivs(userIdentity)) { - return ldapDbPrivs; - } - for (Map.Entry entry : getUserLdapPrivs(userIdentity.getQualifiedUser()) - .getTblPatternToPrivs().entrySet()) { - if (entry.getKey().getPrivLevel().equals(Auth.PrivLevel.DATABASE)) { - ldapDbPrivs.put(entry.getKey(), entry.getValue()); - } - } - return ldapDbPrivs; - } - - public static Map getLdapAllTblPrivs(UserIdentity userIdentity) { - Map ldapTblPrivs = Maps.newConcurrentMap(); - if (!hasLdapPrivs(userIdentity)) { - return ldapTblPrivs; - } - for (Map.Entry entry : getUserLdapPrivs(userIdentity.getQualifiedUser()) - .getTblPatternToPrivs().entrySet()) { - if (entry.getKey().getPrivLevel().equals(Auth.PrivLevel.TABLE)) { - ldapTblPrivs.put(entry.getKey(), entry.getValue()); - } - } - return ldapTblPrivs; - } - - public static Map getLdapAllResourcePrivs(UserIdentity userIdentity) { - Map ldapResourcePrivs = Maps.newConcurrentMap(); - if (!hasLdapPrivs(userIdentity)) { - return ldapResourcePrivs; - } - for (Map.Entry entry : getUserLdapPrivs(userIdentity.getQualifiedUser()) - .getResourcePatternToPrivs().entrySet()) { - if (entry.getKey().getPrivLevel().equals(Auth.PrivLevel.RESOURCE)) { - ldapResourcePrivs.put(entry.getKey(), entry.getValue()); - } - } - return ldapResourcePrivs; - } - - private static Role getUserLdapPrivs(String fullName) { - return Env.getCurrentEnv().getAuth().getLdapManager().getUserRole(fullName); - } - - // Temporary user has information_schema 'Select_priv' priv by default. - public static void grantDefaultPrivToTempUser(Role role, String clusterName) throws DdlException { - TablePattern tblPattern = new TablePattern(InfoSchemaDb.DATABASE_NAME, "*"); - try { - tblPattern.analyze(clusterName); - } catch (AnalysisException e) { - LOG.warn("should not happen.", e); - } - Role newRole = new Role(role.getRoleName(), tblPattern, PrivBitSet.of(Privilege.SELECT_PRIV)); - role.merge(newRole); - } -} diff --git a/fe/fe-core/src/main/java/org/apache/doris/ldap/LdapUserInfo.java b/fe/fe-core/src/main/java/org/apache/doris/ldap/LdapUserInfo.java index 5ead0095e43a5c..d81ea9fb0d951d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/ldap/LdapUserInfo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/ldap/LdapUserInfo.java @@ -21,26 +21,27 @@ import org.apache.doris.mysql.privilege.Role; import java.util.Objects; +import java.util.Set; /** * Used to cache LDAP information of user, such as password and privileges. */ public class LdapUserInfo { - public LdapUserInfo(String userName, boolean isSetPasswd, String passwd, Role role) { + public LdapUserInfo(String userName, boolean isSetPasswd, String passwd, Set roles) { this.userName = userName; this.isExists = true; this.isSetPasswd = isSetPasswd; this.passwd = passwd; - this.role = role; + this.roles = roles; this.lastTimeStamp = System.currentTimeMillis(); } - private LdapUserInfo(String userName, boolean isSetPasswd, String passwd, Role role, long lastTimeStamp) { + private LdapUserInfo(String userName, boolean isSetPasswd, String passwd, Set roles, long lastTimeStamp) { this.userName = userName; this.isExists = true; this.isSetPasswd = isSetPasswd; this.passwd = passwd; - this.role = role; + this.roles = roles; this.lastTimeStamp = lastTimeStamp; } @@ -49,7 +50,7 @@ public LdapUserInfo(String notExistsUserName) { this.isExists = false; this.isSetPasswd = false; this.passwd = null; - this.role = null; + this.roles = null; this.lastTimeStamp = System.currentTimeMillis(); } @@ -61,7 +62,7 @@ public LdapUserInfo(String notExistsUserName) { private final String passwd; - private final Role role; + private final Set roles; private final long lastTimeStamp; @@ -78,8 +79,8 @@ String getPasswd() { return passwd; } - public Role getPaloRole() { - return role; + public Set getPaloRoles() { + return roles; } public boolean isExists() { @@ -88,10 +89,10 @@ public boolean isExists() { public LdapUserInfo cloneWithPasswd(String passwd) { if (Objects.isNull(passwd)) { - return new LdapUserInfo(userName, isSetPasswd, this.passwd, role, lastTimeStamp); + return new LdapUserInfo(userName, isSetPasswd, this.passwd, roles, lastTimeStamp); } - return new LdapUserInfo(userName, true, passwd, role, lastTimeStamp); + return new LdapUserInfo(userName, true, passwd, roles, lastTimeStamp); } // Return true if LdapUserInfo is exceeded the time limit; diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java index a2ab5a7b78e1f2..274ccb56bf6f7f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java @@ -53,7 +53,6 @@ import org.apache.doris.common.io.Writable; import org.apache.doris.datasource.InternalCatalog; import org.apache.doris.ldap.LdapManager; -import org.apache.doris.ldap.LdapPrivsChecker; import org.apache.doris.ldap.LdapUserInfo; import org.apache.doris.load.DppConfig; import org.apache.doris.persist.AlterUserOperationLog; @@ -68,6 +67,7 @@ import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import org.apache.commons.collections.CollectionUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -167,6 +167,10 @@ public void mergeRolesNoCheckName(List roles, Role savedRole) throws Ddl } } + public Role getRoleByName(String roleName) { + return roleManager.getRole(roleName); + } + /* * check password, if matched, save the userIdentity in matched entry. * the following auth checking should use userIdentity saved in currentUser. @@ -229,20 +233,32 @@ public void checkPlainPassword(String remoteUser, String remoteHost, String remo } } + public Set getRolesByUserWithLdap(UserIdentity userIdentity) { + Set roles = Sets.newHashSet(); + Set roleNames = userRoleManager.getRolesByUser(userIdentity); + for (String roleName : roleNames) { + roles.add(roleManager.getRole(roleName)); + } + if (isLdapAuthEnabled()) { + Set ldapRoles = ldapManager.getUserRoles(userIdentity.getQualifiedUser()); + if (!CollectionUtils.isEmpty(ldapRoles)) { + roles.addAll(ldapRoles); + } + } + return roles; + } + public List getUserIdentityForLdap(String remoteUser, String remoteHost) { return userManager.getUserIdentityUncheckPasswd(remoteUser, remoteHost); } // ==== Global ==== public boolean checkGlobalPriv(UserIdentity currentUser, PrivPredicate wanted) { - if (isLdapAuthEnabled() && LdapPrivsChecker.hasGlobalPrivFromLdap(currentUser, wanted)) { - return true; - } readLock(); try { - Set roles = userRoleManager.getRolesByUser(currentUser); - for (String roleName : roles) { - if (roleManager.getRole(roleName).checkGlobalPriv(wanted)) { + Set roles = getRolesByUserWithLdap(currentUser); + for (Role role : roles) { + if (role.checkGlobalPriv(wanted)) { return true; } } @@ -254,20 +270,16 @@ public boolean checkGlobalPriv(UserIdentity currentUser, PrivPredicate wanted) { // ==== Catalog ==== public boolean checkCtlPriv(UserIdentity currentUser, String ctl, PrivPredicate wanted) { - if (isLdapAuthEnabled() && (LdapPrivsChecker.hasCatalogPrivFromLdap(currentUser, ctl, wanted))) { - return true; - } if (wanted.getPrivs().containsNodePriv()) { LOG.debug("should not check NODE priv in catalog level. user: {}, catalog: {}", currentUser, ctl); return false; } - //ldap(before change to rbac) readLock(); try { - Set roles = userRoleManager.getRolesByUser(currentUser); - for (String roleName : roles) { - if (roleManager.getRole(roleName).checkCtlPriv(ctl, wanted)) { + Set roles = getRolesByUserWithLdap(currentUser); + for (Role role : roles) { + if (role.checkCtlPriv(ctl, wanted)) { return true; } } @@ -279,9 +291,6 @@ public boolean checkCtlPriv(UserIdentity currentUser, String ctl, PrivPredicate // ==== Database ==== public boolean checkDbPriv(UserIdentity currentUser, String ctl, String db, PrivPredicate wanted) { - if (isLdapAuthEnabled() && LdapPrivsChecker.hasDbPrivFromLdap(currentUser, ctl, db, wanted)) { - return true; - } if (wanted.getPrivs().containsNodePriv()) { LOG.debug("should not check NODE priv in Database level. user: {}, db: {}", currentUser, db); @@ -289,9 +298,9 @@ public boolean checkDbPriv(UserIdentity currentUser, String ctl, String db, Priv } readLock(); try { - Set roles = userRoleManager.getRolesByUser(currentUser); - for (String roleName : roles) { - if (roleManager.getRole(roleName).checkDbPriv(ctl, db, wanted)) { + Set roles = getRolesByUserWithLdap(currentUser); + for (Role role : roles) { + if (role.checkDbPriv(ctl, db, wanted)) { return true; } } @@ -304,18 +313,15 @@ public boolean checkDbPriv(UserIdentity currentUser, String ctl, String db, Priv // ==== Table ==== public boolean checkTblPriv(UserIdentity currentUser, String ctl, String db, String tbl, PrivPredicate wanted) { - if (isLdapAuthEnabled() && LdapPrivsChecker.hasTblPrivFromLdap(currentUser, ctl, db, tbl, wanted)) { - return true; - } if (wanted.getPrivs().containsNodePriv()) { LOG.debug("should check NODE priv in GLOBAL level. user: {}, db: {}, tbl: {}", currentUser, db, tbl); return false; } readLock(); try { - Set roles = userRoleManager.getRolesByUser(currentUser); - for (String roleName : roles) { - if (roleManager.getRole(roleName).checkTblPriv(ctl, db, tbl, wanted)) { + Set roles = getRolesByUserWithLdap(currentUser); + for (Role role : roles) { + if (role.checkTblPriv(ctl, db, tbl, wanted)) { return true; } } @@ -340,14 +346,11 @@ public void checkColsPriv(UserIdentity currentUser, String ctl, String db, Strin // ==== Resource ==== public boolean checkResourcePriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted) { - if (isLdapAuthEnabled() && LdapPrivsChecker.hasResourcePrivFromLdap(currentUser, resourceName, wanted)) { - return true; - } readLock(); try { - Set roles = userRoleManager.getRolesByUser(currentUser); - for (String roleName : roles) { - if (roleManager.getRole(roleName).checkResourcePriv(resourceName, wanted)) { + Set roles = getRolesByUserWithLdap(currentUser); + for (Role role : roles) { + if (role.checkResourcePriv(resourceName, wanted)) { return true; } } @@ -359,15 +362,11 @@ public boolean checkResourcePriv(UserIdentity currentUser, String resourceName, // ==== Workload Group ==== public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted) { - if (isLdapAuthEnabled() && LdapPrivsChecker.hasWorkloadGroupPrivFromLdap(currentUser, workloadGroupName, - wanted)) { - return true; - } readLock(); try { - Set roles = userRoleManager.getRolesByUser(currentUser); - for (String roleName : roles) { - if (roleManager.getRole(roleName).checkWorkloadGroupPriv(workloadGroupName, wanted)) { + Set roles = getRolesByUserWithLdap(currentUser); + for (Role role : roles) { + if (role.checkWorkloadGroupPriv(workloadGroupName, wanted)) { return true; } } @@ -383,14 +382,11 @@ public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadG * This method will check the given privilege levels */ public boolean checkHasPriv(ConnectContext ctx, PrivPredicate priv, PrivLevel... levels) { - if (isLdapAuthEnabled() && LdapPrivsChecker.checkHasPriv(ctx.getCurrentUserIdentity(), priv, levels)) { - return true; - } readLock(); try { - Set roles = userRoleManager.getRolesByUser(ctx.getCurrentUserIdentity()); - for (String roleName : roles) { - if (roleManager.getRole(roleName).checkHasPriv(priv, levels)) { + Set roles = getRolesByUserWithLdap(ctx.getCurrentUserIdentity()); + for (Role role : roles) { + if (role.checkHasPriv(priv, levels)) { return true; } } @@ -1103,7 +1099,8 @@ private void getUserAuthInfo(List> userAuthInfos, UserIdentity user // ============== Password ============== userAuthInfo.add(ldapUserInfo.isSetPasswd() ? "Yes" : "No"); // ============== Roles ============== - userAuthInfo.add(ldapUserInfo.getPaloRole().getRoleName()); + userAuthInfo.add(ldapUserInfo.getPaloRoles().stream().map(role -> role.getRoleName()) + .collect(Collectors.joining(","))); } else { User user = userManager.getUserByUserIdentity(userIdent); // ============== Password ============== @@ -1163,7 +1160,6 @@ private void getUserAuthInfo(List> userAuthInfos, UserIdentity user for (PrivEntry entry : getUserResourcePrivTable(userIdent).entries) { ResourcePrivEntry rEntry = (ResourcePrivEntry) entry; PrivBitSet savedPrivs = rEntry.getPrivSet().copy(); - savedPrivs.or(LdapPrivsChecker.getResourcePrivFromLdap(userIdent, rEntry.getOrigResource())); resourcePrivs.add(rEntry.getOrigResource() + ": " + savedPrivs.toString()); } @@ -1178,8 +1174,6 @@ private void getUserAuthInfo(List> userAuthInfos, UserIdentity user for (PrivEntry entry : getUserWorkloadGroupPrivTable(userIdent).entries) { WorkloadGroupPrivEntry workloadGroupPrivEntry = (WorkloadGroupPrivEntry) entry; PrivBitSet savedPrivs = workloadGroupPrivEntry.getPrivSet().copy(); - savedPrivs.or(LdapPrivsChecker.getWorkloadGroupPrivFromLdap(userIdent, - workloadGroupPrivEntry.getOrigWorkloadGroupName())); workloadGroupPrivs.add(workloadGroupPrivEntry.getOrigWorkloadGroupName() + ": " + savedPrivs); } @@ -1194,73 +1188,54 @@ private void getUserAuthInfo(List> userAuthInfos, UserIdentity user private GlobalPrivTable getUserGlobalPrivTable(UserIdentity userIdentity) { GlobalPrivTable table = new GlobalPrivTable(); - Set roles = userRoleManager.getRolesByUser(userIdentity); - for (String roleName : roles) { - table.merge(roleManager.getRole(roleName).getGlobalPrivTable()); - } - if (isLdapAuthEnabled() && ldapManager.doesUserExist(userIdentity.getQualifiedUser())) { - table.merge(ldapManager.getUserRole(userIdentity.getQualifiedUser()).getGlobalPrivTable()); + Set roles = getRolesByUserWithLdap(userIdentity); + for (Role role : roles) { + table.merge(role.getGlobalPrivTable()); } return table; } private CatalogPrivTable getUserCtlPrivTable(UserIdentity userIdentity) { CatalogPrivTable table = new CatalogPrivTable(); - Set roles = userRoleManager.getRolesByUser(userIdentity); - for (String roleName : roles) { - table.merge(roleManager.getRole(roleName).getCatalogPrivTable()); - } - if (isLdapAuthEnabled() && ldapManager.doesUserExist(userIdentity.getQualifiedUser())) { - table.merge(ldapManager.getUserRole(userIdentity.getQualifiedUser()).getCatalogPrivTable()); + Set roles = getRolesByUserWithLdap(userIdentity); + for (Role role : roles) { + table.merge(role.getCatalogPrivTable()); } return table; } private DbPrivTable getUserDbPrivTable(UserIdentity userIdentity) { DbPrivTable table = new DbPrivTable(); - Set roles = userRoleManager.getRolesByUser(userIdentity); - for (String roleName : roles) { - table.merge(roleManager.getRole(roleName).getDbPrivTable()); - } - if (isLdapAuthEnabled() && ldapManager.doesUserExist(userIdentity.getQualifiedUser())) { - table.merge(ldapManager.getUserRole(userIdentity.getQualifiedUser()).getDbPrivTable()); + Set roles = getRolesByUserWithLdap(userIdentity); + for (Role role : roles) { + table.merge(role.getDbPrivTable()); } return table; } private TablePrivTable getUserTblPrivTable(UserIdentity userIdentity) { TablePrivTable table = new TablePrivTable(); - Set roles = userRoleManager.getRolesByUser(userIdentity); - for (String roleName : roles) { - table.merge(roleManager.getRole(roleName).getTablePrivTable()); - } - if (isLdapAuthEnabled() && ldapManager.doesUserExist(userIdentity.getQualifiedUser())) { - table.merge(ldapManager.getUserRole(userIdentity.getQualifiedUser()).getTablePrivTable()); + Set roles = getRolesByUserWithLdap(userIdentity); + for (Role role : roles) { + table.merge(role.getTablePrivTable()); } return table; } private ResourcePrivTable getUserResourcePrivTable(UserIdentity userIdentity) { ResourcePrivTable table = new ResourcePrivTable(); - Set roles = userRoleManager.getRolesByUser(userIdentity); - for (String roleName : roles) { - table.merge(roleManager.getRole(roleName).getResourcePrivTable()); - } - if (isLdapAuthEnabled() && ldapManager.doesUserExist(userIdentity.getQualifiedUser())) { - table.merge(ldapManager.getUserRole(userIdentity.getQualifiedUser()).getResourcePrivTable()); + Set roles = getRolesByUserWithLdap(userIdentity); + for (Role role : roles) { + table.merge(role.getResourcePrivTable()); } return table; } private WorkloadGroupPrivTable getUserWorkloadGroupPrivTable(UserIdentity userIdentity) { WorkloadGroupPrivTable table = new WorkloadGroupPrivTable(); - Set roles = userRoleManager.getRolesByUser(userIdentity); - for (String roleName : roles) { - table.merge(roleManager.getRole(roleName).getWorkloadGroupPrivTable()); - } - if (isLdapAuthEnabled() && ldapManager.doesUserExist(userIdentity.getQualifiedUser())) { - table.merge( - ldapManager.getUserRole(userIdentity.getQualifiedUser()).getWorkloadGroupPrivTable()); + Set roles = getRolesByUserWithLdap(userIdentity); + for (Role role : roles) { + table.merge(role.getWorkloadGroupPrivTable()); } return table; } diff --git a/fe/fe-core/src/test/java/org/apache/doris/common/FeNameFormatTest.java b/fe/fe-core/src/test/java/org/apache/doris/common/FeNameFormatTest.java index bd9777f9153943..5d173172c0d692 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/common/FeNameFormatTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/common/FeNameFormatTest.java @@ -38,18 +38,23 @@ public void testCheckColumnName() { ExceptionChecker.expectThrows(AnalysisException.class, () -> FeNameFormat.checkColumnName("?id_")); ExceptionChecker.expectThrows(AnalysisException.class, () -> FeNameFormat.checkColumnName("#id_")); // length 64 - String tblName = "test_sys_partition_list_basic_test_list_partition_bigint_tb_uniq"; + String tblName = "test_sys_partition_list_basic_test_list_partition_bigint_tb-uniq"; ExceptionChecker.expectThrowsNoException(() -> FeNameFormat.checkTableName(tblName)); // length 70 String largeTblName = "test_sys_partition_list_basic_test_list_partition_bigint_tb_uniq_large"; ExceptionChecker.expectThrows(AnalysisException.class, () -> FeNameFormat.checkTableName(largeTblName)); - // check table name use correct regex, not begin with '-' ExceptionChecker.expectThrows(AnalysisException.class, () -> FeNameFormat.checkTableName("-" + tblName)); + ExceptionChecker.expectThrowsNoException(() -> FeNameFormat.checkUserName("a.b")); + // check user name use correct regex, not begin with '.' + ExceptionChecker.expectThrows(AnalysisException.class, () -> FeNameFormat.checkUserName(".a.b")); + // check common name use correct regex, length 65 ExceptionChecker.expectThrows(AnalysisException.class, () -> FeNameFormat.checkCommonName("fakeType", tblName + "t")); ExceptionChecker.expectThrows(AnalysisException.class, () -> FeNameFormat.checkCommonName("fakeType", "_commonName")); + ExceptionChecker.expectThrowsNoException(() -> FeNameFormat.checkCommonName("fakeType", "common-Name")); + ExceptionChecker.expectThrowsNoException(() -> FeNameFormat.checkCommonName("fakeType", "commonName-")); } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/ldap/LdapAuthenticateTest.java b/fe/fe-core/src/test/java/org/apache/doris/ldap/LdapAuthenticateTest.java index e6856950c74e10..87f2daac4163a4 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/ldap/LdapAuthenticateTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/ldap/LdapAuthenticateTest.java @@ -26,6 +26,7 @@ import org.apache.doris.mysql.privilege.Role; import org.apache.doris.qe.ConnectContext; +import com.google.common.collect.Sets; import mockit.Delegate; import mockit.Expectations; import mockit.Mocked; @@ -46,8 +47,6 @@ public class LdapAuthenticateTest { @Mocked private LdapManager ldapManager; @Mocked - private LdapPrivsChecker ldapPrivsChecker; - @Mocked private Env env; @Mocked private Auth auth; @@ -113,7 +112,7 @@ private void setGetUserInfo(boolean res) { minTimes = 0; result = new Delegate() { LdapUserInfo fakeGetGroups(String user) { - return new LdapUserInfo(anyString, false, "", new Role(anyString)); + return new LdapUserInfo(anyString, false, "", Sets.newHashSet(new Role(anyString))); } }; } else { diff --git a/fe/fe-core/src/test/java/org/apache/doris/ldap/LdapManagerTest.java b/fe/fe-core/src/test/java/org/apache/doris/ldap/LdapManagerTest.java index 8ed4a618d00cc6..45d5c4dac888e3 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/ldap/LdapManagerTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/ldap/LdapManagerTest.java @@ -64,7 +64,7 @@ public void testGetUserInfo() { mockClient(true, true); LdapUserInfo ldapUserInfo = ldapManager.getUserInfo(USER1); Assert.assertNotNull(ldapUserInfo); - String paloRoleString = ldapUserInfo.getPaloRole().toString(); + String paloRoleString = ldapUserInfo.getPaloRoles().toString(); Assert.assertTrue(paloRoleString.contains("information_schema")); Assert.assertTrue(paloRoleString.contains("Select_priv")); diff --git a/fe/fe-core/src/test/java/org/apache/doris/ldap/LdapPrivsCheckerTest.java b/fe/fe-core/src/test/java/org/apache/doris/ldap/LdapPrivsCheckerTest.java deleted file mode 100644 index 54a294c8bdf1d5..00000000000000 --- a/fe/fe-core/src/test/java/org/apache/doris/ldap/LdapPrivsCheckerTest.java +++ /dev/null @@ -1,218 +0,0 @@ -// 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.ldap; - -import org.apache.doris.analysis.ResourcePattern; -import org.apache.doris.analysis.TablePattern; -import org.apache.doris.analysis.UserIdentity; -import org.apache.doris.catalog.Env; -import org.apache.doris.common.AnalysisException; -import org.apache.doris.common.LdapConfig; -import org.apache.doris.datasource.InternalCatalog; -import org.apache.doris.mysql.privilege.Auth; -import org.apache.doris.mysql.privilege.PrivBitSet; -import org.apache.doris.mysql.privilege.PrivPredicate; -import org.apache.doris.mysql.privilege.Privilege; -import org.apache.doris.mysql.privilege.Role; -import org.apache.doris.qe.ConnectContext; -import org.apache.doris.qe.SessionVariable; - -import com.google.common.collect.Lists; -import mockit.Expectations; -import mockit.Mocked; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.util.Map; - -public class LdapPrivsCheckerTest { - private static final String CLUSTER = "default_cluster"; - private static final String INTERNAL = InternalCatalog.INTERNAL_CATALOG_NAME; - private static final String DB = "palodb"; - private static final String TABLE_DB = "tabledb"; - private static final String TABLE1 = "table1"; - private static final String TABLE2 = "table2"; - private static final String RESOURCE1 = "spark_resource"; - private static final String RESOURCE2 = "resource"; - private static final String USER = "default_cluster:zhangsan"; - private static final String IP = "192.168.0.1"; - private UserIdentity userIdent = UserIdentity.createAnalyzedUserIdentWithIp(USER, IP); - - @Mocked - private ConnectContext context; - - @Mocked - private SessionVariable sessionVariable; - - @Mocked - private Env env; - - @Mocked - private Auth auth; - - @Mocked - private LdapManager ldapManager; - - @Before - public void setUp() { - LdapConfig.ldap_authentication_enabled = true; - new Expectations() { - { - ConnectContext.get(); - minTimes = 0; - result = context; - - Env.getCurrentEnv(); - minTimes = 0; - result = env; - - env.getAuth(); - minTimes = 0; - result = auth; - - auth.getLdapManager(); - minTimes = 0; - result = ldapManager; - - Role role = new Role("ldapRole"); - Map tblPatternToPrivs = role.getTblPatternToPrivs(); - - TablePattern global = new TablePattern("ctl1", "*", "*"); - tblPatternToPrivs.put(global, PrivBitSet.of(Privilege.SELECT_PRIV, Privilege.CREATE_PRIV)); - TablePattern db = new TablePattern(INTERNAL, DB, "*"); - tblPatternToPrivs.put(db, PrivBitSet.of(Privilege.SELECT_PRIV, Privilege.LOAD_PRIV)); - TablePattern tbl1 = new TablePattern(INTERNAL, TABLE_DB, TABLE1); - tblPatternToPrivs.put(tbl1, PrivBitSet.of(Privilege.SELECT_PRIV, Privilege.ALTER_PRIV)); - TablePattern tbl2 = new TablePattern(INTERNAL, TABLE_DB, TABLE2); - tblPatternToPrivs.put(tbl2, PrivBitSet.of(Privilege.SELECT_PRIV, Privilege.DROP_PRIV)); - - Map resourcePatternToPrivs = role.getResourcePatternToPrivs(); - ResourcePattern resource1 = new ResourcePattern(RESOURCE1); - resourcePatternToPrivs.put(resource1, PrivBitSet.of(Privilege.USAGE_PRIV)); - ResourcePattern resource2 = new ResourcePattern(RESOURCE1); - resourcePatternToPrivs.put(resource2, PrivBitSet.of(Privilege.USAGE_PRIV)); - Role ldapRole = new Role(role.getRoleName()); - try { - global.analyze(CLUSTER); - db.analyze(CLUSTER); - tbl1.analyze(CLUSTER); - tbl2.analyze(CLUSTER); - resource1.analyze(); - resource2.analyze(); - ldapRole.merge(role); - } catch (Exception e) { - e.printStackTrace(); - } - - UserIdentity userIdentity = UserIdentity.createAnalyzedUserIdentWithIp(USER, IP); - - ldapManager.getUserInfo(userIdentity.getQualifiedUser()); - minTimes = 0; - result = new LdapUserInfo(userIdentity.getQualifiedUser(), false, "", ldapRole); - - ldapManager.doesUserExist(userIdentity.getQualifiedUser()); - minTimes = 0; - result = true; - - ldapManager.getUserRole(USER); - minTimes = 0; - result = ldapRole; - - context.getCurrentUserIdentity(); - minTimes = 0; - result = userIdentity; - - context.getSessionVariable(); - minTimes = 0; - result = sessionVariable; - - auth.getUserIdentityForLdap(USER, IP); - minTimes = 0; - result = Lists.newArrayList(userIdentity); - } - }; - // call the mocked method before replay - // for there is exception in tests: Missing 1 invocation to: org.apache.doris.qe.ConnectContext#get() - ConnectContext.get().getSessionVariable().isEnableUnicodeNameSupport(); - } - - @Test - public void testHasDbPrivFromLdap() { - Assert.assertTrue( - LdapPrivsChecker.hasDbPrivFromLdap(userIdent, INTERNAL, CLUSTER + ":" + DB, PrivPredicate.LOAD)); - Assert.assertFalse( - LdapPrivsChecker.hasDbPrivFromLdap(userIdent, INTERNAL, CLUSTER + ":" + DB, PrivPredicate.DROP)); - } - - @Test - public void testHasTblPrivFromLdap() { - Assert.assertTrue(LdapPrivsChecker.hasTblPrivFromLdap(userIdent, INTERNAL, CLUSTER + ":" + TABLE_DB, TABLE1, - PrivPredicate.ALTER)); - Assert.assertFalse(LdapPrivsChecker.hasTblPrivFromLdap(userIdent, INTERNAL, CLUSTER + ":" + TABLE_DB, TABLE1, - PrivPredicate.DROP)); - Assert.assertTrue(LdapPrivsChecker.hasTblPrivFromLdap(userIdent, INTERNAL, CLUSTER + ":" + TABLE_DB, TABLE2, - PrivPredicate.DROP)); - Assert.assertFalse(LdapPrivsChecker.hasTblPrivFromLdap(userIdent, INTERNAL, CLUSTER + ":" + TABLE_DB, TABLE2, - PrivPredicate.CREATE)); - } - - @Test - public void testHasResourcePrivFromLdap() { - Assert.assertTrue(LdapPrivsChecker.hasResourcePrivFromLdap(userIdent, RESOURCE1, PrivPredicate.USAGE)); - Assert.assertFalse(LdapPrivsChecker.hasResourcePrivFromLdap(userIdent, "resource", - PrivPredicate.USAGE)); - } - - @Test - public void testGetResourcePrivFromLdap() { - Assert.assertTrue( - LdapPrivsChecker.getResourcePrivFromLdap(userIdent, RESOURCE1).satisfy(PrivPredicate.USAGE)); - } - - @Test - public void testGetLdapAllDbPrivs() throws AnalysisException { - Map allDb = LdapPrivsChecker.getLdapAllDbPrivs(userIdent); - TablePattern db = new TablePattern(DB, "*"); - db.analyze(CLUSTER); - Assert.assertEquals(PrivBitSet.of(Privilege.SELECT_PRIV, Privilege.LOAD_PRIV).toString(), - allDb.get(db).toString()); - } - - @Test - public void testGetLdapAllTblPrivs() throws AnalysisException { - Map allTbl = LdapPrivsChecker.getLdapAllTblPrivs(userIdent); - TablePattern tbl1 = new TablePattern(TABLE_DB, TABLE1); - TablePattern tbl2 = new TablePattern(TABLE_DB, TABLE2); - tbl1.analyze(CLUSTER); - tbl2.analyze(CLUSTER); - Assert.assertEquals(PrivBitSet.of(Privilege.SELECT_PRIV, Privilege.ALTER_PRIV).toString(), - allTbl.get(tbl1).toString()); - Assert.assertEquals(PrivBitSet.of(Privilege.SELECT_PRIV, Privilege.DROP_PRIV).toString(), - allTbl.get(tbl2).toString()); - } - - @Test - public void testGetLdapAllResourcePrivs() { - Map allResource = LdapPrivsChecker.getLdapAllResourcePrivs(userIdent); - ResourcePattern resource1 = new ResourcePattern(RESOURCE1); - ResourcePattern resource2 = new ResourcePattern(RESOURCE1); - Assert.assertEquals(PrivBitSet.of(Privilege.USAGE_PRIV).toString(), allResource.get(resource1).toString()); - Assert.assertEquals(PrivBitSet.of(Privilege.USAGE_PRIV).toString(), allResource.get(resource2).toString()); - } -}