Skip to content

Commit

Permalink
[enhancement](ldap) Support refresh ldap cache
Browse files Browse the repository at this point in the history
  • Loading branch information
luozenglin committed May 29, 2023
1 parent f9478db commit b355609
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 19 deletions.
11 changes: 11 additions & 0 deletions fe/fe-core/src/main/cup/sql_parser.cup
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ terminal String
KW_LARGEINT,
KW_LAST,
KW_LATERAL,
KW_LDAP,
KW_LDAP_ADMIN_PASSWORD,
KW_LEFT,
KW_LESS,
Expand Down Expand Up @@ -1197,6 +1198,14 @@ refresh_stmt ::=
{:
RESULT = new RefreshCatalogStmt(catalogName, properties);
:}
| KW_REFRESH KW_LDAP KW_ALL
{:
RESULT = new RefreshLdapStmt(true, "");
:}
| KW_REFRESH KW_LDAP opt_user:user
{:
RESULT = new RefreshLdapStmt(false, user);
:}
;

clean_stmt ::=
Expand Down Expand Up @@ -7340,6 +7349,8 @@ keyword ::=
{: RESULT = id; :}
| KW_PASSWORD_LOCK_TIME:id
{: RESULT = id; :}
| KW_LDAP:id
{: RESULT = id; :}
| KW_LDAP_ADMIN_PASSWORD:id
{: RESULT = id; :}
| KW_PLUGIN:id
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// 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.analysis;

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.UserException;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;

import com.google.common.base.Strings;

public class RefreshLdapStmt extends DdlStmt {

private boolean isAll;

private String user;

RefreshLdapStmt(boolean isAll, String user) {
this.isAll = isAll;
this.user = user;
}

public boolean getIsAll() {
return isAll;
}

public String getUser() {
return user;
}

@Override
public void analyze(Analyzer analyzer) throws UserException {
super.analyze(analyzer);
if (Strings.isNullOrEmpty(user)) {
user = analyzer.getQualifiedUser();
} else {
user = ClusterNamespace.getFullName(getClusterName(), user);

if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.ADMIN)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "ADMIN");
}
}
}

@Override
public String toSql() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("REFRESH LDAP ");
if (isAll) {
stringBuilder.append("ALL");
} else {
stringBuilder.append("`").append(user).append("`");
}
return stringBuilder.toString();
}

}
40 changes: 28 additions & 12 deletions fe/fe-core/src/main/java/org/apache/doris/ldap/LdapManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
public class LdapManager {
private static final Logger LOG = LogManager.getLogger(LdapManager.class);

private static final String LDAP_GROUPS_PRIVS_NAME = "ldapGroupsPrivs";
public static final String LDAP_GROUPS_PRIVS_NAME = "ldapGroupsPrivs";

private final LdapClient ldapClient = new LdapClient();

Expand Down Expand Up @@ -89,7 +89,8 @@ public boolean doesUserExist(String fullName) {
if (!checkParam(fullName)) {
return false;
}
return !Objects.isNull(getUserInfo(fullName));
LdapUserInfo info = getUserInfo(fullName);
return !Objects.isNull(info) && info.isExists();
}

public boolean checkUserPasswd(String fullName, String passwd) {
Expand All @@ -98,7 +99,7 @@ public boolean checkUserPasswd(String fullName, String passwd) {
return false;
}
LdapUserInfo ldapUserInfo = getUserInfo(fullName);
if (Objects.isNull(ldapUserInfo)) {
if (Objects.isNull(ldapUserInfo) || !ldapUserInfo.isExists()) {
return false;
}

Expand All @@ -121,6 +122,11 @@ public boolean checkUserPasswd(String fullName, String passwd, String remoteIp,
return false;
}

public Role getUserRole(String fullName) {
LdapUserInfo info = getUserInfo(fullName);
return !Objects.isNull(info) && info.isExists() ? info.getPaloRole() : new Role(LDAP_GROUPS_PRIVS_NAME);
}

private boolean checkParam(String fullName) {
return LdapConfig.ldap_authentication_enabled && !Strings.isNullOrEmpty(fullName) && !fullName.equalsIgnoreCase(
Auth.ROOT_USER) && !fullName.equalsIgnoreCase(Auth.ADMIN_USER);
Expand All @@ -132,8 +138,7 @@ private LdapUserInfo getUserInfoAndUpdateCache(String fulName) throws DdlExcepti
if (Strings.isNullOrEmpty(userName)) {
return null;
} else if (!ldapClient.doesUserExist(userName)) {
removeUserIfExist(fulName);
return null;
return makeUserNotExists(fulName);
}
checkTimeoutCleanCache();

Expand All @@ -157,15 +162,10 @@ private void updatePasswd(LdapUserInfo ldapUserInfo, String passwd) {
}
}

private void removeUserIfExist(String fullName) {
LdapUserInfo ldapUserInfo = getUserInfoFromCache(fullName);
if (ldapUserInfo == null) {
return;
}

private LdapUserInfo makeUserNotExists(String fullName) {
writeLock();
try {
ldapUserInfoCache.remove(ldapUserInfo.getUserName());
return ldapUserInfoCache.put(fullName, new LdapUserInfo(fullName));
} finally {
writeUnlock();
}
Expand Down Expand Up @@ -219,4 +219,20 @@ private Role getLdapGroupsPrivs(String userName, String clusterName) throws DdlE
}
return ldapGroupsPrivs;
}

public void refresh(boolean isAll, String fullName) {
writeLock();
try {
if (isAll) {
ldapUserInfoCache.clear();
lastTimestamp = System.currentTimeMillis();
LOG.info("refreshed all ldap info.");
} else {
ldapUserInfoCache.remove(fullName);
LOG.info("refreshed ldap info for " + fullName);
}
} finally {
writeUnlock();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public static Map<ResourcePattern, PrivBitSet> getLdapAllResourcePrivs(UserIdent
}

private static Role getUserLdapPrivs(String fullName) {
return Env.getCurrentEnv().getAuth().getLdapManager().getUserInfo(fullName).getPaloRole();
return Env.getCurrentEnv().getAuth().getLdapManager().getUserRole(fullName);
}

// Temporary user has information_schema 'Select_priv' priv by default.
Expand Down
17 changes: 17 additions & 0 deletions fe/fe-core/src/main/java/org/apache/doris/ldap/LdapUserInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
public class LdapUserInfo {
public LdapUserInfo(String userName, boolean isSetPasswd, String passwd, Role role) {
this.userName = userName;
this.isExists = true;
this.isSetPasswd = isSetPasswd;
this.passwd = passwd;
this.role = role;
Expand All @@ -36,14 +37,26 @@ public LdapUserInfo(String userName, boolean isSetPasswd, String passwd, Role ro

private LdapUserInfo(String userName, boolean isSetPasswd, String passwd, Role role, long lastTimeStamp) {
this.userName = userName;
this.isExists = true;
this.isSetPasswd = isSetPasswd;
this.passwd = passwd;
this.role = role;
this.lastTimeStamp = lastTimeStamp;
}

public LdapUserInfo(String notExistsUserName) {
this.userName = notExistsUserName;
this.isExists = false;
this.isSetPasswd = false;
this.passwd = null;
this.role = null;
this.lastTimeStamp = System.currentTimeMillis();
}

private final String userName;

private final boolean isExists;

private final boolean isSetPasswd;

private final String passwd;
Expand All @@ -69,6 +82,10 @@ public Role getPaloRole() {
return role;
}

public boolean isExists() {
return isExists;
}

public LdapUserInfo cloneWithPasswd(String passwd) {
if (Objects.isNull(passwd)) {
return new LdapUserInfo(userName, isSetPasswd, this.passwd, role, lastTimeStamp);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.doris.analysis.DropUserStmt;
import org.apache.doris.analysis.GrantStmt;
import org.apache.doris.analysis.PasswordOptions;
import org.apache.doris.analysis.RefreshLdapStmt;
import org.apache.doris.analysis.ResourcePattern;
import org.apache.doris.analysis.RevokeStmt;
import org.apache.doris.analysis.SetLdapPassVar;
Expand Down Expand Up @@ -770,6 +771,10 @@ public void replaySetLdapPassword(LdapInfo info) {
LOG.debug("finish replaying ldap admin password.");
}

public void refreshLdap(RefreshLdapStmt refreshLdapStmt) {
ldapManager.refresh(refreshLdapStmt.getIsAll(), refreshLdapStmt.getUser());
}

// create role
public void createRole(CreateRoleStmt stmt) throws DdlException {
createRoleInternal(stmt.getQualifiedRole(), stmt.isSetIfNotExists(), false);
Expand Down Expand Up @@ -1082,7 +1087,7 @@ private GlobalPrivTable getUserGlobalPrivTable(UserIdentity userIdentity) {
table.merge(roleManager.getRole(roleName).getGlobalPrivTable());
}
if (isLdapAuthEnabled() && ldapManager.doesUserExist(userIdentity.getQualifiedUser())) {
table.merge(ldapManager.getUserInfo(userIdentity.getQualifiedUser()).getPaloRole().getGlobalPrivTable());
table.merge(ldapManager.getUserRole(userIdentity.getQualifiedUser()).getGlobalPrivTable());
}
return table;
}
Expand All @@ -1094,7 +1099,7 @@ private CatalogPrivTable getUserCtlPrivTable(UserIdentity userIdentity) {
table.merge(roleManager.getRole(roleName).getCatalogPrivTable());
}
if (isLdapAuthEnabled() && ldapManager.doesUserExist(userIdentity.getQualifiedUser())) {
table.merge(ldapManager.getUserInfo(userIdentity.getQualifiedUser()).getPaloRole().getCatalogPrivTable());
table.merge(ldapManager.getUserRole(userIdentity.getQualifiedUser()).getCatalogPrivTable());
}
return table;
}
Expand All @@ -1106,7 +1111,7 @@ private DbPrivTable getUserDbPrivTable(UserIdentity userIdentity) {
table.merge(roleManager.getRole(roleName).getDbPrivTable());
}
if (isLdapAuthEnabled() && ldapManager.doesUserExist(userIdentity.getQualifiedUser())) {
table.merge(ldapManager.getUserInfo(userIdentity.getQualifiedUser()).getPaloRole().getDbPrivTable());
table.merge(ldapManager.getUserRole(userIdentity.getQualifiedUser()).getDbPrivTable());
}
return table;
}
Expand All @@ -1118,7 +1123,7 @@ private TablePrivTable getUserTblPrivTable(UserIdentity userIdentity) {
table.merge(roleManager.getRole(roleName).getTablePrivTable());
}
if (isLdapAuthEnabled() && ldapManager.doesUserExist(userIdentity.getQualifiedUser())) {
table.merge(ldapManager.getUserInfo(userIdentity.getQualifiedUser()).getPaloRole().getTablePrivTable());
table.merge(ldapManager.getUserRole(userIdentity.getQualifiedUser()).getTablePrivTable());
}
return table;
}
Expand All @@ -1130,7 +1135,7 @@ private ResourcePrivTable getUserResourcePrivTable(UserIdentity userIdentity) {
table.merge(roleManager.getRole(roleName).getResourcePrivTable());
}
if (isLdapAuthEnabled() && ldapManager.doesUserExist(userIdentity.getQualifiedUser())) {
table.merge(ldapManager.getUserInfo(userIdentity.getQualifiedUser()).getPaloRole().getResourcePrivTable());
table.merge(ldapManager.getUserRole(userIdentity.getQualifiedUser()).getResourcePrivTable());
}
return table;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ private void checkPasswordInternal(String remoteUser, String remoteHost, byte[]

public List<UserIdentity> getUserIdentityUncheckPasswd(String remoteUser, String remoteHost) {
List<UserIdentity> userIdentities = Lists.newArrayList();
List<User> users = nameToUsers.get(remoteUser);
List<User> users = nameToUsers.getOrDefault(remoteUser, Lists.newArrayList());
for (User user : users) {
if (!user.getUserIdentity().isDomain() && (user.isAnyHost() || user.getHostPattern().match(remoteHost))) {
userIdentities.add(user.getUserIdentity());
Expand Down
3 changes: 3 additions & 0 deletions fe/fe-core/src/main/java/org/apache/doris/qe/DdlExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
import org.apache.doris.analysis.RecoverTableStmt;
import org.apache.doris.analysis.RefreshCatalogStmt;
import org.apache.doris.analysis.RefreshDbStmt;
import org.apache.doris.analysis.RefreshLdapStmt;
import org.apache.doris.analysis.RefreshMaterializedViewStmt;
import org.apache.doris.analysis.RefreshTableStmt;
import org.apache.doris.analysis.RestoreStmt;
Expand Down Expand Up @@ -324,6 +325,8 @@ public static void execute(Env env, DdlStmt ddlStmt) throws Exception {
env.refreshMaterializedView((RefreshMaterializedViewStmt) ddlStmt);
} else if (ddlStmt instanceof RefreshCatalogStmt) {
env.getCatalogMgr().refreshCatalog((RefreshCatalogStmt) ddlStmt);
} else if (ddlStmt instanceof RefreshLdapStmt) {
env.getAuth().refreshLdap((RefreshLdapStmt) ddlStmt);
} else if (ddlStmt instanceof AlterUserStmt) {
env.getAuth().alterUser((AlterUserStmt) ddlStmt);
} else if (ddlStmt instanceof CleanProfileStmt) {
Expand Down
1 change: 1 addition & 0 deletions fe/fe-core/src/main/jflex/sql_scanner.flex
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ import org.apache.doris.qe.SqlModeHelper;
keywordMap.put("largeint", new Integer(SqlParserSymbols.KW_LARGEINT));
keywordMap.put("last", new Integer(SqlParserSymbols.KW_LAST));
keywordMap.put("lateral", new Integer(SqlParserSymbols.KW_LATERAL));
keywordMap.put("ldap", new Integer(SqlParserSymbols.KW_LDAP));
keywordMap.put("ldap_admin_password", new Integer(SqlParserSymbols.KW_LDAP_ADMIN_PASSWORD));
keywordMap.put("left", new Integer(SqlParserSymbols.KW_LEFT));
keywordMap.put("less", new Integer(SqlParserSymbols.KW_LESS));
Expand Down

0 comments on commit b355609

Please sign in to comment.