Bläddra i källkod

Implement credential interfaces (#291)

Signed-off-by: SimFG <bang.fu@zilliz.com>

Co-authored-by: fubang <bang.fu@zilliz.com>
SimFG 3 år sedan
förälder
incheckning
05ffd449d8

+ 130 - 0
src/main/java/io/milvus/client/AbstractMilvusGrpcClient.java

@@ -36,6 +36,7 @@ import io.milvus.param.alias.CreateAliasParam;
 import io.milvus.param.alias.DropAliasParam;
 import io.milvus.param.collection.*;
 import io.milvus.param.control.*;
+import io.milvus.param.credential.*;
 import io.milvus.param.dml.*;
 import io.milvus.param.index.*;
 import io.milvus.param.partition.*;
@@ -47,6 +48,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.annotation.Nonnull;
+import java.nio.charset.StandardCharsets;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
@@ -1887,6 +1889,134 @@ public abstract class AbstractMilvusGrpcClient implements MilvusClient {
         }
     }
 
+    @Override
+    public R<RpcStatus> createCredential(CreateCredentialParam requestParam) {
+        if (!clientIsReady()) {
+            return R.failed(new ClientNotConnectedException("Client rpc channel is not ready"));
+        }
+
+        logInfo(requestParam.toString());
+
+        try {
+            CreateCredentialRequest createCredentialRequest = CreateCredentialRequest.newBuilder()
+                    .setUsername(requestParam.getUsername())
+                    .setPassword(getBase64EncodeString(requestParam.getPassword()))
+                    .build();
+
+            Status response = blockingStub().createCredential(createCredentialRequest);
+            if (response.getErrorCode() != ErrorCode.Success) {
+                return failedStatus("CreateCredential", response);
+            }
+
+            logInfo("CreateCredential successfully! Username:{}, password:{}",
+                    requestParam.getUsername(), requestParam.getPassword());
+            return R.success(new RpcStatus(RpcStatus.SUCCESS_MSG));
+        } catch (StatusRuntimeException e) {
+            logError("CreateCredential RPC failed! Username:{}, password:{}\n{}",
+                    requestParam.getUsername(), requestParam.getPassword(), e.getStatus().toString());
+            return R.failed(e);
+        } catch (Exception e) {
+            logError("CreateCredential failed! Username:{}, password:{}\n{}",
+                    requestParam.getUsername(), requestParam.getPassword(), e.getMessage());
+            return R.failed(e);
+        }
+    }
+
+    @Override
+    public R<RpcStatus> updateCredential(UpdateCredentialParam requestParam) {
+        if (!clientIsReady()) {
+            return R.failed(new ClientNotConnectedException("Client rpc channel is not ready"));
+        }
+
+        logInfo(requestParam.toString());
+
+        try {
+            UpdateCredentialRequest updateCredentialRequest = UpdateCredentialRequest.newBuilder()
+                    .setUsername(requestParam.getUsername())
+                    .setOldPassword(getBase64EncodeString(requestParam.getOldPassword()))
+                    .setNewPassword(getBase64EncodeString(requestParam.getNewPassword()))
+                    .build();
+
+            Status response = blockingStub().updateCredential(updateCredentialRequest);
+            if (response.getErrorCode() != ErrorCode.Success) {
+                return failedStatus("UpdateCredential", response);
+            }
+
+            logInfo("UpdateCredential successfully! Username:{}, oldPassword:{}, newPassword:{}",
+                    requestParam.getUsername(), requestParam.getOldPassword(), requestParam.getNewPassword());
+            return R.success(new RpcStatus(RpcStatus.SUCCESS_MSG));
+        } catch (StatusRuntimeException e) {
+            logError("UpdateCredential RPC failed! Username:{}, oldPassword:{}, newPassword:{}\n{}",
+                    requestParam.getUsername(), requestParam.getOldPassword(), requestParam.getNewPassword(), e.getStatus().toString());
+            return R.failed(e);
+        } catch (Exception e) {
+            logError("UpdateCredential failed! Username:{}, oldPassword:{}, newPassword:{}\n{}",
+                    requestParam.getUsername(), requestParam.getOldPassword(), requestParam.getNewPassword(), e.getMessage());
+            return R.failed(e);
+        }
+    }
+
+    @Override
+    public R<RpcStatus> deleteCredential(DeleteCredentialParam requestParam) {
+        if (!clientIsReady()) {
+            return R.failed(new ClientNotConnectedException("Client rpc channel is not ready"));
+        }
+
+        logInfo(requestParam.toString());
+
+        try {
+            DeleteCredentialRequest deleteCredentialRequest = DeleteCredentialRequest.newBuilder()
+                    .setUsername(requestParam.getUsername())
+                    .build();
+
+            Status response = blockingStub().deleteCredential(deleteCredentialRequest);
+            if (response.getErrorCode() != ErrorCode.Success) {
+                return failedStatus("DeleteCredential", response);
+            }
+
+            logInfo("DeleteCredential successfully! Username:{}", requestParam.getUsername());
+            return R.success(new RpcStatus(RpcStatus.SUCCESS_MSG));
+        } catch (StatusRuntimeException e) {
+            logError("DeleteCredential RPC failed! Username:{}\n{}", requestParam.getUsername(), e.getStatus().toString());
+            return R.failed(e);
+        } catch (Exception e) {
+            logError("DeleteCredential failed! Username:{}\n{}", requestParam.getUsername(), e.getMessage());
+            return R.failed(e);
+        }
+    }
+
+    @Override
+    public R<ListCredUsersResponse> listCredUsers(ListCredUsersParam requestParam) {
+        if (!clientIsReady()) {
+            return R.failed(new ClientNotConnectedException("Client rpc channel is not ready"));
+        }
+
+        logInfo(requestParam.toString());
+
+        try {
+            ListCredUsersRequest listCredUsersRequest = ListCredUsersRequest.newBuilder()
+                    .build();
+
+            ListCredUsersResponse response = blockingStub().listCredUsers(listCredUsersRequest);
+            if (response.getStatus().getErrorCode() != ErrorCode.Success) {
+                return failedStatus("ListCredUsers", response.getStatus());
+            }
+
+            logInfo("ListCredUsers successfully!");
+            return R.success(response);
+        } catch (StatusRuntimeException e) {
+            logError("ListCredUsers RPC failed! \n{}", e.getStatus().toString());
+            return R.failed(e);
+        } catch (Exception e) {
+            logError("DeleteCredential failed! \n{}", e.getMessage());
+            return R.failed(e);
+        }
+    }
+
+    private String getBase64EncodeString(String str) {
+        return Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8));
+    }
+
     ///////////////////// Log Functions//////////////////////
 
     private void logInfo(String msg, Object... params) {

+ 36 - 0
src/main/java/io/milvus/client/MilvusClient.java

@@ -27,6 +27,7 @@ import io.milvus.param.alias.CreateAliasParam;
 import io.milvus.param.alias.DropAliasParam;
 import io.milvus.param.collection.*;
 import io.milvus.param.control.*;
+import io.milvus.param.credential.*;
 import io.milvus.param.dml.*;
 import io.milvus.param.index.*;
 import io.milvus.param.partition.*;
@@ -424,4 +425,39 @@ public interface MilvusClient {
      * @return {status:result code, data:GetCompactionPlansResponse{status,info}}
      */
     R<GetCompactionPlansResponse> getCompactionStateWithPlans(GetCompactionPlansParam requestParam);
+
+    /**
+     * Create credential using the given user and password.
+     *
+     * @param requestParam {@link CreateCredentialParam}
+     * @return {status:result code, data:RpcStatus{msg: result message}}
+     */
+    R<RpcStatus> createCredential(CreateCredentialParam requestParam);
+
+    /**
+     * Update credential using the given user and password.
+     * You must provide the original password to check if the operation is valid.
+     * Note: after this operation, client won't change the related header of this connection.
+     * So if you update credential for this connection, the connection may be invalid.
+     *
+     * @param requestParam {@link UpdateCredentialParam}
+     * @return {status:result code, data:RpcStatus{msg: result message}}
+     */
+    R<RpcStatus> updateCredential(UpdateCredentialParam requestParam);
+
+    /**
+     * Delete credential corresponding to the user.
+     *
+     * @param requestParam {@link DeleteCredentialParam}
+     * @return {status:result code, data:RpcStatus{msg: result message}}
+     */
+    R<RpcStatus> deleteCredential(DeleteCredentialParam requestParam);
+
+    /**
+     * List all user names.
+     *
+     * @param requestParam {@link ListCredUsersParam}
+     * @return {status:result code, data:ListCredUsersResponse{status,info}}
+     */
+    R<ListCredUsersResponse> listCredUsers(ListCredUsersParam requestParam);
 }

+ 30 - 5
src/main/java/io/milvus/client/MilvusMultiServiceClient.java

@@ -29,6 +29,7 @@ import io.milvus.param.alias.CreateAliasParam;
 import io.milvus.param.alias.DropAliasParam;
 import io.milvus.param.collection.*;
 import io.milvus.param.control.*;
+import io.milvus.param.credential.*;
 import io.milvus.param.dml.*;
 import io.milvus.param.index.*;
 import io.milvus.param.partition.*;
@@ -52,9 +53,7 @@ public class MilvusMultiServiceClient implements MilvusClient {
         List<ServerSetting> serverSettings = multiConnectParam.getHosts().stream()
                 .map(host -> {
 
-                    MilvusClient milvusClient = buildMilvusClient(host, multiConnectParam.getConnectTimeoutMs(),
-                            multiConnectParam.getKeepAliveTimeMs(), multiConnectParam.getKeepAliveTimeoutMs(),
-                            multiConnectParam.isKeepAliveWithoutCalls(), multiConnectParam.getIdleTimeoutMs());
+                    MilvusClient milvusClient = buildMilvusClient(host, multiConnectParam);
 
                     return ServerSetting.newBuilder()
                             .withHost(host)
@@ -71,8 +70,13 @@ public class MilvusMultiServiceClient implements MilvusClient {
                 .build();
     }
 
-    private MilvusClient buildMilvusClient(ServerAddress host, long connectTimeoutMsm, long keepAliveTimeMs,
-                                           long keepAliveTimeoutMs, boolean keepAliveWithoutCalls, long idleTimeoutMs) {
+    private MilvusClient buildMilvusClient(ServerAddress host, MultiConnectParam multiConnectParam) {
+        long connectTimeoutMsm = multiConnectParam.getConnectTimeoutMs();
+        long keepAliveTimeMs = multiConnectParam.getKeepAliveTimeMs();
+        long keepAliveTimeoutMs = multiConnectParam.getKeepAliveTimeoutMs();
+        boolean keepAliveWithoutCalls = multiConnectParam.isKeepAliveWithoutCalls();
+        long idleTimeoutMs = multiConnectParam.getIdleTimeoutMs();
+
         ConnectParam clusterConnectParam = ConnectParam.newBuilder()
                 .withHost(host.getHost())
                 .withPort(host.getPort())
@@ -81,6 +85,7 @@ public class MilvusMultiServiceClient implements MilvusClient {
                 .withKeepAliveTimeout(keepAliveTimeoutMs, TimeUnit.MILLISECONDS)
                 .keepAliveWithoutCalls(keepAliveWithoutCalls)
                 .withIdleTimeout(idleTimeoutMs, TimeUnit.MILLISECONDS)
+                .withAuthorization(multiConnectParam.getAuthorization())
                 .build();
         return new MilvusServiceClient(clusterConnectParam);
     }
@@ -375,6 +380,26 @@ public class MilvusMultiServiceClient implements MilvusClient {
         return this.clusterFactory.getMaster().getClient().getCompactionStateWithPlans(requestParam);
     }
 
+    @Override
+    public R<RpcStatus> createCredential(CreateCredentialParam requestParam) {
+        return this.clusterFactory.getMaster().getClient().createCredential(requestParam);
+    }
+
+    @Override
+    public R<RpcStatus> updateCredential(UpdateCredentialParam requestParam) {
+        return this.clusterFactory.getMaster().getClient().updateCredential(requestParam);
+    }
+
+    @Override
+    public R<RpcStatus> deleteCredential(DeleteCredentialParam requestParam) {
+        return this.clusterFactory.getMaster().getClient().deleteCredential(requestParam);
+    }
+
+    @Override
+    public R<ListCredUsersResponse> listCredUsers(ListCredUsersParam requestParam) {
+        return this.clusterFactory.getMaster().getClient().listCredUsers(requestParam);
+    }
+
     private <T> R<T> handleResponse(List<R<T>> response) {
         if (CollectionUtils.isNotEmpty(response)) {
             R<T> rSuccess = null;

+ 5 - 0
src/main/java/io/milvus/client/MilvusServiceClient.java

@@ -20,6 +20,7 @@
 package io.milvus.client;
 
 import io.grpc.*;
+import io.grpc.stub.MetadataUtils;
 import io.milvus.grpc.MilvusServiceGrpc;
 import io.milvus.param.ConnectParam;
 
@@ -33,6 +34,9 @@ public class MilvusServiceClient extends AbstractMilvusGrpcClient {
     private final MilvusServiceGrpc.MilvusServiceFutureStub futureStub;
 
     public MilvusServiceClient(@NonNull ConnectParam connectParam) {
+        Metadata metadata = new Metadata();
+        metadata.put(Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER), connectParam.getAuthorization());
+
         channel = ManagedChannelBuilder.forAddress(connectParam.getHost(), connectParam.getPort())
                 .usePlaintext()
                 .maxInboundMessageSize(Integer.MAX_VALUE)
@@ -40,6 +44,7 @@ public class MilvusServiceClient extends AbstractMilvusGrpcClient {
                 .keepAliveTimeout(connectParam.getKeepAliveTimeoutMs(), TimeUnit.MILLISECONDS)
                 .keepAliveWithoutCalls(connectParam.isKeepAliveWithoutCalls())
                 .idleTimeout(connectParam.getIdleTimeoutMs(), TimeUnit.MILLISECONDS)
+                .intercept(MetadataUtils.newAttachHeadersInterceptor(metadata))
                 .build();
         blockingStub = MilvusServiceGrpc.newBlockingStub(channel);
         futureStub = MilvusServiceGrpc.newFutureStub(channel);

+ 30 - 0
src/main/java/io/milvus/param/ConnectParam.java

@@ -22,6 +22,8 @@ package io.milvus.param;
 import io.milvus.exception.ParamException;
 import lombok.NonNull;
 
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -35,6 +37,7 @@ public class ConnectParam {
     private final long keepAliveTimeoutMs;
     private final boolean keepAliveWithoutCalls;
     private final long idleTimeoutMs;
+    private final String authorization;
 
     private ConnectParam(@NonNull Builder builder) {
         this.host = builder.host;
@@ -44,6 +47,7 @@ public class ConnectParam {
         this.keepAliveTimeoutMs = builder.keepAliveTimeoutMs;
         this.keepAliveWithoutCalls = builder.keepAliveWithoutCalls;
         this.idleTimeoutMs = builder.idleTimeoutMs;
+        this.authorization = builder.authorization;
     }
 
     public String getHost() {
@@ -74,6 +78,10 @@ public class ConnectParam {
         return idleTimeoutMs;
     }
 
+    public String getAuthorization() {
+        return authorization;
+    }
+
     public static Builder newBuilder() {
         return new Builder();
     }
@@ -89,6 +97,7 @@ public class ConnectParam {
         private long keepAliveTimeoutMs = 20000;
         private boolean keepAliveWithoutCalls = false;
         private long idleTimeoutMs = TimeUnit.MILLISECONDS.convert(24, TimeUnit.HOURS);
+        private String authorization = "";
 
         private Builder() {
         }
@@ -174,6 +183,27 @@ public class ConnectParam {
             return this;
         }
 
+        /**
+         * Sets the username and password for this connection
+         * @param username current user
+         * @param password password
+         * @return <code>Builder</code>
+         */
+        public Builder withAuthorization(@NonNull String username, @NonNull String password) {
+            this.authorization = Base64.getEncoder().encodeToString(String.format("%s:%s", username, password).getBytes(StandardCharsets.UTF_8));
+            return this;
+        }
+
+        /**
+         * Sets the authorization for this connection
+         * @param authorization the authorization info that has included the encoded username and password info
+         * @return <code>Builder</code>
+         */
+        public Builder withAuthorization(@NonNull String authorization) {
+            this.authorization = authorization;
+            return this;
+        }
+
         /**
          * Verifies parameters and creates a new {@link ConnectParam} instance.
          *

+ 20 - 0
src/main/java/io/milvus/param/MultiConnectParam.java

@@ -4,6 +4,8 @@ import io.milvus.exception.ParamException;
 import lombok.NonNull;
 import org.apache.commons.collections4.CollectionUtils;
 
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
@@ -18,6 +20,7 @@ public class MultiConnectParam {
     private final long keepAliveTimeoutMs;
     private final boolean keepAliveWithoutCalls;
     private final long idleTimeoutMs;
+    private final String authorization;
 
     private MultiConnectParam(@NonNull Builder builder) {
         this.hosts = builder.hosts;
@@ -27,6 +30,7 @@ public class MultiConnectParam {
         this.keepAliveTimeoutMs = builder.keepAliveTimeoutMs;
         this.keepAliveWithoutCalls = builder.keepAliveWithoutCalls;
         this.idleTimeoutMs = builder.idleTimeoutMs;
+        this.authorization = builder.authorization;
     }
 
     public List<ServerAddress> getHosts() {
@@ -57,6 +61,10 @@ public class MultiConnectParam {
         return idleTimeoutMs;
     }
 
+    public String getAuthorization() {
+        return authorization;
+    }
+
     public static Builder newBuilder() {
         return new Builder();
     }
@@ -72,6 +80,7 @@ public class MultiConnectParam {
         private long keepAliveTimeoutMs = 20000;
         private boolean keepAliveWithoutCalls = false;
         private long idleTimeoutMs = TimeUnit.MILLISECONDS.convert(24, TimeUnit.HOURS);
+        private String authorization = "";
 
         private Builder() {
         }
@@ -157,6 +166,17 @@ public class MultiConnectParam {
             return this;
         }
 
+        /**
+         * Sets the username and password for this connection
+         * @param username current user
+         * @param password password
+         * @return <code>Builder</code>
+         */
+        public Builder withAuthorization(@NonNull String username, @NonNull String password) {
+            this.authorization = Base64.getEncoder().encodeToString(String.format("%s:%s", username, password).getBytes(StandardCharsets.UTF_8));
+            return this;
+        }
+
         /**
          * Verifies parameters and creates a new {@link MultiConnectParam} instance.
          *

+ 79 - 0
src/main/java/io/milvus/param/credential/CreateCredentialParam.java

@@ -0,0 +1,79 @@
+package io.milvus.param.credential;
+
+import io.milvus.exception.ParamException;
+import io.milvus.param.ParamUtils;
+import lombok.Getter;
+import lombok.NonNull;
+
+@Getter
+public class CreateCredentialParam {
+    private final String username;
+    private final String password;
+
+    private CreateCredentialParam(@NonNull CreateCredentialParam.Builder builder) {
+        this.username = builder.username;
+        this.password = builder.password;
+    }
+
+    public static CreateCredentialParam.Builder newBuilder() {
+        return new CreateCredentialParam.Builder();
+    }
+
+    /**
+     * Builder for {@link CreateCredentialParam} class.
+     */
+    public static final class Builder {
+        private String username;
+        private String password;
+
+        private Builder() {
+        }
+
+        /**
+         * Sets the username. Username cannot be empty or null.
+         *
+         * @param username username
+         * @return <code>Builder</code>
+         */
+        public CreateCredentialParam.Builder withUsername(@NonNull String username) {
+            this.username = username;
+            return this;
+        }
+
+        /**
+         * Sets the password. Password cannot be empty or null.
+         *
+         * @param password password
+         * @return <code>Builder</code>
+         */
+        public CreateCredentialParam.Builder withPassword(@NonNull String password) {
+            this.password = password;
+            return this;
+        }
+
+        /**
+         * Verifies parameters and creates a new {@link CreateCredentialParam} instance.
+         *
+         * @return {@link CreateCredentialParam}
+         */
+        public CreateCredentialParam build() throws ParamException {
+            ParamUtils.CheckNullEmptyString(username, "Username");
+            ParamUtils.CheckNullEmptyString(password, "Password");
+
+            return new CreateCredentialParam(this);
+        }
+    }
+
+    /**
+     * Constructs a <code>String</code> by {@link CreateCredentialParam} instance.
+     *
+     * @return <code>String</code>
+     */
+    @Override
+    public String toString() {
+        return "CreateCredentialParam{" +
+                "username='" + username + '\'' +
+                ", password='" + password + '\'' +
+                '}';
+    }
+}

+ 63 - 0
src/main/java/io/milvus/param/credential/DeleteCredentialParam.java

@@ -0,0 +1,63 @@
+package io.milvus.param.credential;
+
+import io.milvus.exception.ParamException;
+import io.milvus.param.ParamUtils;
+import lombok.Getter;
+import lombok.NonNull;
+
+@Getter
+public class DeleteCredentialParam {
+    private final String username;
+
+    private DeleteCredentialParam(@NonNull DeleteCredentialParam.Builder builder) {
+        this.username = builder.username;
+    }
+
+    public static DeleteCredentialParam.Builder newBuilder() {
+        return new DeleteCredentialParam.Builder();
+    }
+
+    /**
+     * Builder for {@link DeleteCredentialParam} class.
+     */
+    public static final class Builder {
+        private String username;
+
+        private Builder() {
+        }
+
+        /**
+         * Sets the username. Username cannot be empty or null.
+         *
+         * @param username username
+         * @return <code>Builder</code>
+         */
+        public DeleteCredentialParam.Builder withUsername(@NonNull String username) {
+            this.username = username;
+            return this;
+        }
+
+        /**
+         * Verifies parameters and creates a new {@link DeleteCredentialParam} instance.
+         *
+         * @return {@link DeleteCredentialParam}
+         */
+        public DeleteCredentialParam build() throws ParamException {
+            ParamUtils.CheckNullEmptyString(username, "Username");
+
+            return new DeleteCredentialParam(this);
+        }
+    }
+
+    /**
+     * Constructs a <code>String</code> by {@link DeleteCredentialParam} instance.
+     *
+     * @return <code>String</code>
+     */
+    @Override
+    public String toString() {
+        return "DeleteCredentialParam{" +
+                "username='" + username + '\'' +
+                '}';
+    }
+}

+ 44 - 0
src/main/java/io/milvus/param/credential/ListCredUsersParam.java

@@ -0,0 +1,44 @@
+package io.milvus.param.credential;
+
+import io.milvus.exception.ParamException;
+import lombok.Getter;
+import lombok.NonNull;
+
+@Getter
+public class ListCredUsersParam {
+
+    private ListCredUsersParam(@NonNull ListCredUsersParam.Builder builder) {
+    }
+
+    public static ListCredUsersParam.Builder newBuilder() {
+        return new ListCredUsersParam.Builder();
+    }
+
+    /**
+     * Builder for {@link ListCredUsersParam} class.
+     */
+    public static final class Builder {
+
+        private Builder() {
+        }
+
+        /**
+         * Verifies parameters and creates a new {@link ListCredUsersParam} instance.
+         *
+         * @return {@link ListCredUsersParam}
+         */
+        public ListCredUsersParam build() throws ParamException {
+            return new ListCredUsersParam(this);
+        }
+    }
+
+    /**
+     * Constructs a <code>String</code> by {@link ListCredUsersParam} instance.
+     *
+     * @return <code>String</code>
+     */
+    @Override
+    public String toString() {
+        return "ListCredUsersParam{}";
+    }
+}

+ 95 - 0
src/main/java/io/milvus/param/credential/UpdateCredentialParam.java

@@ -0,0 +1,95 @@
+package io.milvus.param.credential;
+
+import io.milvus.exception.ParamException;
+import io.milvus.param.ParamUtils;
+import lombok.Getter;
+import lombok.NonNull;
+
+@Getter
+public class UpdateCredentialParam {
+    private final String username;
+    private final String oldPassword;
+    private final String newPassword;
+
+    private UpdateCredentialParam(@NonNull UpdateCredentialParam.Builder builder) {
+        this.username = builder.username;
+        this.oldPassword = builder.oldPassword;
+        this.newPassword = builder.newPassword;
+    }
+
+    public static UpdateCredentialParam.Builder newBuilder() {
+        return new UpdateCredentialParam.Builder();
+    }
+
+    /**
+     * Builder for {@link UpdateCredentialParam} class.
+     */
+    public static final class Builder {
+        private String username;
+        private String oldPassword;
+        private String newPassword;
+
+        private Builder() {
+        }
+
+        /**
+         * Sets the username. Username cannot be empty or null.
+         *
+         * @param username username
+         * @return <code>Builder</code>
+         */
+        public UpdateCredentialParam.Builder withUsername(@NonNull String username) {
+            this.username = username;
+            return this;
+        }
+
+        /**
+         * Sets the old password. Old password cannot be empty or null.
+         *
+         * @param password old password
+         * @return <code>Builder</code>
+         */
+        public UpdateCredentialParam.Builder withOldPassword(@NonNull String password) {
+            this.oldPassword = password;
+            return this;
+        }
+
+        /**
+         * Sets the new password. New password cannot be empty or null.
+         *
+         * @param password password
+         * @return <code>Builder</code>
+         */
+        public UpdateCredentialParam.Builder withNewPassword(@NonNull String password) {
+            this.newPassword = password;
+            return this;
+        }
+
+        /**
+         * Verifies parameters and creates a new {@link UpdateCredentialParam} instance.
+         *
+         * @return {@link UpdateCredentialParam}
+         */
+        public UpdateCredentialParam build() throws ParamException {
+            ParamUtils.CheckNullEmptyString(username, "Username");
+            ParamUtils.CheckNullEmptyString(oldPassword, "OldPassword");
+            ParamUtils.CheckNullEmptyString(newPassword, "NewPassword");
+
+            return new UpdateCredentialParam(this);
+        }
+    }
+
+    /**
+     * Constructs a <code>String</code> by {@link UpdateCredentialParam} instance.
+     *
+     * @return <code>String</code>
+     */
+    @Override
+    public String toString() {
+        return "UpdateCredentialParam{" +
+                "username='" + username + '\'' +
+                ", oldPassword='" + oldPassword + '\'' +
+                ", newPassword='" + newPassword + '\'' +
+                '}';
+    }
+}

+ 38 - 1
src/test/java/io/milvus/client/MilvusClientDockerTest.java

@@ -23,6 +23,7 @@ import com.google.common.util.concurrent.ListenableFuture;
 import io.milvus.grpc.*;
 import io.milvus.param.*;
 import io.milvus.param.collection.*;
+//import io.milvus.param.credential.*;
 import io.milvus.param.dml.InsertParam;
 import io.milvus.param.dml.QueryParam;
 import io.milvus.param.dml.SearchParam;
@@ -129,7 +130,7 @@ class MilvusClientDockerTest {
     public static void setUp() {
         startDockerContainer();
 
-        ConnectParam connectParam = connectParamBuilder().build();
+        ConnectParam connectParam = connectParamBuilder().withAuthorization("root", "Milvus").build();
         client = new MilvusServiceClient(connectParam);
         generator = new RandomStringGenerator.Builder().withinRange('a', 'z').build();
     }
@@ -727,4 +728,40 @@ class MilvusClientDockerTest {
         R<RpcStatus> dropR = client.dropCollection(dropParam);
         assertEquals(R.Status.Success.getCode(), dropR.getStatus().intValue());
     }
+
+    // this case can be executed when the milvus image of version 2.1 is published.
+    @Test
+    void testCredential() {
+        /*
+        R<ListCredUsersResponse> responseList = client.listCredUsers(ListCredUsersParam.newBuilder().build());
+        assertEquals(R.Status.Success.getCode(), responseList.getStatus().intValue());
+        int originSize = responseList.getData().getUsernamesList().size();
+
+        String username = "java_test";
+
+        R<RpcStatus> createR = client.createCredential(CreateCredentialParam
+                .newBuilder()
+                .withUsername(username)
+                .withPassword("123456")
+                .build());
+        assertEquals(R.Status.Success.getCode(), createR.getStatus().intValue());
+
+        R<RpcStatus> updateR = client.updateCredential(UpdateCredentialParam
+                .newBuilder()
+                .withUsername(username)
+                .withOldPassword("123456")
+                .withNewPassword("100000")
+                .build());
+        assertEquals(R.Status.Success.getCode(), updateR.getStatus().intValue());
+
+        R<ListCredUsersResponse> responseList2 = client.listCredUsers(ListCredUsersParam.newBuilder().build());
+        assertEquals(R.Status.Success.getCode(), responseList2.getStatus().intValue());
+        assertEquals(originSize + 1, responseList2.getData().getUsernamesList().size());
+
+        R<RpcStatus> deleteR = client.deleteCredential(DeleteCredentialParam
+                .newBuilder()
+                .withUsername(username)
+                .build());
+        assertEquals(R.Status.Success.getCode(), deleteR.getStatus().intValue());*/
+    }
 }

+ 1 - 1
src/test/java/io/milvus/client/MilvusMultiClientDockerTest.java

@@ -126,7 +126,7 @@ class MilvusMultiClientDockerTest {
     public static void setUp() throws InterruptedException {
         startDockerContainer();
 
-        MultiConnectParam connectParam = multiConnectParamBuilder().build();
+        MultiConnectParam connectParam = multiConnectParamBuilder().withAuthorization("root", "Milvus").build();
         client = new MilvusMultiServiceClient(connectParam);
 //        TimeUnit.SECONDS.sleep(10);
         generator = new RandomStringGenerator.Builder().withinRange('a', 'z').build();

+ 92 - 0
src/test/java/io/milvus/client/MilvusServiceClientTest.java

@@ -30,6 +30,7 @@ import io.milvus.param.alias.CreateAliasParam;
 import io.milvus.param.alias.DropAliasParam;
 import io.milvus.param.collection.*;
 import io.milvus.param.control.*;
+import io.milvus.param.credential.*;
 import io.milvus.param.dml.*;
 import io.milvus.param.index.*;
 import io.milvus.param.partition.*;
@@ -2134,6 +2135,97 @@ class MilvusServiceClientTest {
         testFuncByName("getCompactionStateWithPlans", param);
     }
 
+    @Test
+    void createCredentialParam() {
+        assertThrows(ParamException.class, () -> CreateCredentialParam
+                .newBuilder()
+                .withUsername(" ")
+                .withPassword("password")
+                .build()
+        );
+
+        assertThrows(ParamException.class, () -> CreateCredentialParam
+                .newBuilder()
+                .withUsername("username")
+                .withPassword(" ")
+                .build()
+        );
+    }
+
+    @Test
+    void createCredential() {
+        testFuncByName("createCredential", CreateCredentialParam
+                .newBuilder()
+                .withUsername("username")
+                .withPassword("password")
+                .build()
+        );
+    }
+
+    @Test
+    void updateCredentialParam() {
+        assertThrows(ParamException.class, () -> UpdateCredentialParam
+                .newBuilder()
+                .withUsername("  ")
+                .withOldPassword("oldPassword")
+                .withNewPassword("newPassword")
+                .build()
+        );
+
+        assertThrows(ParamException.class, () -> UpdateCredentialParam
+                .newBuilder()
+                .withUsername("username")
+                .withOldPassword("  ")
+                .withNewPassword("newPassword")
+                .build()
+        );
+
+        assertThrows(ParamException.class, () -> UpdateCredentialParam
+                .newBuilder()
+                .withUsername("username")
+                .withOldPassword("oldPassword")
+                .withNewPassword("  ")
+                .build()
+        );
+    }
+
+    @Test
+    void updateCredential() {
+        testFuncByName("updateCredential", UpdateCredentialParam
+                .newBuilder()
+                .withUsername("username")
+                .withOldPassword("oldPassword")
+                .withNewPassword("newPassword")
+                .build()
+        );
+    }
+
+    @Test
+    void deleteCredentialParam() {
+        assertThrows(ParamException.class, () -> DeleteCredentialParam
+                .newBuilder()
+                .withUsername(" ")
+                .build()
+        );
+    }
+
+    @Test
+    void deleteCredential() {
+        testFuncByName("deleteCredential", DeleteCredentialParam
+                .newBuilder()
+                .withUsername("username")
+                .build()
+        );
+    }
+
+    @Test
+    void listCredUsers() {
+        testFuncByName("listCredUsers", ListCredUsersParam
+                .newBuilder()
+                .build()
+        );
+    }
+
     ////////////////////////////////////////////////////////////////////////////////////
     // Response wrapper test
     private void testScalarField(ScalarField field, DataType type, long rowCount) {

+ 55 - 1
src/test/java/io/milvus/server/MockMilvusServerImpl.java

@@ -19,7 +19,8 @@
 
 package io.milvus.server;
 
-import io.milvus.grpc.MilvusServiceGrpc;
+import io.grpc.stub.StreamObserver;
+import io.milvus.grpc.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -68,6 +69,11 @@ public class MockMilvusServerImpl extends MilvusServiceGrpc.MilvusServiceImplBas
     private io.milvus.grpc.ManualCompactionResponse respManualCompaction;
     private io.milvus.grpc.GetCompactionPlansResponse respGetCompactionPlans;
 
+    private io.milvus.grpc.Status respCreateCredential;
+    private io.milvus.grpc.Status respUpdateCredential;
+    private io.milvus.grpc.Status respDeleteCredential;
+    private io.milvus.grpc.ListCredUsersResponse respListCredUsers;
+
     public MockMilvusServerImpl() {
     }
 
@@ -588,6 +594,54 @@ public class MockMilvusServerImpl extends MilvusServiceGrpc.MilvusServiceImplBas
         responseObserver.onCompleted();
     }
 
+    @Override
+    public void createCredential(CreateCredentialRequest request, StreamObserver<Status> responseObserver) {
+        logger.info("createCredential() call");
+
+        responseObserver.onNext(respCreateCredential);
+        responseObserver.onCompleted();
+    }
+
+    public void setRespCreateCredential(Status respCreateCredential) {
+        this.respCreateCredential = respCreateCredential;
+    }
+
+    @Override
+    public void updateCredential(UpdateCredentialRequest request, StreamObserver<Status> responseObserver) {
+        logger.info("updateCredential() call");
+
+        responseObserver.onNext(respUpdateCredential);
+        responseObserver.onCompleted();
+    }
+
+    public void setRespUpdateCredential(Status respUpdateCredential) {
+        this.respUpdateCredential = respUpdateCredential;
+    }
+
+    @Override
+    public void deleteCredential(DeleteCredentialRequest request, StreamObserver<Status> responseObserver) {
+        logger.info("deleteCredential() call");
+
+        responseObserver.onNext(respDeleteCredential);
+        responseObserver.onCompleted();
+    }
+
+    public void setRespDeleteCredential(Status respDeleteCredential) {
+        this.respDeleteCredential = respDeleteCredential;
+    }
+
+    @Override
+    public void listCredUsers(ListCredUsersRequest request, StreamObserver<ListCredUsersResponse> responseObserver) {
+        logger.info("listCredUsers() call");
+
+        responseObserver.onNext(respListCredUsers);
+        responseObserver.onCompleted();
+    }
+
+    public void setRespListCredUsers(ListCredUsersResponse respListCredUsers) {
+        this.respListCredUsers = respListCredUsers;
+    }
+
     public void setGetCompactionPlansResponse(io.milvus.grpc.GetCompactionPlansResponse resp) {
         respGetCompactionPlans = resp;
     }