bp #33668 Co-authored-by: zhangdong <493738387@qq.com>
This commit is contained in:
@ -24,7 +24,7 @@ import org.apache.doris.common.ErrorCode;
|
||||
import org.apache.doris.common.ErrorReport;
|
||||
import org.apache.doris.common.FeNameFormat;
|
||||
import org.apache.doris.common.UserException;
|
||||
import org.apache.doris.mysql.authenticate.MysqlAuthType;
|
||||
import org.apache.doris.mysql.authenticate.AuthenticateType;
|
||||
import org.apache.doris.mysql.privilege.PrivPredicate;
|
||||
import org.apache.doris.mysql.privilege.Role;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
@ -120,7 +120,7 @@ public class CreateUserStmt extends DdlStmt {
|
||||
super.analyze(analyzer);
|
||||
|
||||
if (Config.access_controller_type.equalsIgnoreCase("ranger-doris")
|
||||
&& MysqlAuthType.getAuthTypeConfig() == MysqlAuthType.LDAP) {
|
||||
&& AuthenticateType.getAuthTypeConfig() == AuthenticateType.LDAP) {
|
||||
throw new AnalysisException("Create user is prohibited when Ranger and LDAP are enabled at same time.");
|
||||
}
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ import org.apache.doris.common.Config;
|
||||
import org.apache.doris.common.ErrorCode;
|
||||
import org.apache.doris.common.ErrorReport;
|
||||
import org.apache.doris.common.UserException;
|
||||
import org.apache.doris.mysql.authenticate.MysqlAuthType;
|
||||
import org.apache.doris.mysql.authenticate.AuthenticateType;
|
||||
import org.apache.doris.mysql.privilege.PrivPredicate;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
@ -57,7 +57,7 @@ public class DropUserStmt extends DdlStmt {
|
||||
super.analyze(analyzer);
|
||||
|
||||
if (Config.access_controller_type.equalsIgnoreCase("ranger-doris")
|
||||
&& MysqlAuthType.getAuthTypeConfig() == MysqlAuthType.LDAP) {
|
||||
&& AuthenticateType.getAuthTypeConfig() == AuthenticateType.LDAP) {
|
||||
throw new AnalysisException("Drop user is prohibited when Ranger and LDAP are enabled at same time.");
|
||||
}
|
||||
|
||||
|
||||
@ -183,6 +183,8 @@ import org.apache.doris.mtmv.MTMVRefreshPartitionSnapshot;
|
||||
import org.apache.doris.mtmv.MTMVRelation;
|
||||
import org.apache.doris.mtmv.MTMVService;
|
||||
import org.apache.doris.mtmv.MTMVStatus;
|
||||
import org.apache.doris.mysql.authenticate.AuthenticateType;
|
||||
import org.apache.doris.mysql.authenticate.AuthenticatorManager;
|
||||
import org.apache.doris.mysql.privilege.AccessControllerManager;
|
||||
import org.apache.doris.mysql.privilege.Auth;
|
||||
import org.apache.doris.mysql.privilege.PrivPredicate;
|
||||
@ -454,6 +456,8 @@ public class Env {
|
||||
private Auth auth;
|
||||
private AccessControllerManager accessManager;
|
||||
|
||||
private AuthenticatorManager authenticatorManager;
|
||||
|
||||
private DomainResolver domainResolver;
|
||||
|
||||
private TabletSchedulerStat stat;
|
||||
@ -701,6 +705,7 @@ public class Env {
|
||||
|
||||
this.auth = new Auth();
|
||||
this.accessManager = new AccessControllerManager(auth);
|
||||
this.authenticatorManager = new AuthenticatorManager(AuthenticateType.getAuthTypeConfig());
|
||||
this.domainResolver = new DomainResolver(auth);
|
||||
|
||||
this.metaContext = new MetaContext();
|
||||
@ -825,6 +830,10 @@ public class Env {
|
||||
return accessManager;
|
||||
}
|
||||
|
||||
public AuthenticatorManager getAuthenticatorManager() {
|
||||
return authenticatorManager;
|
||||
}
|
||||
|
||||
public MTMVService getMtmvService() {
|
||||
return mtmvService;
|
||||
}
|
||||
|
||||
@ -23,7 +23,6 @@ import org.apache.doris.common.DdlException;
|
||||
import org.apache.doris.common.ErrorCode;
|
||||
import org.apache.doris.common.ErrorReport;
|
||||
import org.apache.doris.datasource.CatalogIf;
|
||||
import org.apache.doris.mysql.authenticate.MysqlAuth;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
@ -194,7 +193,8 @@ public class MysqlProto {
|
||||
}
|
||||
|
||||
// authenticate
|
||||
if (!MysqlAuth.authenticate(context, qualifiedUser, channel, serializer, authPacket, handshakePacket)) {
|
||||
if (!Env.getCurrentEnv().getAuthenticatorManager()
|
||||
.authenticate(context, qualifiedUser, channel, serializer, authPacket, handshakePacket)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.mysql.authenticate;
|
||||
|
||||
import org.apache.doris.mysql.authenticate.password.Password;
|
||||
|
||||
public class AuthenticateRequest {
|
||||
private String userName;
|
||||
private Password password;
|
||||
private String remoteIp;
|
||||
|
||||
public AuthenticateRequest(String userName, Password password, String remoteIp) {
|
||||
this.userName = userName;
|
||||
this.password = password;
|
||||
this.remoteIp = remoteIp;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public Password getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public String getRemoteIp() {
|
||||
return remoteIp;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.mysql.authenticate;
|
||||
|
||||
import org.apache.doris.analysis.UserIdentity;
|
||||
|
||||
public class AuthenticateResponse {
|
||||
public static AuthenticateResponse failedResponse = new AuthenticateResponse(false);
|
||||
|
||||
private boolean success;
|
||||
private UserIdentity userIdentity;
|
||||
private boolean isTemp = false;
|
||||
|
||||
public AuthenticateResponse(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public AuthenticateResponse(boolean success, UserIdentity userIdentity) {
|
||||
this.success = success;
|
||||
this.userIdentity = userIdentity;
|
||||
}
|
||||
|
||||
public AuthenticateResponse(boolean success, UserIdentity userIdentity, boolean isTemp) {
|
||||
this.success = success;
|
||||
this.userIdentity = userIdentity;
|
||||
this.isTemp = isTemp;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public UserIdentity getUserIdentity() {
|
||||
return userIdentity;
|
||||
}
|
||||
|
||||
public void setUserIdentity(UserIdentity userIdentity) {
|
||||
this.userIdentity = userIdentity;
|
||||
}
|
||||
|
||||
public boolean isTemp() {
|
||||
return isTemp;
|
||||
}
|
||||
|
||||
public void setTemp(boolean temp) {
|
||||
isTemp = temp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AuthenticateResponse{"
|
||||
+ "success=" + success
|
||||
+ ", userIdentity=" + userIdentity
|
||||
+ ", isTemp=" + isTemp
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@ -19,11 +19,11 @@ package org.apache.doris.mysql.authenticate;
|
||||
|
||||
import org.apache.doris.common.Config;
|
||||
|
||||
public enum MysqlAuthType {
|
||||
public enum AuthenticateType {
|
||||
DEFAULT,
|
||||
LDAP;
|
||||
|
||||
public static MysqlAuthType getAuthTypeConfig() {
|
||||
public static AuthenticateType getAuthTypeConfig() {
|
||||
switch (Config.authentication_type.toLowerCase()) {
|
||||
case "default":
|
||||
return DEFAULT;
|
||||
@ -0,0 +1,30 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.mysql.authenticate;
|
||||
|
||||
import org.apache.doris.mysql.authenticate.password.PasswordResolver;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Authenticator {
|
||||
AuthenticateResponse authenticate(AuthenticateRequest request) throws IOException;
|
||||
|
||||
boolean canDeal(String qualifiedUser);
|
||||
|
||||
PasswordResolver getPasswordResolver();
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.mysql.authenticate;
|
||||
|
||||
import org.apache.doris.mysql.MysqlAuthPacket;
|
||||
import org.apache.doris.mysql.MysqlChannel;
|
||||
import org.apache.doris.mysql.MysqlHandshakePacket;
|
||||
import org.apache.doris.mysql.MysqlProto;
|
||||
import org.apache.doris.mysql.MysqlSerializer;
|
||||
import org.apache.doris.mysql.authenticate.ldap.LdapAuthenticator;
|
||||
import org.apache.doris.mysql.authenticate.password.Password;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
public class AuthenticatorManager {
|
||||
private static final Logger LOG = LogManager.getLogger(AuthenticatorManager.class);
|
||||
|
||||
private Authenticator defaultAuthenticator;
|
||||
private Authenticator authTypeAuthenticator;
|
||||
|
||||
public AuthenticatorManager(AuthenticateType type) {
|
||||
LOG.info("authenticate type: {}", type);
|
||||
this.defaultAuthenticator = new DefaultAuthenticator();
|
||||
switch (type) {
|
||||
case LDAP:
|
||||
this.authTypeAuthenticator = new LdapAuthenticator();
|
||||
break;
|
||||
case DEFAULT:
|
||||
default:
|
||||
this.authTypeAuthenticator = defaultAuthenticator;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean authenticate(ConnectContext context,
|
||||
String userName,
|
||||
MysqlChannel channel,
|
||||
MysqlSerializer serializer,
|
||||
MysqlAuthPacket authPacket,
|
||||
MysqlHandshakePacket handshakePacket) throws IOException {
|
||||
Authenticator authenticator = chooseAuthenticator(userName);
|
||||
Optional<Password> password = authenticator.getPasswordResolver()
|
||||
.resolvePassword(context, channel, serializer, authPacket, handshakePacket);
|
||||
if (!password.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
String remoteIp = context.getMysqlChannel().getRemoteIp();
|
||||
AuthenticateRequest request = new AuthenticateRequest(userName, password.get(), remoteIp);
|
||||
AuthenticateResponse response = authenticator.authenticate(request);
|
||||
if (!response.isSuccess()) {
|
||||
MysqlProto.sendResponsePacket(context);
|
||||
return false;
|
||||
}
|
||||
context.setCurrentUserIdentity(response.getUserIdentity());
|
||||
context.setRemoteIP(remoteIp);
|
||||
context.setIsTempUser(response.isTemp());
|
||||
return true;
|
||||
}
|
||||
|
||||
private Authenticator chooseAuthenticator(String userName) {
|
||||
return authTypeAuthenticator.canDeal(userName) ? authTypeAuthenticator : defaultAuthenticator;
|
||||
}
|
||||
}
|
||||
@ -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.mysql.authenticate;
|
||||
|
||||
import org.apache.doris.analysis.UserIdentity;
|
||||
import org.apache.doris.catalog.Env;
|
||||
import org.apache.doris.common.AuthenticationException;
|
||||
import org.apache.doris.common.ErrorReport;
|
||||
import org.apache.doris.mysql.authenticate.password.NativePassword;
|
||||
import org.apache.doris.mysql.authenticate.password.NativePasswordResolver;
|
||||
import org.apache.doris.mysql.authenticate.password.Password;
|
||||
import org.apache.doris.mysql.authenticate.password.PasswordResolver;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class DefaultAuthenticator implements Authenticator {
|
||||
private static final Logger LOG = LogManager.getLogger(DefaultAuthenticator.class);
|
||||
private PasswordResolver passwordResolver;
|
||||
|
||||
public DefaultAuthenticator() {
|
||||
this.passwordResolver = new NativePasswordResolver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticateResponse authenticate(AuthenticateRequest request) throws IOException {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("user:{} start to default authenticate.", request.getUserName());
|
||||
}
|
||||
Password password = request.getPassword();
|
||||
if (!(password instanceof NativePassword)) {
|
||||
return AuthenticateResponse.failedResponse;
|
||||
}
|
||||
NativePassword nativePassword = (NativePassword) password;
|
||||
|
||||
List<UserIdentity> currentUserIdentity = Lists.newArrayList();
|
||||
try {
|
||||
Env.getCurrentEnv().getAuth().checkPassword(request.getUserName(), request.getRemoteIp(),
|
||||
nativePassword.getRemotePasswd(), nativePassword.getRandomString(), currentUserIdentity);
|
||||
} catch (AuthenticationException e) {
|
||||
ErrorReport.report(e.errorCode, e.msgs);
|
||||
return AuthenticateResponse.failedResponse;
|
||||
}
|
||||
return new AuthenticateResponse(true, currentUserIdentity.get(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDeal(String qualifiedUser) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PasswordResolver getPasswordResolver() {
|
||||
return passwordResolver;
|
||||
}
|
||||
}
|
||||
@ -1,205 +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.mysql.authenticate;
|
||||
|
||||
import org.apache.doris.analysis.UserIdentity;
|
||||
import org.apache.doris.catalog.Env;
|
||||
import org.apache.doris.common.AuthenticationException;
|
||||
import org.apache.doris.common.Config;
|
||||
import org.apache.doris.common.ErrorCode;
|
||||
import org.apache.doris.common.ErrorReport;
|
||||
import org.apache.doris.mysql.MysqlAuthPacket;
|
||||
import org.apache.doris.mysql.MysqlAuthSwitchPacket;
|
||||
import org.apache.doris.mysql.MysqlChannel;
|
||||
import org.apache.doris.mysql.MysqlClearTextPacket;
|
||||
import org.apache.doris.mysql.MysqlHandshakePacket;
|
||||
import org.apache.doris.mysql.MysqlProto;
|
||||
import org.apache.doris.mysql.MysqlSerializer;
|
||||
import org.apache.doris.mysql.authenticate.ldap.LdapAuthenticate;
|
||||
import org.apache.doris.mysql.privilege.Auth;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class MysqlAuth {
|
||||
private static final Logger LOG = LogManager.getLogger(MysqlAuth.class);
|
||||
|
||||
// scramble: data receive from server.
|
||||
// randomString: data send by server in plugin data field
|
||||
// user_name#HIGH@cluster_name
|
||||
private static boolean internalAuthenticate(ConnectContext context, byte[] scramble,
|
||||
byte[] randomString, String qualifiedUser) {
|
||||
String remoteIp = context.getMysqlChannel().getRemoteIp();
|
||||
List<UserIdentity> currentUserIdentity = Lists.newArrayList();
|
||||
|
||||
try {
|
||||
Env.getCurrentEnv().getAuth().checkPassword(qualifiedUser, remoteIp,
|
||||
scramble, randomString, currentUserIdentity);
|
||||
} catch (AuthenticationException e) {
|
||||
ErrorReport.report(e.errorCode, e.msgs);
|
||||
return false;
|
||||
}
|
||||
|
||||
context.setCurrentUserIdentity(currentUserIdentity.get(0));
|
||||
context.setRemoteIP(remoteIp);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Default auth uses doris internal user system to authenticate.
|
||||
private static boolean defaultAuth(
|
||||
ConnectContext context,
|
||||
String qualifiedUser,
|
||||
MysqlChannel channel,
|
||||
MysqlSerializer serializer,
|
||||
MysqlAuthPacket authPacket,
|
||||
MysqlHandshakePacket handshakePacket) throws IOException {
|
||||
// Starting with MySQL 8.0.4, MySQL changed the default authentication plugin for MySQL client
|
||||
// from mysql_native_password to caching_sha2_password.
|
||||
// ref: https://mysqlserverteam.com/mysql-8-0-4-new-default-authentication-plugin-caching_sha2_password/
|
||||
// So, User use mysql client or ODBC Driver after 8.0.4 have problem to connect to Doris
|
||||
// with password.
|
||||
// So Doris support the Protocol::AuthSwitchRequest to tell client to keep the default password plugin
|
||||
// which Doris is using now.
|
||||
// Note: Check the authPacket whether support plugin auth firstly,
|
||||
// before we check AuthPlugin between doris and client to compatible with older version: like mysql 5.1
|
||||
if (authPacket.getCapability().isPluginAuth()
|
||||
&& !handshakePacket.checkAuthPluginSameAsDoris(authPacket.getPluginName())) {
|
||||
// 1. clear the serializer
|
||||
serializer.reset();
|
||||
// 2. build the auth switch request and send to the client
|
||||
handshakePacket.buildAuthSwitchRequest(serializer);
|
||||
channel.sendAndFlush(serializer.toByteBuffer());
|
||||
// Server receive auth switch response packet from client.
|
||||
ByteBuffer authSwitchResponse = channel.fetchOnePacket();
|
||||
if (authSwitchResponse == null) {
|
||||
// receive response failed.
|
||||
return false;
|
||||
}
|
||||
// 3. the client use default password plugin of Doris to dispose
|
||||
// password
|
||||
authPacket.setAuthResponse(MysqlProto.readEofString(authSwitchResponse));
|
||||
}
|
||||
|
||||
// NOTE: when we behind proxy, we need random string sent by proxy.
|
||||
byte[] randomString = handshakePacket.getAuthPluginData();
|
||||
if (Config.proxy_auth_enable && authPacket.getRandomString() != null) {
|
||||
randomString = authPacket.getRandomString();
|
||||
}
|
||||
// check authenticate
|
||||
if (!internalAuthenticate(context, authPacket.getAuthResponse(), randomString, qualifiedUser)) {
|
||||
MysqlProto.sendResponsePacket(context);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* ldap:
|
||||
* server ---AuthSwitch---> client
|
||||
* server <--- clear text password --- client
|
||||
*/
|
||||
private static boolean ldapAuth(
|
||||
ConnectContext context,
|
||||
String qualifiedUser,
|
||||
MysqlChannel channel,
|
||||
MysqlSerializer serializer) throws IOException {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("user:{} start to ldap authenticate.", qualifiedUser);
|
||||
}
|
||||
// server send authentication switch packet to request password clear text.
|
||||
// https://dev.mysql.com/doc/internals/en/authentication-method-change.html
|
||||
serializer.reset();
|
||||
MysqlAuthSwitchPacket mysqlAuthSwitchPacket = new MysqlAuthSwitchPacket();
|
||||
mysqlAuthSwitchPacket.writeTo(serializer);
|
||||
channel.sendAndFlush(serializer.toByteBuffer());
|
||||
|
||||
// Server receive password clear text.
|
||||
ByteBuffer authSwitchResponse = channel.fetchOnePacket();
|
||||
if (authSwitchResponse == null) {
|
||||
return false;
|
||||
}
|
||||
MysqlClearTextPacket clearTextPacket = new MysqlClearTextPacket();
|
||||
if (!clearTextPacket.readFrom(authSwitchResponse)) {
|
||||
ErrorReport.report(ErrorCode.ERR_NOT_SUPPORTED_AUTH_MODE);
|
||||
MysqlProto.sendResponsePacket(context);
|
||||
return false;
|
||||
}
|
||||
if (!LdapAuthenticate.authenticate(context, clearTextPacket.getPassword(), qualifiedUser)) {
|
||||
MysqlProto.sendResponsePacket(context);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Based on FE configuration and some prerequisites, decide which authentication type to actually use
|
||||
private static MysqlAuthType useWhichAuthType(ConnectContext context, String qualifiedUser) throws IOException {
|
||||
MysqlAuthType typeConfig = MysqlAuthType.getAuthTypeConfig();
|
||||
|
||||
// Root and admin are internal users of the Doris.
|
||||
// They are used to set the ldap admin password.
|
||||
// Cannot use external authentication.
|
||||
if (qualifiedUser.equals(Auth.ROOT_USER) || qualifiedUser.equals(Auth.ADMIN_USER)) {
|
||||
return MysqlAuthType.DEFAULT;
|
||||
}
|
||||
|
||||
// precondition
|
||||
switch (typeConfig) {
|
||||
case LDAP:
|
||||
try {
|
||||
// If LDAP authentication is enabled and the user exists in LDAP, use LDAP authentication,
|
||||
// otherwise use Doris internal authentication.
|
||||
if (!Env.getCurrentEnv().getAuth().getLdapManager().doesUserExist(qualifiedUser)) {
|
||||
return MysqlAuthType.DEFAULT;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO: can we catch exception here?
|
||||
LOG.warn("Check if user exists in ldap error.", e);
|
||||
MysqlProto.sendResponsePacket(context);
|
||||
return MysqlAuthType.DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return typeConfig;
|
||||
}
|
||||
|
||||
public static boolean authenticate(
|
||||
ConnectContext context,
|
||||
String qualifiedUser,
|
||||
MysqlChannel channel,
|
||||
MysqlSerializer serializer,
|
||||
MysqlAuthPacket authPacket,
|
||||
MysqlHandshakePacket handshakePacket) throws IOException {
|
||||
MysqlAuthType authType = useWhichAuthType(context, qualifiedUser);
|
||||
switch (authType) {
|
||||
case DEFAULT:
|
||||
return defaultAuth(context, qualifiedUser, channel, serializer, authPacket, handshakePacket);
|
||||
case LDAP:
|
||||
return ldapAuth(context, qualifiedUser, channel, serializer);
|
||||
default:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -22,12 +22,20 @@ 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.qe.ConnectContext;
|
||||
import org.apache.doris.mysql.authenticate.AuthenticateRequest;
|
||||
import org.apache.doris.mysql.authenticate.AuthenticateResponse;
|
||||
import org.apache.doris.mysql.authenticate.Authenticator;
|
||||
import org.apache.doris.mysql.authenticate.password.ClearPassword;
|
||||
import org.apache.doris.mysql.authenticate.password.ClearPasswordResolver;
|
||||
import org.apache.doris.mysql.authenticate.password.Password;
|
||||
import org.apache.doris.mysql.authenticate.password.PasswordResolver;
|
||||
import org.apache.doris.mysql.privilege.Auth;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -35,8 +43,43 @@ import java.util.List;
|
||||
* This means that users can log in to Doris with a user name and LDAP password,
|
||||
* and the user will get the privileges of all roles corresponding to the LDAP group.
|
||||
*/
|
||||
public class LdapAuthenticate {
|
||||
private static final Logger LOG = LogManager.getLogger(LdapAuthenticate.class);
|
||||
public class LdapAuthenticator implements Authenticator {
|
||||
private static final Logger LOG = LogManager.getLogger(LdapAuthenticator.class);
|
||||
|
||||
private PasswordResolver passwordResolver;
|
||||
|
||||
public LdapAuthenticator() {
|
||||
this.passwordResolver = new ClearPasswordResolver();
|
||||
}
|
||||
|
||||
/*
|
||||
* ldap:
|
||||
* server ---AuthSwitch---> client
|
||||
* server <--- clear text password --- client
|
||||
*/
|
||||
@Override
|
||||
public AuthenticateResponse authenticate(AuthenticateRequest request) throws IOException {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("user:{} start to ldap authenticate.", request.getUserName());
|
||||
}
|
||||
Password password = request.getPassword();
|
||||
if (!(password instanceof ClearPassword)) {
|
||||
return AuthenticateResponse.failedResponse;
|
||||
}
|
||||
ClearPassword clearPassword = (ClearPassword) password;
|
||||
return internalAuthenticate(clearPassword.getPassword(), request.getUserName(), request.getRemoteIp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDeal(String qualifiedUser) {
|
||||
if (qualifiedUser.equals(Auth.ROOT_USER) || qualifiedUser.equals(Auth.ADMIN_USER)) {
|
||||
return false;
|
||||
}
|
||||
if (!Env.getCurrentEnv().getAuth().getLdapManager().doesUserExist(qualifiedUser)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The LDAP authentication process is as follows:
|
||||
@ -45,7 +88,7 @@ public class LdapAuthenticate {
|
||||
* step3: Set current userIdentity. If the user account does not exist in Doris, login as a temporary user.
|
||||
* Otherwise, login to the Doris account.
|
||||
*/
|
||||
public static boolean authenticate(ConnectContext context, String password, String qualifiedUser) {
|
||||
private AuthenticateResponse internalAuthenticate(String password, String qualifiedUser, String remoteIp) {
|
||||
String usePasswd = (Strings.isNullOrEmpty(password)) ? "NO" : "YES";
|
||||
String userName = ClusterNamespace.getNameFromFullName(qualifiedUser);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
@ -56,35 +99,36 @@ public class LdapAuthenticate {
|
||||
try {
|
||||
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;
|
||||
ErrorReport.report(ErrorCode.ERR_ACCESS_DENIED_ERROR, qualifiedUser, remoteIp, usePasswd);
|
||||
return AuthenticateResponse.failedResponse;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Check ldap password error.", e);
|
||||
return false;
|
||||
return AuthenticateResponse.failedResponse;
|
||||
}
|
||||
|
||||
String remoteIp = context.getMysqlChannel().getRemoteIp();
|
||||
UserIdentity tempUserIdentity = UserIdentity.createAnalyzedUserIdentWithIp(qualifiedUser, remoteIp);
|
||||
// Search the user in doris.
|
||||
List<UserIdentity> userIdentities = Env.getCurrentEnv().getAuth()
|
||||
.getUserIdentityForLdap(qualifiedUser, remoteIp);
|
||||
UserIdentity userIdentity;
|
||||
AuthenticateResponse response = new AuthenticateResponse(true);
|
||||
if (userIdentities.isEmpty()) {
|
||||
userIdentity = tempUserIdentity;
|
||||
response.setUserIdentity(tempUserIdentity);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("User:{} does not exists in doris, login as temporary users.", userName);
|
||||
}
|
||||
context.setIsTempUser(true);
|
||||
response.setTemp(true);
|
||||
} else {
|
||||
userIdentity = userIdentities.get(0);
|
||||
response.setUserIdentity(userIdentities.get(0));
|
||||
}
|
||||
|
||||
context.setCurrentUserIdentity(userIdentity);
|
||||
context.setRemoteIP(remoteIp);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("ldap authentication success: identity:{}", context.getCurrentUserIdentity());
|
||||
LOG.debug("ldap authentication success: identity:{}", response.getUserIdentity());
|
||||
}
|
||||
return true;
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PasswordResolver getPasswordResolver() {
|
||||
return passwordResolver;
|
||||
}
|
||||
}
|
||||
@ -25,7 +25,7 @@ import org.apache.doris.cluster.ClusterNamespace;
|
||||
import org.apache.doris.common.AnalysisException;
|
||||
import org.apache.doris.common.DdlException;
|
||||
import org.apache.doris.common.LdapConfig;
|
||||
import org.apache.doris.mysql.authenticate.MysqlAuthType;
|
||||
import org.apache.doris.mysql.authenticate.AuthenticateType;
|
||||
import org.apache.doris.mysql.privilege.Auth;
|
||||
import org.apache.doris.mysql.privilege.PrivBitSet;
|
||||
import org.apache.doris.mysql.privilege.Privilege;
|
||||
@ -103,7 +103,7 @@ public class LdapManager {
|
||||
|
||||
public boolean checkUserPasswd(String fullName, String passwd) {
|
||||
String userName = ClusterNamespace.getNameFromFullName(fullName);
|
||||
if (MysqlAuthType.getAuthTypeConfig() != MysqlAuthType.LDAP || Strings.isNullOrEmpty(userName)
|
||||
if (AuthenticateType.getAuthTypeConfig() != AuthenticateType.LDAP || Strings.isNullOrEmpty(userName)
|
||||
|| Objects.isNull(passwd)) {
|
||||
return false;
|
||||
}
|
||||
@ -137,7 +137,7 @@ public class LdapManager {
|
||||
}
|
||||
|
||||
private boolean checkParam(String fullName) {
|
||||
return MysqlAuthType.getAuthTypeConfig() == MysqlAuthType.LDAP
|
||||
return AuthenticateType.getAuthTypeConfig() == AuthenticateType.LDAP
|
||||
&& !Strings.isNullOrEmpty(fullName)
|
||||
&& !fullName.equalsIgnoreCase(Auth.ROOT_USER) && !fullName.equalsIgnoreCase(Auth.ADMIN_USER);
|
||||
}
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.mysql.authenticate.password;
|
||||
|
||||
public class ClearPassword extends Password {
|
||||
private String password;
|
||||
|
||||
public ClearPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.mysql.authenticate.password;
|
||||
|
||||
import org.apache.doris.common.ErrorCode;
|
||||
import org.apache.doris.common.ErrorReport;
|
||||
import org.apache.doris.mysql.MysqlAuthPacket;
|
||||
import org.apache.doris.mysql.MysqlAuthSwitchPacket;
|
||||
import org.apache.doris.mysql.MysqlChannel;
|
||||
import org.apache.doris.mysql.MysqlClearTextPacket;
|
||||
import org.apache.doris.mysql.MysqlHandshakePacket;
|
||||
import org.apache.doris.mysql.MysqlProto;
|
||||
import org.apache.doris.mysql.MysqlSerializer;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ClearPasswordResolver implements PasswordResolver {
|
||||
@Override
|
||||
public Optional<Password> resolvePassword(ConnectContext context, MysqlChannel channel, MysqlSerializer serializer,
|
||||
MysqlAuthPacket authPacket,
|
||||
MysqlHandshakePacket handshakePacket) throws IOException {
|
||||
// server send authentication switch packet to request password clear text.
|
||||
// https://dev.mysql.com/doc/internals/en/authentication-method-change.html
|
||||
serializer.reset();
|
||||
MysqlAuthSwitchPacket mysqlAuthSwitchPacket = new MysqlAuthSwitchPacket();
|
||||
mysqlAuthSwitchPacket.writeTo(serializer);
|
||||
channel.sendAndFlush(serializer.toByteBuffer());
|
||||
|
||||
// Server receive password clear text.
|
||||
ByteBuffer authSwitchResponse = channel.fetchOnePacket();
|
||||
if (authSwitchResponse == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
MysqlClearTextPacket clearTextPacket = new MysqlClearTextPacket();
|
||||
if (!clearTextPacket.readFrom(authSwitchResponse)) {
|
||||
ErrorReport.report(ErrorCode.ERR_NOT_SUPPORTED_AUTH_MODE);
|
||||
MysqlProto.sendResponsePacket(context);
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(new ClearPassword(clearTextPacket.getPassword()));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.mysql.authenticate.password;
|
||||
|
||||
public class NativePassword extends Password {
|
||||
private byte[] remotePasswd;
|
||||
private byte[] randomString;
|
||||
|
||||
public NativePassword(byte[] remotePasswd, byte[] randomString) {
|
||||
this.remotePasswd = remotePasswd;
|
||||
this.randomString = randomString;
|
||||
}
|
||||
|
||||
public byte[] getRemotePasswd() {
|
||||
return remotePasswd;
|
||||
}
|
||||
|
||||
public byte[] getRandomString() {
|
||||
return randomString;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.mysql.authenticate.password;
|
||||
|
||||
import org.apache.doris.common.Config;
|
||||
import org.apache.doris.mysql.MysqlAuthPacket;
|
||||
import org.apache.doris.mysql.MysqlChannel;
|
||||
import org.apache.doris.mysql.MysqlHandshakePacket;
|
||||
import org.apache.doris.mysql.MysqlProto;
|
||||
import org.apache.doris.mysql.MysqlSerializer;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Optional;
|
||||
|
||||
public class NativePasswordResolver implements PasswordResolver {
|
||||
@Override
|
||||
public Optional<Password> resolvePassword(ConnectContext context, MysqlChannel channel, MysqlSerializer serializer,
|
||||
MysqlAuthPacket authPacket,
|
||||
MysqlHandshakePacket handshakePacket) throws IOException {
|
||||
// Starting with MySQL 8.0.4, MySQL changed the default authentication plugin for MySQL client
|
||||
// from mysql_native_password to caching_sha2_password.
|
||||
// ref: https://mysqlserverteam.com/mysql-8-0-4-new-default-authentication-plugin-caching_sha2_password/
|
||||
// So, User use mysql client or ODBC Driver after 8.0.4 have problem to connect to Doris
|
||||
// with password.
|
||||
// So Doris support the Protocol::AuthSwitchRequest to tell client to keep the default password plugin
|
||||
// which Doris is using now.
|
||||
// Note: Check the authPacket whether support plugin auth firstly,
|
||||
// before we check AuthPlugin between doris and client to compatible with older version: like mysql 5.1
|
||||
if (authPacket.getCapability().isPluginAuth()
|
||||
&& !handshakePacket.checkAuthPluginSameAsDoris(authPacket.getPluginName())) {
|
||||
// 1. clear the serializer
|
||||
serializer.reset();
|
||||
// 2. build the auth switch request and send to the client
|
||||
handshakePacket.buildAuthSwitchRequest(serializer);
|
||||
channel.sendAndFlush(serializer.toByteBuffer());
|
||||
// Server receive auth switch response packet from client.
|
||||
ByteBuffer authSwitchResponse = channel.fetchOnePacket();
|
||||
if (authSwitchResponse == null) {
|
||||
// receive response failed.
|
||||
return Optional.empty();
|
||||
}
|
||||
// 3. the client use default password plugin of Doris to dispose
|
||||
// password
|
||||
authPacket.setAuthResponse(MysqlProto.readEofString(authSwitchResponse));
|
||||
}
|
||||
|
||||
// NOTE: when we behind proxy, we need random string sent by proxy.
|
||||
byte[] randomString = handshakePacket.getAuthPluginData();
|
||||
if (Config.proxy_auth_enable && authPacket.getRandomString() != null) {
|
||||
randomString = authPacket.getRandomString();
|
||||
}
|
||||
return Optional.of(new NativePassword(authPacket.getAuthResponse(), randomString));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.mysql.authenticate.password;
|
||||
|
||||
public abstract class Password {
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.mysql.authenticate.password;
|
||||
|
||||
import org.apache.doris.mysql.MysqlAuthPacket;
|
||||
import org.apache.doris.mysql.MysqlChannel;
|
||||
import org.apache.doris.mysql.MysqlHandshakePacket;
|
||||
import org.apache.doris.mysql.MysqlSerializer;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface PasswordResolver {
|
||||
Optional<Password> resolvePassword(ConnectContext context, MysqlChannel channel,
|
||||
MysqlSerializer serializer,
|
||||
MysqlAuthPacket authPacket,
|
||||
MysqlHandshakePacket handshakePacket) throws IOException;
|
||||
}
|
||||
@ -53,7 +53,7 @@ import org.apache.doris.common.UserException;
|
||||
import org.apache.doris.common.io.Writable;
|
||||
import org.apache.doris.datasource.InternalCatalog;
|
||||
import org.apache.doris.mysql.MysqlPassword;
|
||||
import org.apache.doris.mysql.authenticate.MysqlAuthType;
|
||||
import org.apache.doris.mysql.authenticate.AuthenticateType;
|
||||
import org.apache.doris.mysql.authenticate.ldap.LdapManager;
|
||||
import org.apache.doris.mysql.authenticate.ldap.LdapUserInfo;
|
||||
import org.apache.doris.persist.AlterUserOperationLog;
|
||||
@ -419,7 +419,7 @@ public class Auth implements Writable {
|
||||
|
||||
// Check if LDAP authentication is enabled.
|
||||
private boolean isLdapAuthEnabled() {
|
||||
return MysqlAuthType.getAuthTypeConfig() == MysqlAuthType.LDAP;
|
||||
return AuthenticateType.getAuthTypeConfig() == AuthenticateType.LDAP;
|
||||
}
|
||||
|
||||
// create user
|
||||
|
||||
@ -20,12 +20,13 @@ package org.apache.doris.mysql;
|
||||
import org.apache.doris.analysis.UserIdentity;
|
||||
import org.apache.doris.catalog.Database;
|
||||
import org.apache.doris.catalog.Env;
|
||||
import org.apache.doris.cluster.ClusterNamespace;
|
||||
import org.apache.doris.common.AuthenticationException;
|
||||
import org.apache.doris.common.Config;
|
||||
import org.apache.doris.common.DdlException;
|
||||
import org.apache.doris.datasource.InternalCatalog;
|
||||
import org.apache.doris.mysql.authenticate.ldap.LdapAuthenticate;
|
||||
import org.apache.doris.mysql.authenticate.AuthenticateRequest;
|
||||
import org.apache.doris.mysql.authenticate.AuthenticatorManager;
|
||||
import org.apache.doris.mysql.authenticate.ldap.LdapAuthenticator;
|
||||
import org.apache.doris.mysql.authenticate.ldap.LdapManager;
|
||||
import org.apache.doris.mysql.privilege.AccessControllerManager;
|
||||
import org.apache.doris.mysql.privilege.Auth;
|
||||
@ -65,14 +66,16 @@ public class MysqlProtoTest {
|
||||
@Mocked
|
||||
private LdapManager ldapManager;
|
||||
@Mocked
|
||||
private LdapAuthenticate ldapAuthenticate;
|
||||
@Mocked
|
||||
private MysqlClearTextPacket clearTextPacket;
|
||||
@Mocked
|
||||
StreamConnection streamConnection;
|
||||
private StreamConnection streamConnection;
|
||||
@Mocked
|
||||
private LdapAuthenticator ldapAuthenticator;
|
||||
@Mocked
|
||||
private AuthenticatorManager authenticatorManager;
|
||||
|
||||
@Before
|
||||
public void setUp() throws DdlException, AuthenticationException {
|
||||
public void setUp() throws DdlException, AuthenticationException, IOException {
|
||||
|
||||
// mock auth
|
||||
new Expectations() {
|
||||
@ -95,6 +98,15 @@ public class MysqlProtoTest {
|
||||
minTimes = 0;
|
||||
result = catalog;
|
||||
|
||||
env.getAuthenticatorManager();
|
||||
minTimes = 0;
|
||||
result = authenticatorManager;
|
||||
|
||||
authenticatorManager.authenticate((ConnectContext) any, anyString, (MysqlChannel) any,
|
||||
(MysqlSerializer) any, (MysqlAuthPacket) any, (MysqlHandshakePacket) any);
|
||||
minTimes = 0;
|
||||
result = true;
|
||||
|
||||
catalog.getDbNullable(anyString);
|
||||
minTimes = 0;
|
||||
result = new Database();
|
||||
@ -215,19 +227,14 @@ public class MysqlProtoTest {
|
||||
private void mockAccess() throws Exception {
|
||||
}
|
||||
|
||||
private void mockLdap(String user, boolean userExist) {
|
||||
private void mockLdap(boolean userExist) throws IOException {
|
||||
Config.authentication_type = "ldap";
|
||||
|
||||
new Expectations() {
|
||||
{
|
||||
LdapAuthenticate.authenticate((ConnectContext) any, anyString, anyString);
|
||||
ldapAuthenticator.authenticate((AuthenticateRequest) any);
|
||||
minTimes = 0;
|
||||
result = new Delegate() {
|
||||
boolean fakeLdapAuthenticate(ConnectContext context, String password, String qualifiedUser) {
|
||||
return password.equals(PASSWORD_CLEAR_TEXT)
|
||||
&& ClusterNamespace.getNameFromFullName(qualifiedUser).equals(user);
|
||||
}
|
||||
};
|
||||
result = true;
|
||||
|
||||
ldapManager.checkUserPasswd(anyString, anyString);
|
||||
minTimes = 0;
|
||||
@ -285,7 +292,7 @@ public class MysqlProtoTest {
|
||||
mockPassword(true);
|
||||
mockAccess();
|
||||
mockMysqlClearTextPacket(PASSWORD_CLEAR_TEXT);
|
||||
mockLdap("user", true);
|
||||
mockLdap(true);
|
||||
ConnectContext context = new ConnectContext(streamConnection);
|
||||
context.setEnv(env);
|
||||
context.setThreadLocalInfo();
|
||||
@ -293,26 +300,12 @@ public class MysqlProtoTest {
|
||||
Config.authentication_type = "default";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNegotiateLdapInvalidPasswd() throws Exception {
|
||||
mockChannel("user", true);
|
||||
mockPassword(true);
|
||||
mockAccess();
|
||||
mockMysqlClearTextPacket("654321");
|
||||
mockLdap("user", true);
|
||||
ConnectContext context = new ConnectContext(streamConnection);
|
||||
context.setEnv(env);
|
||||
context.setThreadLocalInfo();
|
||||
Assert.assertFalse(MysqlProto.negotiate(context));
|
||||
Config.authentication_type = "default";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNegotiateLdapRoot() throws Exception {
|
||||
mockChannel("root", true);
|
||||
mockPassword(true);
|
||||
mockAccess();
|
||||
mockLdap("root", false);
|
||||
mockLdap(false);
|
||||
mockMysqlClearTextPacket("654321");
|
||||
ConnectContext context = new ConnectContext(streamConnection);
|
||||
context.setEnv(env);
|
||||
|
||||
@ -0,0 +1,100 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.mysql.authenticate;
|
||||
|
||||
import org.apache.doris.analysis.UserIdentity;
|
||||
import org.apache.doris.common.AuthenticationException;
|
||||
import org.apache.doris.common.DdlException;
|
||||
import org.apache.doris.mysql.authenticate.password.NativePassword;
|
||||
import org.apache.doris.mysql.authenticate.password.NativePasswordResolver;
|
||||
import org.apache.doris.mysql.privilege.Auth;
|
||||
|
||||
import mockit.Delegate;
|
||||
import mockit.Expectations;
|
||||
import mockit.Mocked;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class DefaultAuthenticatorTest {
|
||||
private static final String USER_NAME = "user";
|
||||
private static final String IP = "192.168.1.1";
|
||||
|
||||
@Mocked
|
||||
private Auth auth;
|
||||
|
||||
private DefaultAuthenticator defaultAuthenticator = new DefaultAuthenticator();
|
||||
private AuthenticateRequest request = new AuthenticateRequest(USER_NAME,
|
||||
new NativePassword(new byte[2], new byte[2]), IP);
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws DdlException, AuthenticationException, IOException {
|
||||
|
||||
// mock auth
|
||||
new Expectations() {
|
||||
{
|
||||
auth.checkPassword(anyString, anyString, (byte[]) any, (byte[]) any, (List<UserIdentity>) any);
|
||||
minTimes = 0;
|
||||
result = new Delegate() {
|
||||
void fakeCheckPassword(String remoteUser, String remoteHost, byte[] remotePasswd,
|
||||
byte[] randomString, List<UserIdentity> currentUser) {
|
||||
UserIdentity userIdentity = new UserIdentity(USER_NAME, IP);
|
||||
currentUser.add(userIdentity);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAuthenticate() throws IOException {
|
||||
AuthenticateResponse response = defaultAuthenticator.authenticate(request);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertFalse(response.isTemp());
|
||||
Assert.assertEquals("'user'@'192.168.1.1'", response.getUserIdentity().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateFailed() throws IOException, AuthenticationException {
|
||||
new Expectations() {
|
||||
{
|
||||
auth.checkPassword(anyString, anyString, (byte[]) any, (byte[]) any, (List<UserIdentity>) any);
|
||||
minTimes = 0;
|
||||
result = new AuthenticationException("exception");
|
||||
}
|
||||
};
|
||||
AuthenticateResponse response = defaultAuthenticator.authenticate(request);
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCanDeal() {
|
||||
Assert.assertTrue(defaultAuthenticator.canDeal("ss"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPasswordResolver() {
|
||||
Assert.assertTrue(defaultAuthenticator.getPasswordResolver() instanceof NativePasswordResolver);
|
||||
}
|
||||
}
|
||||
@ -1,203 +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.mysql.authenticate.ldap;
|
||||
|
||||
import org.apache.doris.analysis.UserIdentity;
|
||||
import org.apache.doris.catalog.Env;
|
||||
import org.apache.doris.common.DdlException;
|
||||
import org.apache.doris.mysql.privilege.AccessControllerManager;
|
||||
import org.apache.doris.mysql.privilege.Auth;
|
||||
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;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LdapAuthenticateTest {
|
||||
private static final String USER_NAME = "user";
|
||||
private static final String IP = "192.168.1.1";
|
||||
private static final String TABLE_RD = "palo_rd";
|
||||
|
||||
private Role ldapGroupsPrivs;
|
||||
|
||||
@Mocked
|
||||
private LdapManager ldapManager;
|
||||
@Mocked
|
||||
private Env env;
|
||||
@Mocked
|
||||
private Auth auth;
|
||||
@Mocked
|
||||
private AccessControllerManager accessManager;
|
||||
|
||||
@Before
|
||||
public void setUp() throws DdlException {
|
||||
new Expectations() {
|
||||
{
|
||||
auth.doesRoleExist(anyString);
|
||||
minTimes = 0;
|
||||
result = true;
|
||||
|
||||
auth.mergeRolesNoCheckName((List<String>) any, (Role) any);
|
||||
minTimes = 0;
|
||||
result = new Delegate() {
|
||||
void fakeMergeRolesNoCheckName(List<String> roles, Role savedRole) {
|
||||
ldapGroupsPrivs = savedRole;
|
||||
}
|
||||
};
|
||||
|
||||
env.getAccessManager();
|
||||
minTimes = 0;
|
||||
result = accessManager;
|
||||
|
||||
env.getAuth();
|
||||
minTimes = 0;
|
||||
result = auth;
|
||||
|
||||
Env.getCurrentEnv();
|
||||
minTimes = 0;
|
||||
result = env;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setCheckPassword(boolean res) {
|
||||
new Expectations() {
|
||||
{
|
||||
ldapManager.checkUserPasswd(anyString, anyString);
|
||||
minTimes = 0;
|
||||
result = res;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setCheckPasswordException() {
|
||||
new Expectations() {
|
||||
{
|
||||
ldapManager.checkUserPasswd(anyString, anyString);
|
||||
minTimes = 0;
|
||||
result = new RuntimeException("exception");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setGetUserInfo(boolean res) {
|
||||
new Expectations() {
|
||||
{
|
||||
if (res) {
|
||||
ldapManager.getUserInfo(anyString);
|
||||
minTimes = 0;
|
||||
result = new Delegate() {
|
||||
LdapUserInfo fakeGetGroups(String user) {
|
||||
return new LdapUserInfo(anyString, false, "", Sets.newHashSet(new Role(anyString)));
|
||||
}
|
||||
};
|
||||
} else {
|
||||
ldapManager.getUserInfo(anyString);
|
||||
minTimes = 0;
|
||||
result = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setGetCurrentUserIdentity(boolean res) {
|
||||
new Expectations() {
|
||||
{
|
||||
if (res) {
|
||||
auth.getCurrentUserIdentity((UserIdentity) any);
|
||||
minTimes = 0;
|
||||
result = new UserIdentity(USER_NAME, IP);
|
||||
} else {
|
||||
auth.getCurrentUserIdentity((UserIdentity) any);
|
||||
minTimes = 0;
|
||||
result = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ConnectContext getContext() {
|
||||
ConnectContext context = new ConnectContext();
|
||||
context.setEnv(env);
|
||||
context.setThreadLocalInfo();
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAuthenticate() {
|
||||
ConnectContext context = getContext();
|
||||
setCheckPassword(true);
|
||||
setGetUserInfo(true);
|
||||
setGetCurrentUserIdentity(true);
|
||||
String qualifiedUser = USER_NAME;
|
||||
Assert.assertTrue(LdapAuthenticate.authenticate(context, "123", qualifiedUser));
|
||||
Assert.assertTrue(context.getIsTempUser());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateWithWrongPassword() {
|
||||
ConnectContext context = getContext();
|
||||
setCheckPassword(false);
|
||||
setGetUserInfo(true);
|
||||
setGetCurrentUserIdentity(true);
|
||||
String qualifiedUser = USER_NAME;
|
||||
Assert.assertFalse(LdapAuthenticate.authenticate(context, "123", qualifiedUser));
|
||||
Assert.assertFalse(context.getIsTempUser());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateWithCheckPasswordException() {
|
||||
ConnectContext context = getContext();
|
||||
setCheckPasswordException();
|
||||
setGetUserInfo(true);
|
||||
setGetCurrentUserIdentity(true);
|
||||
String qualifiedUser = USER_NAME;
|
||||
Assert.assertFalse(LdapAuthenticate.authenticate(context, "123", qualifiedUser));
|
||||
Assert.assertFalse(context.getIsTempUser());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateGetGroupsNull() {
|
||||
ConnectContext context = getContext();
|
||||
setCheckPassword(true);
|
||||
setGetUserInfo(false);
|
||||
setGetCurrentUserIdentity(true);
|
||||
String qualifiedUser = USER_NAME;
|
||||
Assert.assertTrue(LdapAuthenticate.authenticate(context, "123", qualifiedUser));
|
||||
Assert.assertTrue(context.getIsTempUser());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateUserNotExistInDoris() {
|
||||
ConnectContext context = getContext();
|
||||
setCheckPassword(true);
|
||||
setGetUserInfo(true);
|
||||
setGetCurrentUserIdentity(false);
|
||||
String qualifiedUser = USER_NAME;
|
||||
Assert.assertTrue(LdapAuthenticate.authenticate(context, "123", qualifiedUser));
|
||||
Assert.assertTrue(context.getIsTempUser());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,146 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.mysql.authenticate.ldap;
|
||||
|
||||
import org.apache.doris.analysis.UserIdentity;
|
||||
import org.apache.doris.mysql.authenticate.AuthenticateRequest;
|
||||
import org.apache.doris.mysql.authenticate.AuthenticateResponse;
|
||||
import org.apache.doris.mysql.authenticate.password.ClearPassword;
|
||||
import org.apache.doris.mysql.authenticate.password.ClearPasswordResolver;
|
||||
import org.apache.doris.mysql.privilege.Auth;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import mockit.Expectations;
|
||||
import mockit.Mocked;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class LdapAuthenticatorTest {
|
||||
private static final String USER_NAME = "user";
|
||||
private static final String IP = "192.168.1.1";
|
||||
|
||||
@Mocked
|
||||
private LdapManager ldapManager;
|
||||
|
||||
@Mocked
|
||||
private Auth auth;
|
||||
|
||||
private LdapAuthenticator ldapAuthenticator = new LdapAuthenticator();
|
||||
private AuthenticateRequest request = new AuthenticateRequest(USER_NAME, new ClearPassword("123"), IP);
|
||||
|
||||
private void setCheckPassword(boolean res) {
|
||||
new Expectations() {
|
||||
{
|
||||
ldapManager.checkUserPasswd(anyString, anyString);
|
||||
minTimes = 0;
|
||||
result = res;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setCheckPasswordException() {
|
||||
new Expectations() {
|
||||
{
|
||||
ldapManager.checkUserPasswd(anyString, anyString);
|
||||
minTimes = 0;
|
||||
result = new RuntimeException("exception");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setGetUserInDoris(boolean res) {
|
||||
new Expectations() {
|
||||
{
|
||||
if (res) {
|
||||
List<UserIdentity> list = Lists.newArrayList(new UserIdentity(USER_NAME, IP));
|
||||
auth.getUserIdentityForLdap(anyString, anyString);
|
||||
minTimes = 0;
|
||||
result = list;
|
||||
} else {
|
||||
auth.getCurrentUserIdentity((UserIdentity) any);
|
||||
minTimes = 0;
|
||||
result = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setLdapUserExist(boolean res) {
|
||||
new Expectations() {
|
||||
{
|
||||
ldapManager.doesUserExist(anyString);
|
||||
minTimes = 0;
|
||||
result = res;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticate() throws IOException {
|
||||
setCheckPassword(true);
|
||||
setGetUserInDoris(true);
|
||||
AuthenticateResponse response = ldapAuthenticator.authenticate(request);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertFalse(response.isTemp());
|
||||
Assert.assertEquals("'user'@'192.168.1.1'", response.getUserIdentity().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateWithWrongPassword() throws IOException {
|
||||
setCheckPassword(false);
|
||||
setGetUserInDoris(true);
|
||||
AuthenticateResponse response = ldapAuthenticator.authenticate(request);
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateWithCheckPasswordException() throws IOException {
|
||||
setCheckPasswordException();
|
||||
setGetUserInDoris(true);
|
||||
AuthenticateResponse response = ldapAuthenticator.authenticate(request);
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateUserNotExistInDoris() throws IOException {
|
||||
setCheckPassword(true);
|
||||
setGetUserInDoris(false);
|
||||
AuthenticateResponse response = ldapAuthenticator.authenticate(request);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertTrue(response.isTemp());
|
||||
Assert.assertEquals("'user'@'192.168.1.1'", response.getUserIdentity().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanDeal() {
|
||||
setLdapUserExist(true);
|
||||
Assert.assertFalse(ldapAuthenticator.canDeal(Auth.ROOT_USER));
|
||||
Assert.assertFalse(ldapAuthenticator.canDeal(Auth.ADMIN_USER));
|
||||
Assert.assertTrue(ldapAuthenticator.canDeal("ss"));
|
||||
setLdapUserExist(false);
|
||||
Assert.assertFalse(ldapAuthenticator.canDeal("ss"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPasswordResolver() {
|
||||
Assert.assertTrue(ldapAuthenticator.getPasswordResolver() instanceof ClearPasswordResolver);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user