[enhancement](ldap) optimize LDAP authentication. (#11948)
* [enhancement](ldap) optimize LDAP authentication. 1. Support caching LDAP user information. 2. HTTP authentication supports LDAP. 3. LDAP temporary users support default user property. 4. LDAP configuration supports the `admin show config` and `admin set config` commands.
This commit is contained in:
1
build.sh
1
build.sh
@ -432,6 +432,7 @@ if [[ "${BUILD_FE}" -eq 1 ]]; then
|
||||
|
||||
cp -r -p "${DORIS_HOME}/bin"/*_fe.sh "${DORIS_OUTPUT}/fe/bin"/
|
||||
cp -r -p "${DORIS_HOME}/conf/fe.conf" "${DORIS_OUTPUT}/fe/conf"/
|
||||
cp -r -p "${DORIS_HOME}/conf/ldap.conf" "${DORIS_OUTPUT}/fe/conf"/
|
||||
cp -r -p "${DORIS_HOME}/conf"/*.xml "${DORIS_OUTPUT}/fe/conf"/
|
||||
rm -rf "${DORIS_OUTPUT}/fe/lib"/*
|
||||
cp -r -p "${DORIS_HOME}/fe/fe-core/target/lib"/* "${DORIS_OUTPUT}/fe/lib"/
|
||||
|
||||
@ -41,14 +41,16 @@ ldap_user_basedn = ou=people,dc=domain,dc=com
|
||||
ldap_user_filter = (&(uid={login}))
|
||||
ldap_group_basedn = ou=group,dc=domain,dc=com
|
||||
|
||||
# ldap_cache_time_out_s = 12 * 60 * 60;
|
||||
|
||||
# LDAP pool configuration
|
||||
# https://docs.spring.io/spring-ldap/docs/2.3.3.RELEASE/reference/#pool-configuration
|
||||
#max_active = 8
|
||||
#max_total = -1
|
||||
#max_idle = 8
|
||||
#min_idle = 0
|
||||
#max_wait = -1
|
||||
#when_exhausted = 1
|
||||
#test_on_borrow = false
|
||||
#test_on_return = false
|
||||
#test_while_idle = false
|
||||
# ldap_pool_max_active = 8
|
||||
# ldap_pool_max_total = -1
|
||||
# ldap_pool_max_idle = 8
|
||||
# ldap_pool_min_idle = 0
|
||||
# ldap_pool_max_wait = -1
|
||||
# ldap_pool_when_exhausted = 1
|
||||
# ldap_pool_test_on_borrow = false
|
||||
# ldap_pool_test_on_return = false
|
||||
# ldap_pool_test_while_idle = false
|
||||
@ -171,5 +171,3 @@ If jack also belongs to the LDAP groups doris_qa, doris_pm; Doris exists roles:
|
||||
## 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.
|
||||
* The current LDAP authentication only supports password authentication under mysql protocol. If you use the Http interface, you cannot use LDAP users for authentication.
|
||||
* Temporary users do not have user properties.
|
||||
@ -188,5 +188,3 @@ member: uid=jack,ou=aidp,dc=domain,dc=com
|
||||
## LDAP验证的局限
|
||||
|
||||
- 目前Doris的LDAP功能只支持明文密码验证,即用户登录时,密码在client与fe之间、fe与LDAP服务之间以明文的形式传输。
|
||||
- 当前的LDAP验证只支持在mysql协议下进行密码验证,如果使用Http接口则无法使用LDAP用户进行验证。
|
||||
- 临时用户不具有用户属性。
|
||||
@ -75,11 +75,12 @@ public class ConfigBase {
|
||||
private static String ldapCustomConfFile;
|
||||
public static Class<? extends ConfigBase> ldapConfClass;
|
||||
|
||||
public static Map<String, Field> ldapConfFields = Maps.newHashMap();
|
||||
|
||||
private boolean isLdapConfig = false;
|
||||
|
||||
public void init(String configFile) throws Exception {
|
||||
this.isLdapConfig = (this instanceof LdapConfig);
|
||||
if (!isLdapConfig) {
|
||||
if (this instanceof Config) {
|
||||
confClass = this.getClass();
|
||||
confFile = configFile;
|
||||
confFields = Maps.newHashMap();
|
||||
@ -92,9 +93,17 @@ public class ConfigBase {
|
||||
}
|
||||
|
||||
initConf(confFile);
|
||||
} else {
|
||||
} else if (this instanceof LdapConfig) {
|
||||
isLdapConfig = true;
|
||||
ldapConfClass = this.getClass();
|
||||
ldapConfFile = configFile;
|
||||
for (Field field : ldapConfClass.getFields()) {
|
||||
ConfField confField = field.getAnnotation(ConfField.class);
|
||||
if (confField == null) {
|
||||
continue;
|
||||
}
|
||||
ldapConfFields.put(confField.value().equals("") ? field.getName() : confField.value(), field);
|
||||
}
|
||||
initConf(ldapConfFile);
|
||||
}
|
||||
}
|
||||
@ -292,7 +301,11 @@ public class ConfigBase {
|
||||
public static synchronized void setMutableConfig(String key, String value) throws DdlException {
|
||||
Field field = confFields.get(key);
|
||||
if (field == null) {
|
||||
throw new DdlException("Config '" + key + "' does not exist");
|
||||
if (ldapConfFields.containsKey(key)) {
|
||||
field = ldapConfFields.get(key);
|
||||
} else {
|
||||
throw new DdlException("Config '" + key + "' does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
ConfField anno = field.getAnnotation(ConfField.class);
|
||||
@ -313,7 +326,10 @@ public class ConfigBase {
|
||||
}
|
||||
|
||||
public static synchronized List<List<String>> getConfigInfo(PatternMatcher matcher) {
|
||||
return confFields.entrySet().stream().sorted(Map.Entry.comparingByKey()).flatMap(e -> {
|
||||
Map<String, Field> allConfFields = Maps.newHashMap();
|
||||
allConfFields.putAll(confFields);
|
||||
allConfFields.putAll(ldapConfFields);
|
||||
return allConfFields.entrySet().stream().sorted(Map.Entry.comparingByKey()).flatMap(e -> {
|
||||
String confKey = e.getKey();
|
||||
Field f = e.getValue();
|
||||
ConfField anno = f.getAnnotation(ConfField.class);
|
||||
|
||||
@ -66,10 +66,18 @@ public class LdapConfig extends ConfigBase {
|
||||
public static String ldap_group_basedn = "";
|
||||
|
||||
/**
|
||||
* Maximum number of user connections. This value should be between 1 and 10000.
|
||||
* The user LDAP information cache time.
|
||||
* After timeout, the user information will be retrieved from the LDAP service again.
|
||||
*/
|
||||
@ConfigBase.ConfField
|
||||
public static long user_max_connections = 100L;
|
||||
@ConfigBase.ConfField(mutable = true)
|
||||
public static long ldap_user_cache_timeout_s = 12 * 60 * 60;
|
||||
|
||||
/**
|
||||
* System LDAP information cache time.
|
||||
* After timeout, clear all user information in the cache.
|
||||
*/
|
||||
@ConfigBase.ConfField(mutable = true)
|
||||
public static long ldap_cache_timeout_day = 30;
|
||||
|
||||
/**
|
||||
* LDAP pool configuration:
|
||||
@ -80,35 +88,35 @@ public class LdapConfig extends ConfigBase {
|
||||
* from this pool at the same time. You can use a non-positive number for no limit.
|
||||
*/
|
||||
@ConfigBase.ConfField
|
||||
public static int max_active = 8;
|
||||
public static int ldap_pool_max_active = 8;
|
||||
|
||||
/**
|
||||
* The overall maximum number of active connections (for all types) that can be allocated from this pool
|
||||
* at the same time. You can use a non-positive number for no limit.
|
||||
*/
|
||||
@ConfigBase.ConfField
|
||||
public static int max_total = -1;
|
||||
public static int ldap_pool_max_total = -1;
|
||||
|
||||
/**
|
||||
* The maximum number of active connections of each type (read-only or read-write) that can remain idle
|
||||
* in the pool without extra connections being released. You can use a non-positive number for no limit.
|
||||
*/
|
||||
@ConfigBase.ConfField
|
||||
public static int max_idle = 8;
|
||||
public static int ldap_pool_max_idle = 8;
|
||||
|
||||
/**
|
||||
* The minimum number of active connections of each type (read-only or read-write) that can remain idle
|
||||
* in the pool without extra connections being created. You can use zero (the default) to create none.
|
||||
*/
|
||||
@ConfigBase.ConfField
|
||||
public static int min_idle = 0;
|
||||
public static int ldap_pool_min_idle = 0;
|
||||
|
||||
/**
|
||||
* The maximum number of milliseconds that the pool waits (when no connections are available) for a connection
|
||||
* to be returned before throwing an exception. You can use a non-positive number to wait indefinitely.
|
||||
*/
|
||||
@ConfigBase.ConfField
|
||||
public static int max_wait = -1;
|
||||
public static int ldap_pool_max_wait = -1;
|
||||
|
||||
/**
|
||||
* Specifies the behavior when the pool is exhausted.
|
||||
@ -121,25 +129,25 @@ public class LdapConfig extends ConfigBase {
|
||||
* The '2' option creates and returns a new object (essentially making max-active meaningless).
|
||||
*/
|
||||
@ConfigBase.ConfField
|
||||
public static byte when_exhausted = 1;
|
||||
public static byte ldap_pool_when_exhausted = 1;
|
||||
|
||||
/**
|
||||
* Whether objects are validated before being borrowed from the pool. If the object fails to validate,
|
||||
* it is dropped from the pool, and an attempt to borrow another is made.
|
||||
*/
|
||||
@ConfigBase.ConfField
|
||||
public static boolean test_on_borrow = false;
|
||||
public static boolean ldap_pool_test_on_borrow = false;
|
||||
|
||||
/**
|
||||
* Whether objects are validated before being returned to the pool.
|
||||
*/
|
||||
@ConfigBase.ConfField
|
||||
public static boolean test_on_return = false;
|
||||
public static boolean ldap_pool_test_on_return = false;
|
||||
|
||||
/**
|
||||
* Whether objects are validated by the idle object evictor (if any). If an object fails to validate,
|
||||
* it is dropped from the pool.
|
||||
*/
|
||||
@ConfigBase.ConfField
|
||||
public static boolean test_while_idle = false;
|
||||
public static boolean ldap_pool_test_while_idle = false;
|
||||
}
|
||||
|
||||
@ -22,17 +22,12 @@ import org.apache.doris.catalog.Env;
|
||||
import org.apache.doris.cluster.ClusterNamespace;
|
||||
import org.apache.doris.common.ErrorCode;
|
||||
import org.apache.doris.common.ErrorReport;
|
||||
import org.apache.doris.common.LdapConfig;
|
||||
import org.apache.doris.mysql.privilege.PaloRole;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is used for LDAP authentication login and LDAP group authorization.
|
||||
* This means that users can log in to Doris with a user name and LDAP password,
|
||||
@ -41,20 +36,6 @@ import java.util.List;
|
||||
public class LdapAuthenticate {
|
||||
private static final Logger LOG = LogManager.getLogger(LdapAuthenticate.class);
|
||||
|
||||
private static final String LDAP_GROUPS_PRIVS_NAME = "ldapGroupsPrivs";
|
||||
|
||||
// Maximum number of the user LDAP authentication login connections.
|
||||
private static long userMaxConn = 100;
|
||||
|
||||
{
|
||||
if (LdapConfig.user_max_connections <= 0 || LdapConfig.user_max_connections > 10000) {
|
||||
LOG.warn("Ldap config user_max_connections is invalid. It should be set between 1 and 10000. "
|
||||
+ "And now, it is set to the default value.");
|
||||
} else {
|
||||
userMaxConn = LdapConfig.user_max_connections;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The LDAP authentication process is as follows:
|
||||
* step1: Check the LDAP password.
|
||||
@ -70,8 +51,8 @@ public class LdapAuthenticate {
|
||||
|
||||
// check user password by ldap server.
|
||||
try {
|
||||
if (!LdapClient.checkPassword(userName, password)) {
|
||||
LOG.debug("user:{} use error LDAP password.", userName);
|
||||
if (!Env.getCurrentEnv().getAuth().getLdapManager().checkUserPasswd(qualifiedUser, password)) {
|
||||
LOG.info("user:{} use check LDAP password failed.", userName);
|
||||
ErrorReport.report(ErrorCode.ERR_ACCESS_DENIED_ERROR, qualifiedUser, context.getRemoteIP(), usePasswd);
|
||||
return false;
|
||||
}
|
||||
@ -80,15 +61,6 @@ public class LdapAuthenticate {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the LDAP groups privileges as a role.
|
||||
PaloRole ldapGroupsPrivs;
|
||||
try {
|
||||
ldapGroupsPrivs = getLdapGroupsPrivs(userName, clusterName);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Get ldap groups error.", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
String remoteIp = context.getMysqlChannel().getRemoteIp();
|
||||
UserIdentity tempUserIdentity = UserIdentity.createAnalyzedUserIdentWithIp(qualifiedUser, remoteIp);
|
||||
// Search the user in doris.
|
||||
@ -97,48 +69,11 @@ public class LdapAuthenticate {
|
||||
userIdentity = tempUserIdentity;
|
||||
LOG.debug("User:{} does not exists in doris, login as temporary users.", userName);
|
||||
context.setIsTempUser(true);
|
||||
if (ldapGroupsPrivs == null) {
|
||||
ldapGroupsPrivs = new PaloRole(LDAP_GROUPS_PRIVS_NAME);
|
||||
}
|
||||
LdapPrivsChecker.grantDefaultPrivToTempUser(ldapGroupsPrivs, clusterName);
|
||||
}
|
||||
|
||||
context.setCurrentUserIdentity(userIdentity);
|
||||
context.setRemoteIP(remoteIp);
|
||||
context.setLdapGroupsPrivs(ldapGroupsPrivs);
|
||||
LOG.debug("ldap authentication success: identity:{}, privs:{}",
|
||||
context.getCurrentUserIdentity(), context.getLdapGroupsPrivs());
|
||||
LOG.debug("ldap authentication success: identity:{}", context.getCurrentUserIdentity());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step1: get ldap groups from ldap server;
|
||||
* Step2: get roles by ldap groups;
|
||||
* Step3: merge the roles;
|
||||
*/
|
||||
private static PaloRole getLdapGroupsPrivs(String userName, String clusterName) {
|
||||
//get user ldap group. the ldap group name should be the same as the doris role name
|
||||
List<String> ldapGroups = LdapClient.getGroups(userName);
|
||||
List<String> rolesNames = Lists.newArrayList();
|
||||
for (String group : ldapGroups) {
|
||||
String qualifiedRole = ClusterNamespace.getFullName(clusterName, group);
|
||||
if (Env.getCurrentEnv().getAuth().doesRoleExist(qualifiedRole)) {
|
||||
rolesNames.add(qualifiedRole);
|
||||
}
|
||||
}
|
||||
LOG.debug("get user:{} ldap groups:{} and doris roles:{}", userName, ldapGroups, rolesNames);
|
||||
|
||||
// merge the roles
|
||||
if (rolesNames.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
PaloRole ldapGroupsPrivs = new PaloRole(LDAP_GROUPS_PRIVS_NAME);
|
||||
Env.getCurrentEnv().getAuth().mergeRolesNoCheckName(rolesNames, ldapGroupsPrivs);
|
||||
return ldapGroupsPrivs;
|
||||
}
|
||||
}
|
||||
|
||||
public static long getMaxConn() {
|
||||
return userMaxConn;
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ import java.util.List;
|
||||
public class LdapClient {
|
||||
private static final Logger LOG = LogManager.getLogger(LdapClient.class);
|
||||
|
||||
private static volatile ClientInfo clientInfo;
|
||||
private volatile ClientInfo clientInfo;
|
||||
|
||||
@Data
|
||||
private static class ClientInfo {
|
||||
@ -85,15 +85,15 @@ public class LdapClient {
|
||||
PoolingContextSource poolingContextSource = new PoolingContextSource();
|
||||
poolingContextSource.setDirContextValidator(new DefaultDirContextValidator());
|
||||
poolingContextSource.setContextSource(contextSource);
|
||||
poolingContextSource.setMaxActive(LdapConfig.max_active);
|
||||
poolingContextSource.setMaxTotal(LdapConfig.max_total);
|
||||
poolingContextSource.setMaxIdle(LdapConfig.max_idle);
|
||||
poolingContextSource.setMaxWait(LdapConfig.max_wait);
|
||||
poolingContextSource.setMinIdle(LdapConfig.min_idle);
|
||||
poolingContextSource.setWhenExhaustedAction(LdapConfig.when_exhausted);
|
||||
poolingContextSource.setTestOnBorrow(LdapConfig.test_on_borrow);
|
||||
poolingContextSource.setTestOnReturn(LdapConfig.test_on_return);
|
||||
poolingContextSource.setTestWhileIdle(LdapConfig.test_while_idle);
|
||||
poolingContextSource.setMaxActive(LdapConfig.ldap_pool_max_active);
|
||||
poolingContextSource.setMaxTotal(LdapConfig.ldap_pool_max_total);
|
||||
poolingContextSource.setMaxIdle(LdapConfig.ldap_pool_max_idle);
|
||||
poolingContextSource.setMaxWait(LdapConfig.ldap_pool_max_wait);
|
||||
poolingContextSource.setMinIdle(LdapConfig.ldap_pool_min_idle);
|
||||
poolingContextSource.setWhenExhaustedAction(LdapConfig.ldap_pool_when_exhausted);
|
||||
poolingContextSource.setTestOnBorrow(LdapConfig.ldap_pool_test_on_borrow);
|
||||
poolingContextSource.setTestOnReturn(LdapConfig.ldap_pool_test_on_return);
|
||||
poolingContextSource.setTestWhileIdle(LdapConfig.ldap_pool_test_while_idle);
|
||||
|
||||
TransactionAwareContextSourceProxy proxy = new TransactionAwareContextSourceProxy(poolingContextSource);
|
||||
ldapTemplatePool = new LdapTemplate(proxy);
|
||||
@ -104,7 +104,7 @@ public class LdapClient {
|
||||
}
|
||||
}
|
||||
|
||||
private static void init() {
|
||||
private void init() {
|
||||
LdapInfo ldapInfo = Env.getCurrentEnv().getAuth().getLdapInfo();
|
||||
if (ldapInfo == null || !ldapInfo.isValid()) {
|
||||
LOG.error("info is null, maybe no ldap admin password is set.");
|
||||
@ -123,7 +123,7 @@ public class LdapClient {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean doesUserExist(String userName) {
|
||||
boolean doesUserExist(String userName) {
|
||||
String user = getUserDn(userName);
|
||||
if (user == null) {
|
||||
LOG.debug("User:{} does not exist in LDAP.", userName);
|
||||
@ -132,7 +132,7 @@ public class LdapClient {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean checkPassword(String userName, String password) {
|
||||
boolean checkPassword(String userName, String password) {
|
||||
init();
|
||||
try {
|
||||
clientInfo.getLdapTemplateNoPool().authenticate(org.springframework.ldap.query.LdapQueryBuilder.query()
|
||||
@ -145,7 +145,7 @@ public class LdapClient {
|
||||
}
|
||||
|
||||
// Search group DNs by 'member' attribution.
|
||||
public static List<String> getGroups(String userName) {
|
||||
List<String> getGroups(String userName) {
|
||||
List<String> groups = Lists.newArrayList();
|
||||
if (LdapConfig.ldap_group_basedn.isEmpty()) {
|
||||
return groups;
|
||||
@ -171,7 +171,7 @@ public class LdapClient {
|
||||
return groups;
|
||||
}
|
||||
|
||||
private static String getUserDn(String userName) {
|
||||
private String getUserDn(String userName) {
|
||||
List<String> userDns = getDn(org.springframework.ldap.query.LdapQueryBuilder.query()
|
||||
.base(LdapConfig.ldap_user_basedn).filter(getUserFilter(LdapConfig.ldap_user_filter, userName)));
|
||||
if (userDns == null || userDns.isEmpty()) {
|
||||
@ -186,7 +186,7 @@ public class LdapClient {
|
||||
return userDns.get(0);
|
||||
}
|
||||
|
||||
private static List<String> getDn(LdapQuery query) {
|
||||
private List<String> getDn(LdapQuery query) {
|
||||
init();
|
||||
try {
|
||||
return clientInfo.getLdapTemplatePool().search(query, new AbstractContextMapper<String>() {
|
||||
@ -201,7 +201,7 @@ public class LdapClient {
|
||||
}
|
||||
}
|
||||
|
||||
private static String getUserFilter(String userFilter, String userName) {
|
||||
private String getUserFilter(String userFilter, String userName) {
|
||||
return userFilter.replaceAll("\\{login}", userName);
|
||||
}
|
||||
}
|
||||
|
||||
216
fe/fe-core/src/main/java/org/apache/doris/ldap/LdapManager.java
Normal file
216
fe/fe-core/src/main/java/org/apache/doris/ldap/LdapManager.java
Normal file
@ -0,0 +1,216 @@
|
||||
// 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.UserIdentity;
|
||||
import org.apache.doris.catalog.Env;
|
||||
import org.apache.doris.cluster.ClusterNamespace;
|
||||
import org.apache.doris.common.LdapConfig;
|
||||
import org.apache.doris.mysql.privilege.PaloAuth;
|
||||
import org.apache.doris.mysql.privilege.PaloRole;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.parquet.Strings;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* Encapsulates LDAP service interfaces and caches user LDAP information.
|
||||
*/
|
||||
public class LdapManager {
|
||||
private static final Logger LOG = LogManager.getLogger(LdapManager.class);
|
||||
|
||||
private static final String LDAP_GROUPS_PRIVS_NAME = "ldapGroupsPrivs";
|
||||
|
||||
private final LdapClient ldapClient = new LdapClient();
|
||||
|
||||
private final Map<String, LdapUserInfo> ldapUserInfoCache = Maps.newHashMap();
|
||||
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
private void readLock() {
|
||||
lock.readLock().lock();
|
||||
}
|
||||
|
||||
private void readUnlock() {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
|
||||
private void writeLock() {
|
||||
lock.writeLock().lock();
|
||||
}
|
||||
|
||||
private void writeUnlock() {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
|
||||
private volatile long lastTimestamp = System.currentTimeMillis();
|
||||
|
||||
// If the user exists in LDAP, the LDAP information of the user is returned; otherwise, null is returned.
|
||||
public LdapUserInfo getUserInfo(String fullName) {
|
||||
if (!checkParam(fullName)) {
|
||||
return null;
|
||||
}
|
||||
LdapUserInfo ldapUserInfo = getUserInfoFromCache(fullName);
|
||||
if (ldapUserInfo != null && !ldapUserInfo.checkTimeout()) {
|
||||
return ldapUserInfo;
|
||||
}
|
||||
return getUserInfoAndUpdateCache(fullName);
|
||||
}
|
||||
|
||||
public boolean doesUserExist(String fullName) {
|
||||
if (!checkParam(fullName)) {
|
||||
return false;
|
||||
}
|
||||
return !Objects.isNull(getUserInfo(fullName));
|
||||
}
|
||||
|
||||
public boolean checkUserPasswd(String fullName, String passwd) {
|
||||
String userName = ClusterNamespace.getNameFromFullName(fullName);
|
||||
if (!LdapConfig.ldap_authentication_enabled || Strings.isNullOrEmpty(userName) || Objects.isNull(passwd)) {
|
||||
return false;
|
||||
}
|
||||
LdapUserInfo ldapUserInfo = getUserInfo(fullName);
|
||||
if (Objects.isNull(ldapUserInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ldapUserInfo.isSetPasswd() && ldapUserInfo.getPasswd().equals(passwd)) {
|
||||
return true;
|
||||
}
|
||||
boolean isRightPasswd = ldapClient.checkPassword(userName, passwd);
|
||||
if (!isRightPasswd) {
|
||||
return false;
|
||||
}
|
||||
updatePasswd(ldapUserInfo, passwd);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkUserPasswd(String fullName, String passwd, String remoteIp, List<UserIdentity> currentUser) {
|
||||
if (checkUserPasswd(fullName, passwd)) {
|
||||
currentUser.add(UserIdentity.createAnalyzedUserIdentWithIp(fullName, remoteIp));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkParam(String fullName) {
|
||||
return LdapConfig.ldap_authentication_enabled && !Strings.isNullOrEmpty(fullName) && !fullName.equalsIgnoreCase(
|
||||
PaloAuth.ROOT_USER) && !fullName.equalsIgnoreCase(PaloAuth.ADMIN_USER);
|
||||
}
|
||||
|
||||
private LdapUserInfo getUserInfoAndUpdateCache(String fulName) {
|
||||
String cluster = ClusterNamespace.getClusterNameFromFullName(fulName);
|
||||
String userName = ClusterNamespace.getNameFromFullName(fulName);
|
||||
if (Strings.isNullOrEmpty(userName)) {
|
||||
return null;
|
||||
} else if (!ldapClient.doesUserExist(userName)) {
|
||||
removeUserIfExist(fulName);
|
||||
return null;
|
||||
}
|
||||
checkTimeoutCleanCache();
|
||||
|
||||
LdapUserInfo ldapUserInfo = new LdapUserInfo(fulName, false, "", getLdapGroupsPrivs(userName, cluster));
|
||||
writeLock();
|
||||
try {
|
||||
ldapUserInfoCache.put(ldapUserInfo.getUserName(), ldapUserInfo);
|
||||
} finally {
|
||||
writeUnlock();
|
||||
}
|
||||
return ldapUserInfo;
|
||||
}
|
||||
|
||||
private void updatePasswd(LdapUserInfo ldapUserInfo, String passwd) {
|
||||
LdapUserInfo newLdapUserInfo = ldapUserInfo.cloneWithPasswd(passwd);
|
||||
writeLock();
|
||||
try {
|
||||
ldapUserInfoCache.put(newLdapUserInfo.getUserName(), newLdapUserInfo);
|
||||
} finally {
|
||||
writeUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void removeUserIfExist(String fullName) {
|
||||
LdapUserInfo ldapUserInfo = getUserInfoFromCache(fullName);
|
||||
if (ldapUserInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
writeLock();
|
||||
try {
|
||||
ldapUserInfoCache.remove(ldapUserInfo.getUserName());
|
||||
} finally {
|
||||
writeUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkTimeoutCleanCache() {
|
||||
long tempTimestamp = System.currentTimeMillis() - LdapConfig.ldap_cache_timeout_day * 24 * 60 * 60 * 1000;
|
||||
if (lastTimestamp < tempTimestamp) {
|
||||
writeLock();
|
||||
try {
|
||||
if (lastTimestamp < tempTimestamp) {
|
||||
ldapUserInfoCache.clear();
|
||||
lastTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
} finally {
|
||||
writeUnlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LdapUserInfo getUserInfoFromCache(String fullName) {
|
||||
readLock();
|
||||
try {
|
||||
return ldapUserInfoCache.get(fullName);
|
||||
} finally {
|
||||
readUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Step1: get ldap groups from ldap server;
|
||||
* Step2: get roles by ldap groups;
|
||||
* Step3: merge the roles;
|
||||
*/
|
||||
private PaloRole getLdapGroupsPrivs(String userName, String clusterName) {
|
||||
//get user ldap group. the ldap group name should be the same as the doris role name
|
||||
List<String> ldapGroups = ldapClient.getGroups(userName);
|
||||
List<String> rolesNames = Lists.newArrayList();
|
||||
for (String group : ldapGroups) {
|
||||
String qualifiedRole = ClusterNamespace.getFullName(clusterName, group);
|
||||
if (Env.getCurrentEnv().getAuth().doesRoleExist(qualifiedRole)) {
|
||||
rolesNames.add(qualifiedRole);
|
||||
}
|
||||
}
|
||||
LOG.debug("get user:{} ldap groups:{} and doris roles:{}", userName, ldapGroups, rolesNames);
|
||||
|
||||
PaloRole ldapGroupsPrivs = new PaloRole(LDAP_GROUPS_PRIVS_NAME);
|
||||
LdapPrivsChecker.grantDefaultPrivToTempUser(ldapGroupsPrivs, clusterName);
|
||||
if (!rolesNames.isEmpty()) {
|
||||
Env.getCurrentEnv().getAuth().mergeRolesNoCheckName(rolesNames, ldapGroupsPrivs);
|
||||
}
|
||||
return ldapGroupsPrivs;
|
||||
}
|
||||
}
|
||||
@ -20,6 +20,7 @@ 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.LdapConfig;
|
||||
@ -28,7 +29,6 @@ import org.apache.doris.mysql.privilege.PaloPrivilege;
|
||||
import org.apache.doris.mysql.privilege.PaloRole;
|
||||
import org.apache.doris.mysql.privilege.PrivBitSet;
|
||||
import org.apache.doris.mysql.privilege.PrivPredicate;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Maps;
|
||||
@ -38,9 +38,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* If the user logs in with LDAP authentication, the user LDAP group privileges will be saved in 'ldapGroupsPrivs' of
|
||||
* ConnectContext. When checking user privileges, Doris need to check both the privileges granted by Doris
|
||||
* and LDAP group privileges. This class is used for checking current user LDAP group privileges.
|
||||
* This class is used for checking current user LDAP group privileges.
|
||||
*/
|
||||
public class LdapPrivsChecker {
|
||||
private static final Logger LOG = LogManager.getLogger(LdapPrivsChecker.class);
|
||||
@ -116,7 +114,7 @@ public class LdapPrivsChecker {
|
||||
if (!hasLdapPrivs(currentUser)) {
|
||||
return;
|
||||
}
|
||||
PaloRole currentUserLdapPrivs = ConnectContext.get().getLdapGroupsPrivs();
|
||||
PaloRole currentUserLdapPrivs = getUserLdapPrivs(currentUser.getQualifiedUser());
|
||||
for (Map.Entry<TablePattern, PrivBitSet> entry : currentUserLdapPrivs.getTblPatternToPrivs().entrySet()) {
|
||||
switch (entry.getKey().getPrivLevel()) {
|
||||
case GLOBAL:
|
||||
@ -150,7 +148,7 @@ public class LdapPrivsChecker {
|
||||
if (!hasLdapPrivs(currentUser)) {
|
||||
return;
|
||||
}
|
||||
PaloRole currentUserLdapPrivs = ConnectContext.get().getLdapGroupsPrivs();
|
||||
PaloRole currentUserLdapPrivs = getUserLdapPrivs(currentUser.getQualifiedUser());
|
||||
for (Map.Entry<ResourcePattern, PrivBitSet> entry
|
||||
: currentUserLdapPrivs.getResourcePatternToPrivs().entrySet()) {
|
||||
switch (entry.getKey().getPrivLevel()) {
|
||||
@ -177,7 +175,7 @@ public class LdapPrivsChecker {
|
||||
if (!hasLdapPrivs(currentUser)) {
|
||||
return false;
|
||||
}
|
||||
PaloRole currentUserLdapPrivs = ConnectContext.get().getLdapGroupsPrivs();
|
||||
PaloRole currentUserLdapPrivs = getUserLdapPrivs(currentUser.getQualifiedUser());
|
||||
for (Map.Entry<TablePattern, PrivBitSet> entry : currentUserLdapPrivs.getTblPatternToPrivs().entrySet()) {
|
||||
if (entry.getKey().getPrivLevel().equals(level) && PaloPrivilege.satisfy(entry.getValue(), wanted)) {
|
||||
return true;
|
||||
@ -191,7 +189,7 @@ public class LdapPrivsChecker {
|
||||
if (!hasLdapPrivs(currentUser)) {
|
||||
return false;
|
||||
}
|
||||
PaloRole currentUserLdapPrivs = ConnectContext.get().getLdapGroupsPrivs();
|
||||
PaloRole currentUserLdapPrivs = getUserLdapPrivs(currentUser.getQualifiedUser());
|
||||
for (Map.Entry<TablePattern, PrivBitSet> entry : currentUserLdapPrivs.getTblPatternToPrivs().entrySet()) {
|
||||
if (entry.getKey().getPrivLevel().equals(PaloAuth.PrivLevel.TABLE)
|
||||
&& entry.getKey().getQualifiedDb().equals(db)) {
|
||||
@ -201,19 +199,9 @@ public class LdapPrivsChecker {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isCurrentUser(UserIdentity userIdent) {
|
||||
ConnectContext context = ConnectContext.get();
|
||||
if (context == null) {
|
||||
return false;
|
||||
}
|
||||
UserIdentity currentUser = context.getCurrentUserIdentity();
|
||||
return currentUser.getQualifiedUser().equals(userIdent.getQualifiedUser())
|
||||
&& currentUser.getHost().equals(userIdent.getHost());
|
||||
}
|
||||
|
||||
public static boolean hasLdapPrivs(UserIdentity userIdent) {
|
||||
return LdapConfig.ldap_authentication_enabled && isCurrentUser(userIdent)
|
||||
&& ConnectContext.get().getLdapGroupsPrivs() != null;
|
||||
return LdapConfig.ldap_authentication_enabled && Env.getCurrentEnv().getAuth().getLdapManager()
|
||||
.doesUserExist(userIdent.getQualifiedUser());
|
||||
}
|
||||
|
||||
public static Map<TablePattern, PrivBitSet> getLdapAllDbPrivs(UserIdentity userIdentity) {
|
||||
@ -221,7 +209,7 @@ public class LdapPrivsChecker {
|
||||
if (!hasLdapPrivs(userIdentity)) {
|
||||
return ldapDbPrivs;
|
||||
}
|
||||
for (Map.Entry<TablePattern, PrivBitSet> entry : ConnectContext.get().getLdapGroupsPrivs()
|
||||
for (Map.Entry<TablePattern, PrivBitSet> entry : getUserLdapPrivs(userIdentity.getQualifiedUser())
|
||||
.getTblPatternToPrivs().entrySet()) {
|
||||
if (entry.getKey().getPrivLevel().equals(PaloAuth.PrivLevel.DATABASE)) {
|
||||
ldapDbPrivs.put(entry.getKey(), entry.getValue());
|
||||
@ -235,7 +223,7 @@ public class LdapPrivsChecker {
|
||||
if (!hasLdapPrivs(userIdentity)) {
|
||||
return ldapTblPrivs;
|
||||
}
|
||||
for (Map.Entry<TablePattern, PrivBitSet> entry : ConnectContext.get().getLdapGroupsPrivs()
|
||||
for (Map.Entry<TablePattern, PrivBitSet> entry : getUserLdapPrivs(userIdentity.getQualifiedUser())
|
||||
.getTblPatternToPrivs().entrySet()) {
|
||||
if (entry.getKey().getPrivLevel().equals(PaloAuth.PrivLevel.TABLE)) {
|
||||
ldapTblPrivs.put(entry.getKey(), entry.getValue());
|
||||
@ -249,7 +237,7 @@ public class LdapPrivsChecker {
|
||||
if (!hasLdapPrivs(userIdentity)) {
|
||||
return ldapResourcePrivs;
|
||||
}
|
||||
for (Map.Entry<ResourcePattern, PrivBitSet> entry : ConnectContext.get().getLdapGroupsPrivs()
|
||||
for (Map.Entry<ResourcePattern, PrivBitSet> entry : getUserLdapPrivs(userIdentity.getQualifiedUser())
|
||||
.getResourcePatternToPrivs().entrySet()) {
|
||||
if (entry.getKey().getPrivLevel().equals(PaloAuth.PrivLevel.RESOURCE)) {
|
||||
ldapResourcePrivs.put(entry.getKey(), entry.getValue());
|
||||
@ -258,6 +246,10 @@ public class LdapPrivsChecker {
|
||||
return ldapResourcePrivs;
|
||||
}
|
||||
|
||||
private static PaloRole getUserLdapPrivs(String fullName) {
|
||||
return Env.getCurrentEnv().getAuth().getLdapManager().getUserInfo(fullName).getPaloRole();
|
||||
}
|
||||
|
||||
// Temporary user has information_schema 'Select_priv' priv by default.
|
||||
public static void grantDefaultPrivToTempUser(PaloRole role, String clusterName) {
|
||||
TablePattern tblPattern = new TablePattern(InfoSchemaDb.DATABASE_NAME, "*");
|
||||
|
||||
@ -0,0 +1,84 @@
|
||||
// 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.common.LdapConfig;
|
||||
import org.apache.doris.mysql.privilege.PaloRole;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Used to cache LDAP information of user, such as password and privileges.
|
||||
*/
|
||||
public class LdapUserInfo {
|
||||
public LdapUserInfo(String userName, boolean isSetPasswd, String passwd, PaloRole paloRole) {
|
||||
this.userName = userName;
|
||||
this.isSetPasswd = isSetPasswd;
|
||||
this.passwd = passwd;
|
||||
this.paloRole = paloRole;
|
||||
this.lastTimeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
private LdapUserInfo(String userName, boolean isSetPasswd, String passwd, PaloRole paloRole, long lastTimeStamp) {
|
||||
this.userName = userName;
|
||||
this.isSetPasswd = isSetPasswd;
|
||||
this.passwd = passwd;
|
||||
this.paloRole = paloRole;
|
||||
this.lastTimeStamp = lastTimeStamp;
|
||||
}
|
||||
|
||||
private final String userName;
|
||||
|
||||
private final boolean isSetPasswd;
|
||||
|
||||
private final String passwd;
|
||||
|
||||
private final PaloRole paloRole;
|
||||
|
||||
private final long lastTimeStamp;
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
// The password needs to be checked by LdapManager for updated cache, so it is visible in the package.
|
||||
boolean isSetPasswd() {
|
||||
return isSetPasswd;
|
||||
}
|
||||
|
||||
String getPasswd() {
|
||||
return passwd;
|
||||
}
|
||||
|
||||
public PaloRole getPaloRole() {
|
||||
return paloRole;
|
||||
}
|
||||
|
||||
public LdapUserInfo cloneWithPasswd(String passwd) {
|
||||
if (Objects.isNull(passwd)) {
|
||||
return new LdapUserInfo(userName, isSetPasswd, this.passwd, paloRole, lastTimeStamp);
|
||||
}
|
||||
|
||||
return new LdapUserInfo(userName, true, passwd, paloRole, lastTimeStamp);
|
||||
}
|
||||
|
||||
// Return true if LdapUserInfo is exceeded the time limit;
|
||||
public boolean checkTimeout() {
|
||||
return System.currentTimeMillis() > lastTimeStamp + LdapConfig.ldap_user_cache_timeout_s * 1000;
|
||||
}
|
||||
}
|
||||
@ -26,7 +26,6 @@ import org.apache.doris.common.ErrorCode;
|
||||
import org.apache.doris.common.ErrorReport;
|
||||
import org.apache.doris.common.LdapConfig;
|
||||
import org.apache.doris.ldap.LdapAuthenticate;
|
||||
import org.apache.doris.ldap.LdapClient;
|
||||
import org.apache.doris.mysql.privilege.PaloAuth;
|
||||
import org.apache.doris.mysql.privilege.UserResource;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
@ -137,11 +136,8 @@ public class MysqlProto {
|
||||
}
|
||||
// If LDAP authentication is enabled and the user exists in LDAP, use LDAP authentication,
|
||||
// otherwise use Doris authentication.
|
||||
if (LdapConfig.ldap_authentication_enabled
|
||||
&& LdapClient.doesUserExist(ClusterNamespace.getNameFromFullName(qualifiedUser))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return LdapConfig.ldap_authentication_enabled && Env.getCurrentEnv().getAuth().getLdapManager()
|
||||
.doesUserExist(qualifiedUser);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -206,7 +202,7 @@ public class MysqlProto {
|
||||
try {
|
||||
useLdapAuthenticate = useLdapAuthenticate(qualifiedUser);
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Check if user exists in ldap error.", e);
|
||||
LOG.warn("Check if user exists in ldap error.", e);
|
||||
sendResponsePacket(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@ import org.apache.doris.common.Pair;
|
||||
import org.apache.doris.common.UserException;
|
||||
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.load.DppConfig;
|
||||
import org.apache.doris.persist.LdapInfo;
|
||||
@ -92,6 +93,8 @@ public class PaloAuth implements Writable {
|
||||
|
||||
private LdapInfo ldapInfo = new LdapInfo();
|
||||
|
||||
private LdapManager ldapManager = new LdapManager();
|
||||
|
||||
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
private void readLock() {
|
||||
@ -138,6 +141,10 @@ public class PaloAuth implements Writable {
|
||||
this.ldapInfo = ldapInfo;
|
||||
}
|
||||
|
||||
public LdapManager getLdapManager() {
|
||||
return ldapManager;
|
||||
}
|
||||
|
||||
private GlobalPrivEntry grantGlobalPrivs(UserIdentity userIdentity, boolean errOnExist, boolean errOnNonExist,
|
||||
PrivBitSet privs) throws DdlException {
|
||||
if (errOnExist && errOnNonExist) {
|
||||
@ -328,6 +335,11 @@ public class PaloAuth implements Writable {
|
||||
if (!Config.enable_auth_check) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the LDAP password when the user exists in the LDAP service.
|
||||
if (ldapManager.doesUserExist(remoteUser)) {
|
||||
return ldapManager.checkUserPasswd(remoteUser, remotePasswd, remoteHost, currentUser);
|
||||
}
|
||||
readLock();
|
||||
try {
|
||||
return userPrivTable.checkPlainPassword(remoteUser, remoteHost, remotePasswd, currentUser);
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
package org.apache.doris.mysql.privilege;
|
||||
|
||||
import org.apache.doris.analysis.UserIdentity;
|
||||
import org.apache.doris.catalog.Env;
|
||||
import org.apache.doris.common.AnalysisException;
|
||||
import org.apache.doris.common.Config;
|
||||
import org.apache.doris.common.DdlException;
|
||||
@ -48,6 +49,19 @@ public class UserPropertyMgr implements Writable {
|
||||
protected Map<String, UserProperty> propertyMap = Maps.newHashMap();
|
||||
public static final String ROOT_USER = "root";
|
||||
public static final String SYSTEM_RESOURCE_USER = "system";
|
||||
public static final String LDAP_RESOURCE_USER = "ldap";
|
||||
|
||||
private static final UserProperty LDAP_PROPERTY = new UserProperty(LDAP_RESOURCE_USER);
|
||||
|
||||
static {
|
||||
try {
|
||||
setNormalUserDefaultResource(LDAP_PROPERTY);
|
||||
} catch (DdlException e) {
|
||||
LOG.error("init DEFAULT_PROPERTY error.", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private AtomicLong resourceVersion = new AtomicLong(0);
|
||||
|
||||
public UserPropertyMgr() {
|
||||
@ -118,6 +132,7 @@ public class UserPropertyMgr implements Writable {
|
||||
|
||||
public long getMaxConn(String qualifiedUser) {
|
||||
UserProperty existProperty = propertyMap.get(qualifiedUser);
|
||||
existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
|
||||
if (existProperty == null) {
|
||||
return 0;
|
||||
}
|
||||
@ -126,6 +141,7 @@ public class UserPropertyMgr implements Writable {
|
||||
|
||||
public long getMaxQueryInstances(String qualifiedUser) {
|
||||
UserProperty existProperty = propertyMap.get(qualifiedUser);
|
||||
existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
|
||||
if (existProperty == null) {
|
||||
return Config.default_max_query_instances;
|
||||
}
|
||||
@ -134,6 +150,7 @@ public class UserPropertyMgr implements Writable {
|
||||
|
||||
public Set<Tag> getResourceTags(String qualifiedUser) {
|
||||
UserProperty existProperty = propertyMap.get(qualifiedUser);
|
||||
existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
|
||||
if (existProperty == null) {
|
||||
return UserProperty.INVALID_RESOURCE_TAGS;
|
||||
}
|
||||
@ -154,7 +171,7 @@ public class UserPropertyMgr implements Writable {
|
||||
userResource.updateResource("HDD_WRITE_MBPS", 30);
|
||||
}
|
||||
|
||||
private void setNormalUserDefaultResource(UserProperty user) throws DdlException {
|
||||
private static void setNormalUserDefaultResource(UserProperty user) throws DdlException {
|
||||
UserResource userResource = user.getResource();
|
||||
userResource.updateResource("CPU_SHARE", 1000);
|
||||
userResource.updateResource("IO_SHARE", 1000);
|
||||
@ -179,21 +196,21 @@ public class UserPropertyMgr implements Writable {
|
||||
public Pair<String, DppConfig> getLoadClusterInfo(String qualifiedUser, String cluster) throws DdlException {
|
||||
Pair<String, DppConfig> loadClusterInfo = null;
|
||||
|
||||
if (!propertyMap.containsKey(qualifiedUser)) {
|
||||
UserProperty property = propertyMap.get(qualifiedUser);
|
||||
property = getLdapPropertyIfNull(qualifiedUser, property);
|
||||
if (property == null) {
|
||||
throw new DdlException("User " + qualifiedUser + " does not exist");
|
||||
}
|
||||
|
||||
UserProperty property = propertyMap.get(qualifiedUser);
|
||||
loadClusterInfo = property.getLoadClusterInfo(cluster);
|
||||
return loadClusterInfo;
|
||||
}
|
||||
|
||||
public List<List<String>> fetchUserProperty(String qualifiedUser) throws AnalysisException {
|
||||
if (!propertyMap.containsKey(qualifiedUser)) {
|
||||
UserProperty property = propertyMap.get(qualifiedUser);
|
||||
property = getLdapPropertyIfNull(qualifiedUser, property);
|
||||
if (property == null) {
|
||||
throw new AnalysisException("User " + qualifiedUser + " does not exist");
|
||||
}
|
||||
|
||||
UserProperty property = propertyMap.get(qualifiedUser);
|
||||
return property.fetchProperty();
|
||||
}
|
||||
|
||||
@ -232,6 +249,7 @@ public class UserPropertyMgr implements Writable {
|
||||
|
||||
public String[] getSqlBlockRules(String qualifiedUser) {
|
||||
UserProperty existProperty = propertyMap.get(qualifiedUser);
|
||||
existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
|
||||
if (existProperty == null) {
|
||||
return new String[]{};
|
||||
}
|
||||
@ -240,18 +258,16 @@ public class UserPropertyMgr implements Writable {
|
||||
|
||||
public int getCpuResourceLimit(String qualifiedUser) {
|
||||
UserProperty existProperty = propertyMap.get(qualifiedUser);
|
||||
existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
|
||||
if (existProperty == null) {
|
||||
return -1;
|
||||
}
|
||||
return existProperty.getCpuResourceLimit();
|
||||
}
|
||||
|
||||
public UserProperty getUserProperty(String qualifiedUserName) {
|
||||
return propertyMap.get(qualifiedUserName);
|
||||
}
|
||||
|
||||
public long getExecMemLimit(String qualifiedUser) {
|
||||
UserProperty existProperty = propertyMap.get(qualifiedUser);
|
||||
existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
|
||||
if (existProperty == null) {
|
||||
return -1;
|
||||
}
|
||||
@ -260,12 +276,20 @@ public class UserPropertyMgr implements Writable {
|
||||
|
||||
public long getLoadMemLimit(String qualifiedUser) {
|
||||
UserProperty existProperty = propertyMap.get(qualifiedUser);
|
||||
existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
|
||||
if (existProperty == null) {
|
||||
return -1;
|
||||
}
|
||||
return existProperty.getLoadMemLimit();
|
||||
}
|
||||
|
||||
private UserProperty getLdapPropertyIfNull(String qualifiedUser, UserProperty existProperty) {
|
||||
if (existProperty == null && Env.getCurrentEnv().getAuth().getLdapManager().doesUserExist(qualifiedUser)) {
|
||||
return LDAP_PROPERTY;
|
||||
}
|
||||
return existProperty;
|
||||
}
|
||||
|
||||
public static UserPropertyMgr read(DataInput in) throws IOException {
|
||||
UserPropertyMgr userPropertyMgr = new UserPropertyMgr();
|
||||
userPropertyMgr.readFields(in);
|
||||
|
||||
@ -31,7 +31,6 @@ import org.apache.doris.mysql.MysqlCapability;
|
||||
import org.apache.doris.mysql.MysqlChannel;
|
||||
import org.apache.doris.mysql.MysqlCommand;
|
||||
import org.apache.doris.mysql.MysqlSerializer;
|
||||
import org.apache.doris.mysql.privilege.PaloRole;
|
||||
import org.apache.doris.plugin.AuditEvent.AuditEventBuilder;
|
||||
import org.apache.doris.resource.Tag;
|
||||
import org.apache.doris.thrift.TResourceInfo;
|
||||
@ -88,8 +87,6 @@ public class ConnectContext {
|
||||
// LDAP authenticated but the Doris account does not exist,
|
||||
// set the flag, and the user login Doris as Temporary user.
|
||||
protected volatile boolean isTempUser = false;
|
||||
// Save the privs from the ldap groups.
|
||||
protected volatile PaloRole ldapGroupsPrivs = null;
|
||||
// username@host combination for the Doris account
|
||||
// that the server used to authenticate the current client.
|
||||
// In other word, currentUserIdentity is the entry that matched in Doris auth table.
|
||||
@ -321,14 +318,6 @@ public class ConnectContext {
|
||||
this.isTempUser = isTempUser;
|
||||
}
|
||||
|
||||
public PaloRole getLdapGroupsPrivs() {
|
||||
return ldapGroupsPrivs;
|
||||
}
|
||||
|
||||
public void setLdapGroupsPrivs(PaloRole ldapGroupsPrivs) {
|
||||
this.ldapGroupsPrivs = ldapGroupsPrivs;
|
||||
}
|
||||
|
||||
// for USER() function
|
||||
public UserIdentity getUserIdentity() {
|
||||
return new UserIdentity(qualifiedUser, remoteIP);
|
||||
|
||||
@ -21,7 +21,6 @@ import org.apache.doris.catalog.Env;
|
||||
import org.apache.doris.common.Config;
|
||||
import org.apache.doris.common.ErrorCode;
|
||||
import org.apache.doris.common.ThreadPoolManager;
|
||||
import org.apache.doris.ldap.LdapAuthenticate;
|
||||
import org.apache.doris.mysql.MysqlProto;
|
||||
import org.apache.doris.mysql.nio.NConnectContext;
|
||||
import org.apache.doris.mysql.privilege.PrivPredicate;
|
||||
@ -102,13 +101,7 @@ public class ConnectScheduler {
|
||||
// Check user
|
||||
connByUser.putIfAbsent(ctx.getQualifiedUser(), new AtomicInteger(0));
|
||||
AtomicInteger conns = connByUser.get(ctx.getQualifiedUser());
|
||||
if (ctx.getIsTempUser()) {
|
||||
if (conns.incrementAndGet() > LdapAuthenticate.getMaxConn()) {
|
||||
conns.decrementAndGet();
|
||||
numberConnection.decrementAndGet();
|
||||
return false;
|
||||
}
|
||||
} else if (conns.incrementAndGet() > ctx.getEnv().getAuth().getMaxConn(ctx.getQualifiedUser())) {
|
||||
if (conns.incrementAndGet() > ctx.getEnv().getAuth().getMaxConn(ctx.getQualifiedUser())) {
|
||||
conns.decrementAndGet();
|
||||
numberConnection.decrementAndGet();
|
||||
return false;
|
||||
|
||||
@ -25,7 +25,6 @@ import org.apache.doris.mysql.privilege.PaloAuth;
|
||||
import org.apache.doris.mysql.privilege.PaloRole;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import mockit.Delegate;
|
||||
import mockit.Expectations;
|
||||
import mockit.Mocked;
|
||||
@ -33,7 +32,6 @@ import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LdapAuthenticateTest {
|
||||
@ -45,7 +43,7 @@ public class LdapAuthenticateTest {
|
||||
private PaloRole ldapGroupsPrivs;
|
||||
|
||||
@Mocked
|
||||
private LdapClient ldapClient;
|
||||
private LdapManager ldapManager;
|
||||
@Mocked
|
||||
private LdapPrivsChecker ldapPrivsChecker;
|
||||
@Mocked
|
||||
@ -83,7 +81,7 @@ public class LdapAuthenticateTest {
|
||||
private void setCheckPassword(boolean res) {
|
||||
new Expectations() {
|
||||
{
|
||||
LdapClient.checkPassword(anyString, anyString);
|
||||
ldapManager.checkUserPasswd(anyString, anyString);
|
||||
minTimes = 0;
|
||||
result = res;
|
||||
}
|
||||
@ -93,45 +91,33 @@ public class LdapAuthenticateTest {
|
||||
private void setCheckPasswordException() {
|
||||
new Expectations() {
|
||||
{
|
||||
LdapClient.checkPassword(anyString, anyString);
|
||||
ldapManager.checkUserPasswd(anyString, anyString);
|
||||
minTimes = 0;
|
||||
result = new RuntimeException("exception");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setGetGroups(boolean res) {
|
||||
private void setGetUserInfo(boolean res) {
|
||||
new Expectations() {
|
||||
{
|
||||
if (res) {
|
||||
LdapClient.getGroups(anyString);
|
||||
ldapManager.getUserInfo(anyString);
|
||||
minTimes = 0;
|
||||
result = new Delegate() {
|
||||
List<String> fakeGetGroups(String user) {
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add(TABLE_RD);
|
||||
return list;
|
||||
LdapUserInfo fakeGetGroups(String user) {
|
||||
return new LdapUserInfo(anyString, false, "", new PaloRole(anyString));
|
||||
}
|
||||
};
|
||||
} else {
|
||||
LdapClient.getGroups(anyString);
|
||||
ldapManager.getUserInfo(anyString);
|
||||
minTimes = 0;
|
||||
result = Lists.newArrayList();
|
||||
result = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setGetGroupsException() {
|
||||
new Expectations() {
|
||||
{
|
||||
LdapClient.getGroups(anyString);
|
||||
minTimes = 0;
|
||||
result = new RuntimeException("exception");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setGetCurrentUserIdentity(boolean res) {
|
||||
new Expectations() {
|
||||
{
|
||||
@ -160,71 +146,54 @@ public class LdapAuthenticateTest {
|
||||
public void testAuthenticate() {
|
||||
ConnectContext context = getContext();
|
||||
setCheckPassword(true);
|
||||
setGetGroups(true);
|
||||
setGetUserInfo(true);
|
||||
setGetCurrentUserIdentity(true);
|
||||
String qualifiedUser = ClusterNamespace.getFullName(DEFAULT_CLUSTER, USER_NAME);
|
||||
Assert.assertTrue(LdapAuthenticate.authenticate(context, "123", qualifiedUser));
|
||||
Assert.assertFalse(context.getIsTempUser());
|
||||
Assert.assertSame(ldapGroupsPrivs, context.getLdapGroupsPrivs());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateWithWrongPassword() {
|
||||
ConnectContext context = getContext();
|
||||
setCheckPassword(false);
|
||||
setGetGroups(true);
|
||||
setGetUserInfo(true);
|
||||
setGetCurrentUserIdentity(true);
|
||||
String qualifiedUser = ClusterNamespace.getFullName(DEFAULT_CLUSTER, USER_NAME);
|
||||
Assert.assertFalse(LdapAuthenticate.authenticate(context, "123", qualifiedUser));
|
||||
Assert.assertFalse(context.getIsTempUser());
|
||||
Assert.assertNull(context.getLdapGroupsPrivs());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateWithCheckPasswordException() {
|
||||
ConnectContext context = getContext();
|
||||
setCheckPasswordException();
|
||||
setGetGroups(true);
|
||||
setGetUserInfo(true);
|
||||
setGetCurrentUserIdentity(true);
|
||||
String qualifiedUser = ClusterNamespace.getFullName(DEFAULT_CLUSTER, USER_NAME);
|
||||
Assert.assertFalse(LdapAuthenticate.authenticate(context, "123", qualifiedUser));
|
||||
Assert.assertFalse(context.getIsTempUser());
|
||||
Assert.assertNull(context.getLdapGroupsPrivs());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateGetGroupsNull() {
|
||||
ConnectContext context = getContext();
|
||||
setCheckPassword(true);
|
||||
setGetGroups(false);
|
||||
setGetUserInfo(false);
|
||||
setGetCurrentUserIdentity(true);
|
||||
String qualifiedUser = ClusterNamespace.getFullName(DEFAULT_CLUSTER, USER_NAME);
|
||||
Assert.assertTrue(LdapAuthenticate.authenticate(context, "123", qualifiedUser));
|
||||
Assert.assertFalse(context.getIsTempUser());
|
||||
Assert.assertNull(context.getLdapGroupsPrivs());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateGetGroupsException() {
|
||||
ConnectContext context = getContext();
|
||||
setCheckPassword(true);
|
||||
setGetGroupsException();
|
||||
setGetCurrentUserIdentity(true);
|
||||
String qualifiedUser = ClusterNamespace.getFullName(DEFAULT_CLUSTER, USER_NAME);
|
||||
Assert.assertFalse(LdapAuthenticate.authenticate(context, "123", qualifiedUser));
|
||||
Assert.assertFalse(context.getIsTempUser());
|
||||
Assert.assertNull(context.getLdapGroupsPrivs());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateUserNotExistInDoris() {
|
||||
ConnectContext context = getContext();
|
||||
setCheckPassword(true);
|
||||
setGetGroups(true);
|
||||
setGetUserInfo(true);
|
||||
setGetCurrentUserIdentity(false);
|
||||
String qualifiedUser = ClusterNamespace.getFullName(DEFAULT_CLUSTER, USER_NAME);
|
||||
Assert.assertTrue(LdapAuthenticate.authenticate(context, "123", qualifiedUser));
|
||||
Assert.assertTrue(context.getIsTempUser());
|
||||
Assert.assertSame(ldapGroupsPrivs, context.getLdapGroupsPrivs());
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +49,8 @@ public class LdapClientTest {
|
||||
|
||||
private LdapInfo ldapInfo = new LdapInfo(ADMIN_PASSWORD);
|
||||
|
||||
private LdapClient ldapClient = new LdapClient();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
new Expectations() {
|
||||
@ -96,7 +98,7 @@ public class LdapClientTest {
|
||||
if (passwd.equals(password)) {
|
||||
return;
|
||||
} else {
|
||||
throw new RuntimeException("exception");
|
||||
throw new org.springframework.ldap.AuthenticationException();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -109,13 +111,13 @@ public class LdapClientTest {
|
||||
List<String> list = Lists.newArrayList();
|
||||
list.add("zhangsan");
|
||||
mockLdapTemplateSearch(list);
|
||||
Assert.assertTrue(LdapClient.doesUserExist("zhangsan"));
|
||||
Assert.assertTrue(ldapClient.doesUserExist("zhangsan"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoesUserExistFail() {
|
||||
mockLdapTemplateSearch(null);
|
||||
Assert.assertFalse(LdapClient.doesUserExist("zhangsan"));
|
||||
Assert.assertFalse(ldapClient.doesUserExist("zhangsan"));
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
@ -124,15 +126,15 @@ public class LdapClientTest {
|
||||
list.add("zhangsan");
|
||||
list.add("zhangsan");
|
||||
mockLdapTemplateSearch(list);
|
||||
Assert.assertTrue(LdapClient.doesUserExist("zhangsan"));
|
||||
Assert.assertTrue(ldapClient.doesUserExist("zhangsan"));
|
||||
Assert.fail("No Exception throws.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckPassword() {
|
||||
mockLdapTemplateAuthenticate(ADMIN_PASSWORD);
|
||||
Assert.assertTrue(LdapClient.checkPassword("zhangsan", ADMIN_PASSWORD));
|
||||
Assert.assertFalse(LdapClient.checkPassword("zhangsan", "123"));
|
||||
Assert.assertTrue(ldapClient.checkPassword("zhangsan", ADMIN_PASSWORD));
|
||||
Assert.assertFalse(ldapClient.checkPassword("zhangsan", "123"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -140,6 +142,6 @@ public class LdapClientTest {
|
||||
List<String> list = Lists.newArrayList();
|
||||
list.add("cn=groupName,ou=groups,dc=example,dc=com");
|
||||
mockLdapTemplateSearch(list);
|
||||
Assert.assertEquals(1, LdapClient.getGroups("zhangsan").size());
|
||||
Assert.assertEquals(1, ldapClient.getGroups("zhangsan").size());
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
// 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.common.LdapConfig;
|
||||
|
||||
import mockit.Expectations;
|
||||
import mockit.Mocked;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class LdapManagerTest {
|
||||
|
||||
private static final String USER1 = "default_cluster:user1";
|
||||
private static final String USER2 = "default_cluster:user2";
|
||||
|
||||
@Mocked
|
||||
private LdapClient ldapClient;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
LdapConfig.ldap_authentication_enabled = true;
|
||||
}
|
||||
|
||||
private void mockClient(boolean userExist, boolean passwd) {
|
||||
new Expectations() {
|
||||
{
|
||||
ldapClient.doesUserExist(anyString);
|
||||
minTimes = 0;
|
||||
result = userExist;
|
||||
|
||||
ldapClient.checkPassword(anyString, anyString);
|
||||
minTimes = 0;
|
||||
result = passwd;
|
||||
|
||||
ldapClient.getGroups(anyString);
|
||||
minTimes = 0;
|
||||
result = new ArrayList<>();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUserInfo() {
|
||||
LdapManager ldapManager = new LdapManager();
|
||||
mockClient(true, true);
|
||||
LdapUserInfo ldapUserInfo = ldapManager.getUserInfo(USER1);
|
||||
Assert.assertNotNull(ldapUserInfo);
|
||||
String paloRoleString = ldapUserInfo.getPaloRole().toString();
|
||||
Assert.assertTrue(paloRoleString.contains("information_schema"));
|
||||
Assert.assertTrue(paloRoleString.contains("Select_priv"));
|
||||
|
||||
mockClient(false, false);
|
||||
Assert.assertNull(ldapManager.getUserInfo(USER2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckUserPasswd() {
|
||||
LdapManager ldapManager = new LdapManager();
|
||||
mockClient(true, true);
|
||||
Assert.assertTrue(ldapManager.checkUserPasswd(USER1, "123"));
|
||||
LdapUserInfo ldapUserInfo = ldapManager.getUserInfo(USER1);
|
||||
Assert.assertNotNull(ldapUserInfo);
|
||||
Assert.assertTrue(ldapUserInfo.isSetPasswd());
|
||||
Assert.assertEquals("123", ldapUserInfo.getPasswd());
|
||||
|
||||
mockClient(true, false);
|
||||
Assert.assertFalse(ldapManager.checkUserPasswd(USER2, "123"));
|
||||
}
|
||||
}
|
||||
@ -20,9 +20,11 @@ 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.PaloAuth;
|
||||
import org.apache.doris.mysql.privilege.PaloPrivilege;
|
||||
import org.apache.doris.mysql.privilege.PaloRole;
|
||||
import org.apache.doris.mysql.privilege.PrivBitSet;
|
||||
@ -53,6 +55,15 @@ public class LdapPrivsCheckerTest {
|
||||
@Mocked
|
||||
private ConnectContext context;
|
||||
|
||||
@Mocked
|
||||
private Env env;
|
||||
|
||||
@Mocked
|
||||
private PaloAuth paloAuth;
|
||||
|
||||
@Mocked
|
||||
private LdapManager ldapManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
LdapConfig.ldap_authentication_enabled = true;
|
||||
@ -62,6 +73,18 @@ public class LdapPrivsCheckerTest {
|
||||
minTimes = 0;
|
||||
result = context;
|
||||
|
||||
Env.getCurrentEnv();
|
||||
minTimes = 0;
|
||||
result = env;
|
||||
|
||||
env.getAuth();
|
||||
minTimes = 0;
|
||||
result = paloAuth;
|
||||
|
||||
paloAuth.getLdapManager();
|
||||
minTimes = 0;
|
||||
result = ldapManager;
|
||||
|
||||
PaloRole role = new PaloRole("");
|
||||
Map<TablePattern, PrivBitSet> tblPatternToPrivs = role.getTblPatternToPrivs();
|
||||
|
||||
@ -91,13 +114,20 @@ public class LdapPrivsCheckerTest {
|
||||
} catch (AnalysisException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
context.getLdapGroupsPrivs();
|
||||
|
||||
UserIdentity userIdentity = UserIdentity.createAnalyzedUserIdentWithIp(USER, IP);
|
||||
|
||||
ldapManager.getUserInfo(userIdentity.getQualifiedUser());
|
||||
minTimes = 0;
|
||||
result = role;
|
||||
result = new LdapUserInfo(userIdentity.getQualifiedUser(), false, "", role);
|
||||
|
||||
ldapManager.doesUserExist(userIdentity.getQualifiedUser());
|
||||
minTimes = 0;
|
||||
result = true;
|
||||
|
||||
context.getCurrentUserIdentity();
|
||||
minTimes = 0;
|
||||
result = UserIdentity.createAnalyzedUserIdentWithIp(USER, IP);
|
||||
result = userIdentity;
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -167,15 +197,6 @@ public class LdapPrivsCheckerTest {
|
||||
Assert.assertTrue(LdapPrivsChecker.hasPrivsOfDb(userIdent, CLUSTER + ":" + TABLE_DB));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsCurrentUser() {
|
||||
Assert.assertTrue(LdapPrivsChecker.isCurrentUser(userIdent));
|
||||
Assert.assertFalse(LdapPrivsChecker.isCurrentUser(
|
||||
UserIdentity.createAnalyzedUserIdentWithIp("default_cluster:lisi", IP)));
|
||||
Assert.assertFalse(LdapPrivsChecker.isCurrentUser(
|
||||
UserIdentity.createAnalyzedUserIdentWithIp(USER, "127.0.0.1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLdapAllDbPrivs() throws AnalysisException {
|
||||
Map<TablePattern, PrivBitSet> allDb = LdapPrivsChecker.getLdapAllDbPrivs(userIdent);
|
||||
|
||||
@ -25,7 +25,7 @@ import org.apache.doris.common.DdlException;
|
||||
import org.apache.doris.common.LdapConfig;
|
||||
import org.apache.doris.datasource.InternalCatalog;
|
||||
import org.apache.doris.ldap.LdapAuthenticate;
|
||||
import org.apache.doris.ldap.LdapClient;
|
||||
import org.apache.doris.ldap.LdapManager;
|
||||
import org.apache.doris.mysql.privilege.PaloAuth;
|
||||
import org.apache.doris.mysql.privilege.PrivPredicate;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
@ -58,7 +58,7 @@ public class MysqlProtoTest {
|
||||
@Mocked
|
||||
private PaloAuth auth;
|
||||
@Mocked
|
||||
private LdapClient ldapClient;
|
||||
private LdapManager ldapManager;
|
||||
@Mocked
|
||||
private LdapAuthenticate ldapAuthenticate;
|
||||
@Mocked
|
||||
@ -219,7 +219,11 @@ public class MysqlProtoTest {
|
||||
}
|
||||
};
|
||||
|
||||
LdapClient.doesUserExist(anyString);
|
||||
ldapManager.checkUserPasswd(anyString, anyString);
|
||||
minTimes = 0;
|
||||
result = userExist;
|
||||
|
||||
ldapManager.doesUserExist(anyString);
|
||||
minTimes = 0;
|
||||
result = userExist;
|
||||
}
|
||||
@ -276,6 +280,7 @@ public class MysqlProtoTest {
|
||||
context.setEnv(env);
|
||||
context.setThreadLocalInfo();
|
||||
Assert.assertTrue(MysqlProto.negotiate(context));
|
||||
LdapConfig.ldap_authentication_enabled = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -289,6 +294,7 @@ public class MysqlProtoTest {
|
||||
context.setEnv(env);
|
||||
context.setThreadLocalInfo();
|
||||
Assert.assertFalse(MysqlProto.negotiate(context));
|
||||
LdapConfig.ldap_authentication_enabled = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -302,6 +308,7 @@ public class MysqlProtoTest {
|
||||
context.setEnv(env);
|
||||
context.setThreadLocalInfo();
|
||||
Assert.assertTrue(MysqlProto.negotiate(context));
|
||||
LdapConfig.ldap_authentication_enabled = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user