This is an automated email from the ASF dual-hosted git repository.

tanjian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new 1310719  add token authentication between agent and oap receiver. 
(#4197)
1310719 is described below

commit 131071964523e26243d7a2db4b3fd30022c93d9b
Author: Jared Tan <jian....@daocloud.io>
AuthorDate: Sun Jan 12 23:08:39 2020 +0800

    add token authentication between agent and oap receiver. (#4197)
    
    * add token authentication between agent and oap receiver.
    
    * revert ui.
    
    * fix code style.
    
    * update docs.
    
    * Update docs/en/setup/backend/backend-token-auth.md
    
    Co-Authored-By: kezhenxu94 <kezhenx...@apache.org>
    
    * fix hits.
    
    * filter
    
    * revert yml.
    
    * update logical.
    
    * fix codestyle check.
    
    * fix ci and add e2e test case.
    
    * revert mistake commit.
    
    * fix ci
    
    * remove duplicate maven dependency.
    
    * revert pom
    
    * revert unchanged.
    
    * update javadocs.
    
    * update logical.
    
    Co-authored-by: kezhenxu94 <kezhenx...@163.com>
---
 docker/oap-es7/docker-entrypoint.sh                |   1 +
 docker/oap/docker-entrypoint.sh                    |   1 +
 docs/en/setup/backend/backend-setup.md             |   1 +
 docs/en/setup/backend/backend-token-auth.md        |  43 +++
 .../src/main/resources/application.yml             |   1 +
 .../server/core/server/GRPCHandlerRegister.java    |   4 +-
 .../core/server/GRPCHandlerRegisterImpl.java       |  10 +-
 .../server/auth/AuthenticationInterceptor.java     |  71 ++++
 .../library/server/grpc/GRPCServerConfig.java      |  71 ----
 .../server/ReceiverGRPCHandlerRegister.java        |  32 +-
 .../sharing/server/SharingServerConfig.java        |   3 +-
 .../server/SharingServerModuleProvider.java        |  17 +-
 test/e2e/e2e-agent-auth/pom.xml                    | 142 ++++++++
 .../e2e-agent-auth/src/docker/rc.d/rc0-prepare.sh  |  42 +++
 .../e2e-agent-auth/src/docker/rc.d/rc1-startup.sh  |  53 +++
 .../e2e/sample/client/SampleClientApplication.java |  20 +-
 .../e2e/sample/client/TestController.java          |  49 +++
 .../apache/skywalking/e2e/sample/client/User.java  |  38 +-
 .../skywalking/e2e/sample/client/UserRepo.java     |  13 +-
 .../src/main/resources/application.yml             |  35 ++
 .../skywalking/e2e/SampleVerificationITCase.java   | 383 +++++++++++++++++++++
 ...king.e2e.SampleVerificationITCase.endpoints.yml |  27 ++
 ...king.e2e.SampleVerificationITCase.instances.yml |  34 ++
 ...ampleVerificationITCase.serviceInstanceTopo.yml |  41 +++
 ...lking.e2e.SampleVerificationITCase.services.yml |  25 ++
 ...kywalking.e2e.SampleVerificationITCase.topo.yml |  46 +++
 ...walking.e2e.SampleVerificationITCase.traces.yml |  31 ++
 test/e2e/pom.xml                                   |   1 +
 test/plugin/containers/jvm-container/docker/run.sh |   1 +
 .../containers/tomcat-container/docker/catalina.sh |   1 +
 30 files changed, 1126 insertions(+), 111 deletions(-)

diff --git a/docker/oap-es7/docker-entrypoint.sh 
b/docker/oap-es7/docker-entrypoint.sh
index aca6994..b1ab944 100755
--- a/docker/oap-es7/docker-entrypoint.sh
+++ b/docker/oap-es7/docker-entrypoint.sh
@@ -338,6 +338,7 @@ receiver-sharing-server:
    maxMessageSize: \${SW_RECEIVER_SHARING_MAX_MESSAGE_SIZE:0}
    gRPCThreadPoolSize: \${SW_RECEIVER_SHARING_GRPC_THREAD_POOL_SIZE:0}
    gRPCThreadPoolQueueSize: 
\${SW_RECEIVER_SHARING_GRPC_THREAD_POOL_QUEUE_SIZE:0}
+   authentication: \${SW_AUTHENTICATION:""}
 receiver-register:
   default:
 receiver-trace:
diff --git a/docker/oap/docker-entrypoint.sh b/docker/oap/docker-entrypoint.sh
index 8fb2abd..7b61db5 100755
--- a/docker/oap/docker-entrypoint.sh
+++ b/docker/oap/docker-entrypoint.sh
@@ -339,6 +339,7 @@ receiver-sharing-server:
    maxMessageSize: \${SW_RECEIVER_SHARING_MAX_MESSAGE_SIZE:0}
    gRPCThreadPoolSize: \${SW_RECEIVER_SHARING_GRPC_THREAD_POOL_SIZE:0}
    gRPCThreadPoolQueueSize: 
\${SW_RECEIVER_SHARING_GRPC_THREAD_POOL_QUEUE_SIZE:0}
+   authentication: \${SW_AUTHENTICATION:""}
 receiver-register:
   default:
 receiver-trace:
diff --git a/docs/en/setup/backend/backend-setup.md 
b/docs/en/setup/backend/backend-setup.md
index 9555fd1..3168565 100755
--- a/docs/en/setup/backend/backend-setup.md
+++ b/docs/en/setup/backend/backend-setup.md
@@ -66,6 +66,7 @@ DB. But clearly, it doesn't fit the product env. In here, you 
could find what ot
 Choose the one you like, we are also welcome anyone to contribute new storage 
implementor,
 1. [Set receivers](backend-receivers.md). You could choose receivers by your 
requirements, most receivers
 are harmless, at least our default receivers are. You would set and active all 
receivers provided.
+1. [Token authentication](backend-token-auth.md). You could add token 
authentication mechanisms to avoid `OAP` receiving untrusted data.  
 1. Do [trace sampling](trace-sampling.md) at backend. This sample keep the 
metrics accurate, only don't save some of traces
 in storage based on rate.
 1. Follow [slow DB statement threshold](slow-db-statement.md) config document 
to understand that, 
diff --git a/docs/en/setup/backend/backend-token-auth.md 
b/docs/en/setup/backend/backend-token-auth.md
index e69de29..9579a23 100644
--- a/docs/en/setup/backend/backend-token-auth.md
+++ b/docs/en/setup/backend/backend-token-auth.md
@@ -0,0 +1,43 @@
+# Token Authentication
+## Supported version
+7.0.0+
+
+## Why need token authentication after we have TLS?
+TLS is about transport security, which makes sure the network can be trusted. 
+The token authentication is about monitoring application data **can be 
trusted**.
+
+## Token 
+In current version, Token is considered as a simple string.
+
+### Set Token
+1. Set token in agent.config file
+```properties
+# Authentication active is based on backend setting, see application.yml for 
more details.
+agent.authentication = ${SW_AGENT_AUTHENTICATION:xxxx}
+```
+
+2. Set token in `application.yml` file
+```yaml
+······
+receiver-sharing-server:
+  default:
+    authentication: ${SW_AUTHENTICATION:""}
+······
+```
+
+## Authentication fails
+The Skywalking OAP verifies every request from agent, only allows requests 
whose token matches the one configured in `application.yml`.
+
+If the token is not right, you will see the following log in agent
+```
+org.apache.skywalking.apm.dependencies.io.grpc.StatusRuntimeException: 
PERMISSION_DENIED
+```
+
+## FAQ
+### Can I use token authentication instead of TLS?
+No, you shouldn't. In tech way, you can of course, but token and TLS are used 
for untrusted network env. In that circumstance,
+TLS has higher priority than this. Token can be trusted only under TLS 
protection.Token can be stolen easily if you 
+send it through a non-TLS network.
+
+### Do you support other authentication mechanisms? Such as ak/sk?
+For now, no. But we appreciate someone contributes this feature. 
diff --git a/oap-server/server-bootstrap/src/main/resources/application.yml 
b/oap-server/server-bootstrap/src/main/resources/application.yml
index c2281ff..3f79711 100755
--- a/oap-server/server-bootstrap/src/main/resources/application.yml
+++ b/oap-server/server-bootstrap/src/main/resources/application.yml
@@ -137,6 +137,7 @@ storage:
 #    metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}
 receiver-sharing-server:
   default:
+    authentication: ${SW_AUTHENTICATION:""}
 receiver-register:
   default:
 receiver-trace:
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegister.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegister.java
index 3244d44..c6a39a5 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegister.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegister.java
@@ -22,11 +22,13 @@ import io.grpc.*;
 import org.apache.skywalking.oap.server.library.module.Service;
 
 /**
- * @author peng-yongsheng
+ * @author peng-yongsheng, jian.tan
  */
 public interface GRPCHandlerRegister extends Service {
 
     void addHandler(BindableService handler);
 
     void addHandler(ServerServiceDefinition definition);
+
+    void addFilter(ServerInterceptor interceptor);
 }
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegisterImpl.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegisterImpl.java
index 229c3ca..ca0b076 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegisterImpl.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegisterImpl.java
@@ -18,11 +18,13 @@
 
 package org.apache.skywalking.oap.server.core.server;
 
-import io.grpc.*;
+import io.grpc.BindableService;
+import io.grpc.ServerInterceptor;
+import io.grpc.ServerServiceDefinition;
 import org.apache.skywalking.oap.server.library.server.grpc.GRPCServer;
 
 /**
- * @author peng-yongsheng
+ * @author peng-yongsheng, jian.tan
  */
 public class GRPCHandlerRegisterImpl implements GRPCHandlerRegister {
 
@@ -39,4 +41,8 @@ public class GRPCHandlerRegisterImpl implements 
GRPCHandlerRegister {
     @Override public void addHandler(ServerServiceDefinition definition) {
         server.addHandler(definition);
     }
+
+    @Override public void addFilter(ServerInterceptor interceptor) {
+
+    }
 }
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/auth/AuthenticationInterceptor.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/auth/AuthenticationInterceptor.java
new file mode 100644
index 0000000..0a688bb
--- /dev/null
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/auth/AuthenticationInterceptor.java
@@ -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.skywalking.oap.server.core.server.auth;
+
+import io.grpc.Metadata;
+import io.grpc.ServerCall;
+import io.grpc.ServerCallHandler;
+import io.grpc.ServerInterceptor;
+import io.grpc.Status;
+
+/**
+ * Active the authentication between agent and oap receiver. token checker if 
expected token exists in application.yml
+ *
+ * @author jian.tan
+ */
+public class AuthenticationInterceptor implements ServerInterceptor {
+
+    private String expectedToken = "";
+
+    private ServerCall.Listener listener = new ServerCall.Listener() {
+    };
+
+    public AuthenticationInterceptor(String expectedToken) {
+        this.expectedToken = expectedToken;
+    }
+
+    public void setExpectedToken(String expectedToken) {
+        this.expectedToken = expectedToken;
+    }
+
+    private static final Metadata.Key<String> AUTH_HEAD_HEADER_NAME = 
Metadata.Key.of("Authentication", Metadata.ASCII_STRING_MARSHALLER);
+
+    /**
+     * intercept point of call.
+     *
+     * @param serverCall        call of server.
+     * @param metadata          of call.
+     * @param serverCallHandler handler of call.
+     * @param <REQUEST>         of call.
+     * @param <RESPONSE>        of call.
+     * @return lister of call.
+     */
+    @Override
+    public <REQUEST, RESPONSE> ServerCall.Listener<REQUEST> 
interceptCall(ServerCall<REQUEST, RESPONSE> serverCall,
+        Metadata metadata,
+        ServerCallHandler<REQUEST, RESPONSE> serverCallHandler) {
+        String token = metadata.get(AUTH_HEAD_HEADER_NAME);
+        if (expectedToken.equals(token)) {
+            return serverCallHandler.startCall(serverCall, metadata);
+        } else {
+            serverCall.close(Status.PERMISSION_DENIED, new Metadata());
+            return listener;
+        }
+    }
+}
diff --git 
a/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/GRPCServerConfig.java
 
b/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/GRPCServerConfig.java
deleted file mode 100644
index f0a5c2f..0000000
--- 
a/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/GRPCServerConfig.java
+++ /dev/null
@@ -1,71 +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.skywalking.oap.server.library.server.grpc;
-
-/**
- * @author peng-yongsheng
- */
-public abstract class GRPCServerConfig {
-
-    private String host;
-    private int port;
-    private String sslCertChainFilePath;
-    private String sslPrivateKeyFilePath;
-    private String authentication;
-
-    public String getHost() {
-        return host;
-    }
-
-    public void setHost(String host) {
-        this.host = host;
-    }
-
-    public int getPort() {
-        return port;
-    }
-
-    public void setPort(int port) {
-        this.port = port;
-    }
-
-    public String getSslCertChainFilePath() {
-        return sslCertChainFilePath;
-    }
-
-    public void setSslCertChainFilePath(String sslCertChainFilePath) {
-        this.sslCertChainFilePath = sslCertChainFilePath;
-    }
-
-    public String getSslPrivateKeyFilePath() {
-        return sslPrivateKeyFilePath;
-    }
-
-    public void setSslPrivateKeyFilePath(String sslPrivateKeyFilePath) {
-        this.sslPrivateKeyFilePath = sslPrivateKeyFilePath;
-    }
-
-    public String getAuthentication() {
-        return authentication;
-    }
-
-    public void setAuthentication(String authentication) {
-        this.authentication = authentication;
-    }
-}
diff --git 
a/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/ReceiverGRPCHandlerRegister.java
 
b/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/ReceiverGRPCHandlerRegister.java
index 2638799..4c62fa5 100644
--- 
a/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/ReceiverGRPCHandlerRegister.java
+++ 
b/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/ReceiverGRPCHandlerRegister.java
@@ -18,22 +18,48 @@
 
 package org.apache.skywalking.oap.server.receiver.sharing.server;
 
-import io.grpc.*;
+import io.grpc.BindableService;
+import io.grpc.ServerInterceptor;
+import io.grpc.ServerInterceptors;
+import io.grpc.ServerServiceDefinition;
+import java.util.LinkedList;
+import java.util.List;
 import lombok.Setter;
 import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister;
 
 /**
- * @author peng-yongsheng
+ * @author peng-yongsheng, jian.tan
  */
 public class ReceiverGRPCHandlerRegister implements GRPCHandlerRegister {
 
     @Setter private GRPCHandlerRegister grpcHandlerRegister;
+    private List<ServerInterceptor> interceptors = new LinkedList<>();
 
     @Override public void addHandler(BindableService handler) {
-        grpcHandlerRegister.addHandler(handler);
+        if (interceptors.isEmpty()) {
+            grpcHandlerRegister.addHandler(handler);
+        } else {
+            interceptors.forEach(interceptor -> {
+                grpcHandlerRegister.addHandler(handlerInterceptorBind(handler, 
interceptor));
+            });
+        }
     }
 
     @Override public void addHandler(ServerServiceDefinition definition) {
         grpcHandlerRegister.addHandler(definition);
     }
+
+    /**
+     * If you want to bind @{io.grpc.ServerInterceptor} on a handler,
+     * you must call this method before register a handler.
+     *
+     * @param interceptor of @{io.grpc.ServerInterceptor}
+     */
+    @Override public void addFilter(ServerInterceptor interceptor) {
+        this.interceptors.add(interceptor);
+    }
+
+    private ServerServiceDefinition handlerInterceptorBind(BindableService 
handler, ServerInterceptor interceptor) {
+        return ServerInterceptors.intercept(handler, interceptor);
+    }
 }
diff --git 
a/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerConfig.java
 
b/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerConfig.java
index 2f0b005..f7fa0f9 100644
--- 
a/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerConfig.java
+++ 
b/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerConfig.java
@@ -22,7 +22,7 @@ import lombok.*;
 import org.apache.skywalking.oap.server.library.module.ModuleConfig;
 
 /**
- * @author peng-yongsheng,yantaowu
+ * @author peng-yongsheng,yantaowu,jian.tan
  */
 @Getter
 @Setter
@@ -36,4 +36,5 @@ public class SharingServerConfig extends ModuleConfig {
     private int maxMessageSize;
     private int gRPCThreadPoolSize;
     private int gRPCThreadPoolQueueSize;
+    private String authentication;
 }
diff --git 
a/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerModuleProvider.java
 
b/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerModuleProvider.java
index a4ae401..9eb0803 100644
--- 
a/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerModuleProvider.java
+++ 
b/oap-server/server-receiver-plugin/skywalking-sharing-server-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/sharing/server/SharingServerModuleProvider.java
@@ -20,16 +20,24 @@ package 
org.apache.skywalking.oap.server.receiver.sharing.server;
 
 import java.util.Objects;
 import org.apache.logging.log4j.util.Strings;
+import org.apache.skywalking.apm.util.StringUtil;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import 
org.apache.skywalking.oap.server.core.remote.health.HealthCheckServiceHandler;
-import org.apache.skywalking.oap.server.core.server.*;
-import org.apache.skywalking.oap.server.library.module.*;
+import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister;
+import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegisterImpl;
+import org.apache.skywalking.oap.server.core.server.JettyHandlerRegister;
+import org.apache.skywalking.oap.server.core.server.JettyHandlerRegisterImpl;
+import 
org.apache.skywalking.oap.server.core.server.auth.AuthenticationInterceptor;
+import org.apache.skywalking.oap.server.library.module.ModuleConfig;
+import org.apache.skywalking.oap.server.library.module.ModuleDefine;
+import org.apache.skywalking.oap.server.library.module.ModuleProvider;
+import org.apache.skywalking.oap.server.library.module.ModuleStartException;
 import org.apache.skywalking.oap.server.library.server.ServerException;
 import org.apache.skywalking.oap.server.library.server.grpc.GRPCServer;
 import org.apache.skywalking.oap.server.library.server.jetty.JettyServer;
 
 /**
- * @author peng-yongsheng
+ * @author peng-yongsheng, jian.tan
  */
 public class SharingServerModuleProvider extends ModuleProvider {
 
@@ -86,6 +94,9 @@ public class SharingServerModuleProvider extends 
ModuleProvider {
             this.registerServiceImplementation(GRPCHandlerRegister.class, new 
GRPCHandlerRegisterImpl(grpcServer));
         } else {
             this.receiverGRPCHandlerRegister = new 
ReceiverGRPCHandlerRegister();
+            if (StringUtil.isNotEmpty(config.getAuthentication())) {
+                receiverGRPCHandlerRegister.addFilter(new 
AuthenticationInterceptor(config.getAuthentication()));
+            }
             this.registerServiceImplementation(GRPCHandlerRegister.class, 
receiverGRPCHandlerRegister);
         }
     }
diff --git a/test/e2e/e2e-agent-auth/pom.xml b/test/e2e/e2e-agent-auth/pom.xml
new file mode 100755
index 0000000..55e329a
--- /dev/null
+++ b/test/e2e/e2e-agent-auth/pom.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <parent>
+        <artifactId>apache-skywalking-e2e</artifactId>
+        <groupId>org.apache.skywalking</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>e2e-agent-auth</artifactId>
+
+    <properties>
+        <e2e.container.version>1.1</e2e.container.version>
+        
<e2e.container.name.prefix>skywalking-e2e-container-${build.id}-agent-auth</e2e.container.name.prefix>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+            <version>${spring.boot.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <version>${h2.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>e2e-base</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring.boot.version}</version>
+                <configuration>
+                    <executable>true</executable>
+                    <addResources>true</addResources>
+                    <excludeDevtools>true</excludeDevtools>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>io.fabric8</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <configuration>
+                    <containerNamePattern>%a-%t-%i</containerNamePattern>
+                    <images>
+                        <image>
+                            
<name>skyapm/e2e-container:${e2e.container.version}</name>
+                            <alias>${e2e.container.name.prefix}</alias>
+                            <run>
+                                <env>
+                                    
<INSTRUMENTED_SERVICE>${project.build.finalName}.jar</INSTRUMENTED_SERVICE>
+                                    
<INSTRUMENTED_SERVICE_OPTS>-Dskywalking.agent.cool_down_threshold=1
+                                    </INSTRUMENTED_SERVICE_OPTS>
+                                </env>
+                                <ports>
+                                    <port>+webapp.host:webapp.port:8080</port>
+                                    <port>+client.host:client.port:9090</port>
+                                    <port>+reboot.host:reboot.port:9091</port>
+                                </ports>
+                                <volumes>
+                                    <bind>
+                                        <volume>${sw.home}:/sw</volume>
+                                        
<volume>${project.build.directory}:/home</volume>
+                                        
<volume>${project.basedir}/src/docker/rc.d:/rc.d:ro</volume>
+                                    </bind>
+                                </volumes>
+                                <wait>
+                                    <log>SkyWalking e2e container is ready for 
tests</log>
+                                    <time>2400000</time>
+                                </wait>
+                            </run>
+                        </image>
+                    </images>
+                </configuration>
+            </plugin>
+
+            <!-- set the system properties that can be used in test codes -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <configuration>
+                    <systemPropertyVariables>
+                        <sw.webapp.host>
+                            ${webapp.host}
+                        </sw.webapp.host>
+                        <sw.webapp.port>
+                            ${webapp.port}
+                        </sw.webapp.port>
+                        <client.host>
+                            ${client.host}
+                        </client.host>
+                        <client.port>
+                            ${client.port}
+                        </client.port>
+                    </systemPropertyVariables>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>verify</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/test/e2e/e2e-agent-auth/src/docker/rc.d/rc0-prepare.sh 
b/test/e2e/e2e-agent-auth/src/docker/rc.d/rc0-prepare.sh
new file mode 100755
index 0000000..5f771bd
--- /dev/null
+++ b/test/e2e/e2e-agent-auth/src/docker/rc.d/rc0-prepare.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+# Licensed to the SkyAPM 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.
+
+# in order to make it easier to restart the OAP (by executing the restart 
script) from outside (container),
+# we'll expose a tcp port and whenever we receive a message on that port, 
we'll restart the OAP server,
+# socat will help on this to execute the script when receiving a message on 
that port
+
+apt-get update && apt-get -y install socat
+
+# socat will execute the command in a new shell, thus won't catch the original 
functions' declarations
+# so we'll put the restart command in a script file
+
+echo '
+    ps -ef | grep -v grep | grep oap.logDir | awk '"'"'{print $2}'"'"' | xargs 
--no-run-if-empty kill -9
+    rm -rf /tmp/oap/trace_buffer1
+    rm -rf /tmp/oap/mesh_buffer1
+    echo "restarting OAP server..." \
+        && SW_RECEIVER_BUFFER_PATH=/tmp/oap/trace_buffer1 \
+        && SW_SERVICE_MESH_BUFFER_PATH=/tmp/oap/mesh_buffer1 \
+        && cd /sw \
+        && bash bin/oapService.sh > /dev/null 2>&1 &
+' > /usr/bin/restart_oap
+
+sync
+
+chmod +x /usr/bin/restart_oap
+
+sync
diff --git a/test/e2e/e2e-agent-auth/src/docker/rc.d/rc1-startup.sh 
b/test/e2e/e2e-agent-auth/src/docker/rc.d/rc1-startup.sh
new file mode 100755
index 0000000..3b1388c
--- /dev/null
+++ b/test/e2e/e2e-agent-auth/src/docker/rc.d/rc1-startup.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+# Licensed to the SkyAPM 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.
+
+# set up the tcp server to listen for the restart command
+
+socat -u tcp-l:9091,fork system:'bash restart_oap' &
+
+echo 'starting OAP server...' \
+    && SW_STORAGE_ES_BULK_ACTIONS=1 \
+    && SW_STORAGE_ES_FLUSH_INTERVAL=1 \
+    && SW_RECEIVER_BUFFER_PATH=/tmp/oap/trace_buffer1 \
+    && SW_SERVICE_MESH_BUFFER_PATH=/tmp/oap/mesh_buffer1 \
+    && SW_AUTHENTICATION="test-token" \
+    && start_oap 'init'
+
+echo 'starting Web app...' \
+    && start_webapp '0.0.0.0' 8080
+
+echo 'starting instrumented services...' \
+    && start_instrumented_services
+
+check_tcp 127.0.0.1 \
+          9090 \
+          60 \
+          10 \
+          "waiting for the instrumented service to be ready"
+
+if [[ $? -ne 0 ]]; then
+    echo "instrumented service failed to start in 30 * 10 seconds: "
+    cat ${SERVICE_LOG}/*
+    exit 1
+fi
+
+echo "SkyWalking e2e container is ready for tests"
+
+tail -f ${OAP_LOG_DIR}/* \
+        ${WEBAPP_LOG_DIR}/* \
+        ${SERVICE_LOG}/* \
+        ${ES_HOME}/logs/stdout.log
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegister.java
 
b/test/e2e/e2e-agent-auth/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java
similarity index 62%
copy from 
oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegister.java
copy to 
test/e2e/e2e-agent-auth/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java
index 3244d44..37a9858 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegister.java
+++ 
b/test/e2e/e2e-agent-auth/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java
@@ -16,17 +16,19 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core.server;
+package org.apache.skywalking.e2e.sample.client;
 
-import io.grpc.*;
-import org.apache.skywalking.oap.server.library.module.Service;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
 
 /**
- * @author peng-yongsheng
+ * @author kezhenxu94, jian.tan
  */
-public interface GRPCHandlerRegister extends Service {
-
-    void addHandler(BindableService handler);
-
-    void addHandler(ServerServiceDefinition definition);
+@EnableJpaRepositories
+@SpringBootApplication
+public class SampleClientApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(SampleClientApplication.class, args);
+    }
 }
diff --git 
a/test/e2e/e2e-agent-auth/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java
 
b/test/e2e/e2e-agent-auth/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java
new file mode 100644
index 0000000..6f5b983
--- /dev/null
+++ 
b/test/e2e/e2e-agent-auth/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java
@@ -0,0 +1,49 @@
+/*
+ * 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.skywalking.e2e.sample.client;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author kezhenxu94, jian.tan
+ */
+@RestController
+@RequestMapping("/e2e")
+public class TestController {
+    private final UserRepo userRepo;
+
+    public TestController(final UserRepo userRepo) {
+        this.userRepo = userRepo;
+    }
+
+    @GetMapping("/health-check")
+    public String hello() {
+        return "healthy";
+    }
+
+    @PostMapping("/users")
+    public User createAuthor(@RequestBody final User user) throws 
InterruptedException {
+        Thread.sleep(1000L);
+        return userRepo.save(user);
+    }
+}
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegisterImpl.java
 
b/test/e2e/e2e-agent-auth/src/main/java/org/apache/skywalking/e2e/sample/client/User.java
similarity index 58%
copy from 
oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegisterImpl.java
copy to 
test/e2e/e2e-agent-auth/src/main/java/org/apache/skywalking/e2e/sample/client/User.java
index 229c3ca..b34755c 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegisterImpl.java
+++ 
b/test/e2e/e2e-agent-auth/src/main/java/org/apache/skywalking/e2e/sample/client/User.java
@@ -16,27 +16,41 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core.server;
+package org.apache.skywalking.e2e.sample.client;
 
-import io.grpc.*;
-import org.apache.skywalking.oap.server.library.server.grpc.GRPCServer;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
 
 /**
- * @author peng-yongsheng
+ * @author kezhenxu94, jian.tan
  */
-public class GRPCHandlerRegisterImpl implements GRPCHandlerRegister {
+@Entity
+public class User {
+    public User() {
+    }
+
+    @Id
+    @GeneratedValue
+    private Long id;
 
-    private final GRPCServer server;
+    @Column
+    private String name;
+
+    public Long getId() {
+        return id;
+    }
 
-    public GRPCHandlerRegisterImpl(GRPCServer server) {
-        this.server = server;
+    public void setId(final Long id) {
+        this.id = id;
     }
 
-    @Override public void addHandler(BindableService handler) {
-        server.addHandler(handler);
+    public String getName() {
+        return name;
     }
 
-    @Override public void addHandler(ServerServiceDefinition definition) {
-        server.addHandler(definition);
+    public void setName(final String name) {
+        this.name = name;
     }
 }
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegister.java
 
b/test/e2e/e2e-agent-auth/src/main/java/org/apache/skywalking/e2e/sample/client/UserRepo.java
similarity index 71%
copy from 
oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegister.java
copy to 
test/e2e/e2e-agent-auth/src/main/java/org/apache/skywalking/e2e/sample/client/UserRepo.java
index 3244d44..472ddfc 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/server/GRPCHandlerRegister.java
+++ 
b/test/e2e/e2e-agent-auth/src/main/java/org/apache/skywalking/e2e/sample/client/UserRepo.java
@@ -16,17 +16,12 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core.server;
+package org.apache.skywalking.e2e.sample.client;
 
-import io.grpc.*;
-import org.apache.skywalking.oap.server.library.module.Service;
+import org.springframework.data.jpa.repository.JpaRepository;
 
 /**
- * @author peng-yongsheng
+ * @author kezhenxu94, jian.tan
  */
-public interface GRPCHandlerRegister extends Service {
-
-    void addHandler(BindableService handler);
-
-    void addHandler(ServerServiceDefinition definition);
+public interface UserRepo extends JpaRepository<User, Long> {
 }
diff --git a/test/e2e/e2e-agent-auth/src/main/resources/application.yml 
b/test/e2e/e2e-agent-auth/src/main/resources/application.yml
new file mode 100644
index 0000000..ef3ed01
--- /dev/null
+++ b/test/e2e/e2e-agent-auth/src/main/resources/application.yml
@@ -0,0 +1,35 @@
+# 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.
+
+server:
+  port: 9090
+
+spring:
+  main:
+    banner-mode: 'off'
+  datasource:
+    url: jdbc:h2:mem:testdb
+    driver-class-name: org.h2.Driver
+    data-username: sa
+    password: sa
+    platform: org.hibernate.dialect.H2Dialect
+  jpa:
+    generate-ddl: true
+    hibernate:
+      ddl-auto: create-drop
+    properties:
+      hibernate.format_sql: true
+    show-sql: true
diff --git 
a/test/e2e/e2e-agent-auth/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java
 
b/test/e2e/e2e-agent-auth/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java
new file mode 100644
index 0000000..93e3c11
--- /dev/null
+++ 
b/test/e2e/e2e-agent-auth/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java
@@ -0,0 +1,383 @@
+/*
+ * 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.skywalking.e2e;
+
+import java.io.InputStream;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.skywalking.e2e.metrics.AtLeastOneOfMetricsMatcher;
+import org.apache.skywalking.e2e.metrics.Metrics;
+import org.apache.skywalking.e2e.metrics.MetricsQuery;
+import org.apache.skywalking.e2e.metrics.MetricsValueMatcher;
+import org.apache.skywalking.e2e.service.Service;
+import org.apache.skywalking.e2e.service.ServicesMatcher;
+import org.apache.skywalking.e2e.service.ServicesQuery;
+import org.apache.skywalking.e2e.service.endpoint.Endpoint;
+import org.apache.skywalking.e2e.service.endpoint.EndpointQuery;
+import org.apache.skywalking.e2e.service.endpoint.Endpoints;
+import org.apache.skywalking.e2e.service.endpoint.EndpointsMatcher;
+import org.apache.skywalking.e2e.service.instance.Instance;
+import org.apache.skywalking.e2e.service.instance.Instances;
+import org.apache.skywalking.e2e.service.instance.InstancesMatcher;
+import org.apache.skywalking.e2e.service.instance.InstancesQuery;
+import org.apache.skywalking.e2e.topo.Call;
+import org.apache.skywalking.e2e.topo.ServiceInstanceTopoData;
+import org.apache.skywalking.e2e.topo.ServiceInstanceTopoMatcher;
+import org.apache.skywalking.e2e.topo.ServiceInstanceTopoQuery;
+import org.apache.skywalking.e2e.topo.TopoData;
+import org.apache.skywalking.e2e.topo.TopoMatcher;
+import org.apache.skywalking.e2e.topo.TopoQuery;
+import org.apache.skywalking.e2e.trace.Trace;
+import org.apache.skywalking.e2e.trace.TracesMatcher;
+import org.apache.skywalking.e2e.trace.TracesQuery;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.web.client.RestTemplate;
+import org.yaml.snakeyaml.Yaml;
+
+import static org.apache.skywalking.e2e.metrics.MetricsMatcher.verifyMetrics;
+import static 
org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_ENDPOINT_METRICS;
+import static 
org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_INSTANCE_METRICS;
+import static 
org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_INSTANCE_RELATION_CLIENT_METRICS;
+import static 
org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_INSTANCE_RELATION_SERVER_METRICS;
+import static 
org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_METRICS;
+import static 
org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATION_CLIENT_METRICS;
+import static 
org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATION_SERVER_METRICS;
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author kezhenxu94, jian.tan
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+public class SampleVerificationITCase {
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(SampleVerificationITCase.class);
+
+    private final RestTemplate restTemplate = new RestTemplate();
+    private final int retryInterval = 30;
+
+    private SimpleQueryClient queryClient;
+    private String instrumentedServiceUrl;
+
+    @Before
+    public void setUp() {
+        final String swWebappHost = System.getProperty("sw.webapp.host", 
"127.0.0.1");
+        final String swWebappPort = System.getProperty("sw.webapp.port", 
"32783");
+        final String instrumentedServiceHost = 
System.getProperty("client.host", "127.0.0.1");
+        final String instrumentedServicePort = 
System.getProperty("client.port", "32782");
+        queryClient = new SimpleQueryClient(swWebappHost, swWebappPort);
+        instrumentedServiceUrl = "http://"; + instrumentedServiceHost + ":" + 
instrumentedServicePort;
+    }
+
+    @Test(timeout = 1200000)
+    @DirtiesContext
+    public void verify() throws Exception {
+        final LocalDateTime minutesAgo = LocalDateTime.now(ZoneOffset.UTC);
+
+        while (true) {
+            try {
+                final Map<String, String> user = new HashMap<>();
+                user.put("name", "SkyWalking");
+                final ResponseEntity<String> responseEntity = 
restTemplate.postForEntity(
+                    instrumentedServiceUrl + "/e2e/users",
+                    user,
+                    String.class
+                );
+                LOGGER.info("responseEntity: {}", responseEntity);
+                
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
+                final List<Trace> traces = queryClient.traces(
+                    new TracesQuery()
+                        .start(minutesAgo)
+                        .end(LocalDateTime.now())
+                        .orderByDuration()
+                );
+                if (!traces.isEmpty()) {
+                    break;
+                }
+                Thread.sleep(10000L);
+            } catch (Exception ignored) {
+            }
+        }
+
+        doRetryableVerification(() -> {
+            try {
+                verifyTraces(minutesAgo);
+            } catch (Exception e) {
+                LOGGER.warn(e.getMessage(), e);
+            }
+        });
+
+        doRetryableVerification(() -> {
+            try {
+                verifyServices(minutesAgo);
+            } catch (Exception e) {
+                LOGGER.warn(e.getMessage(), e);
+            }
+        });
+
+        doRetryableVerification(() -> {
+            try {
+                verifyTopo(minutesAgo);
+            } catch (Exception e) {
+                LOGGER.warn(e.getMessage(), e);
+            }
+        });
+
+        doRetryableVerification(() -> {
+            try{
+                verifyServiceInstanceTopo(minutesAgo);
+            }catch (Exception e) {
+                LOGGER.warn(e.getMessage(), e);
+            }
+        });
+    }
+
+    private void verifyTopo(LocalDateTime minutesAgo) throws Exception {
+        final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
+
+        final TopoData topoData = queryClient.topo(
+            new TopoQuery()
+                .stepByMinute()
+                .start(minutesAgo.minusDays(1))
+                .end(now)
+        );
+        LOGGER.info("topoData: {}", topoData);
+
+        InputStream expectedInputStream =
+            new 
ClassPathResource("expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml").getInputStream();
+
+        final TopoMatcher topoMatcher = new Yaml().loadAs(expectedInputStream, 
TopoMatcher.class);
+        topoMatcher.verify(topoData);
+        verifyServiceRelationMetrics(topoData.getCalls(), minutesAgo);
+    }
+
+    private void verifyServiceInstanceTopo(LocalDateTime minutesAgo) throws 
Exception {
+        final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
+
+        final ServiceInstanceTopoData topoData = 
queryClient.serviceInstanceTopo(
+                new ServiceInstanceTopoQuery()
+                        .stepByMinute()
+                        .start(minutesAgo.minusDays(1))
+                        .end(now)
+                        .clientServiceId("1")
+                        .serverServiceId("2")
+        );
+        LOGGER.info("instanceTopoData: {}", topoData);
+
+        InputStream expectedInputStream =
+                new 
ClassPathResource("expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml").getInputStream();
+
+        final ServiceInstanceTopoMatcher topoMatcher = new 
Yaml().loadAs(expectedInputStream, ServiceInstanceTopoMatcher.class);
+        topoMatcher.verify(topoData);
+        verifyServiceInstanceRelationMetrics(topoData.getCalls(), minutesAgo);
+    }
+
+    private void verifyServices(LocalDateTime minutesAgo) throws Exception {
+        final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
+
+        final List<Service> services = queryClient.services(
+            new ServicesQuery()
+                .start(minutesAgo)
+                .end(now)
+        );
+        LOGGER.info("services: {}", services);
+
+        InputStream expectedInputStream =
+            new 
ClassPathResource("expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml").getInputStream();
+
+        final ServicesMatcher servicesMatcher = new 
Yaml().loadAs(expectedInputStream, ServicesMatcher.class);
+        servicesMatcher.verify(services);
+
+        for (Service service : services) {
+            LOGGER.info("verifying service instances: {}", service);
+
+            verifyServiceMetrics(service);
+
+            Instances instances = verifyServiceInstances(minutesAgo, now, 
service);
+
+            verifyInstancesMetrics(instances);
+
+            Endpoints endpoints = verifyServiceEndpoints(minutesAgo, now, 
service);
+
+            verifyEndpointsMetrics(endpoints);
+        }
+    }
+
+    private Instances verifyServiceInstances(LocalDateTime minutesAgo, 
LocalDateTime now,
+        Service service) throws Exception {
+        InputStream expectedInputStream;
+        Instances instances = queryClient.instances(
+            new InstancesQuery()
+                .serviceId(service.getKey())
+                .start(minutesAgo)
+                .end(now)
+        );
+        LOGGER.info("instances: {}", instances);
+        expectedInputStream =
+            new 
ClassPathResource("expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml").getInputStream();
+        final InstancesMatcher instancesMatcher = new 
Yaml().loadAs(expectedInputStream, InstancesMatcher.class);
+        instancesMatcher.verify(instances);
+        return instances;
+    }
+
+    private Endpoints verifyServiceEndpoints(LocalDateTime minutesAgo, 
LocalDateTime now,
+        Service service) throws Exception {
+        Endpoints instances = queryClient.endpoints(
+            new EndpointQuery().serviceId(service.getKey())
+        );
+        LOGGER.info("instances: {}", instances);
+        InputStream expectedInputStream =
+            new 
ClassPathResource("expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml").getInputStream();
+        final EndpointsMatcher endpointsMatcher = new 
Yaml().loadAs(expectedInputStream, EndpointsMatcher.class);
+        endpointsMatcher.verify(instances);
+        return instances;
+    }
+
+    private void verifyInstancesMetrics(Instances instances) throws Exception {
+        for (Instance instance : instances.getInstances()) {
+            for (String metricsName : ALL_INSTANCE_METRICS) {
+                LOGGER.info("verifying service instance response time: {}", 
instance);
+                final Metrics instanceMetrics = queryClient.metrics(
+                    new MetricsQuery()
+                        .stepByMinute()
+                        .metricsName(metricsName)
+                        .id(instance.getKey())
+                );
+                LOGGER.info("instanceMetrics: {}", instanceMetrics);
+                AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new 
AtLeastOneOfMetricsMatcher();
+                MetricsValueMatcher greaterThanZero = new 
MetricsValueMatcher();
+                greaterThanZero.setValue("gt 0");
+                instanceRespTimeMatcher.setValue(greaterThanZero);
+                instanceRespTimeMatcher.verify(instanceMetrics);
+                LOGGER.info("{}: {}", metricsName, instanceMetrics);
+            }
+        }
+    }
+
+    private void verifyEndpointsMetrics(Endpoints endpoints) throws Exception {
+        for (Endpoint endpoint : endpoints.getEndpoints()) {
+            if (!endpoint.getLabel().equals("/e2e/users")) {
+                continue;
+            }
+            for (String metricName : ALL_ENDPOINT_METRICS) {
+                LOGGER.info("verifying endpoint {}, metrics: {}", endpoint, 
metricName);
+                final Metrics metrics = queryClient.metrics(
+                    new MetricsQuery()
+                        .stepByMinute()
+                        .metricsName(metricName)
+                        .id(endpoint.getKey())
+                );
+                LOGGER.info("metrics: {}", metrics);
+                AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new 
AtLeastOneOfMetricsMatcher();
+                MetricsValueMatcher greaterThanZero = new 
MetricsValueMatcher();
+                greaterThanZero.setValue("gt 0");
+                instanceRespTimeMatcher.setValue(greaterThanZero);
+                instanceRespTimeMatcher.verify(metrics);
+                LOGGER.info("{}: {}", metricName, metrics);
+            }
+        }
+    }
+
+    private void verifyServiceMetrics(Service service) throws Exception {
+        for (String metricName : ALL_SERVICE_METRICS) {
+            LOGGER.info("verifying service {}, metrics: {}", service, 
metricName);
+            final Metrics serviceMetrics = queryClient.metrics(
+                new MetricsQuery()
+                    .stepByMinute()
+                    .metricsName(metricName)
+                    .id(service.getKey())
+            );
+            LOGGER.info("serviceMetrics: {}", serviceMetrics);
+            AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new 
AtLeastOneOfMetricsMatcher();
+            MetricsValueMatcher greaterThanZero = new MetricsValueMatcher();
+            greaterThanZero.setValue("gt 0");
+            instanceRespTimeMatcher.setValue(greaterThanZero);
+            instanceRespTimeMatcher.verify(serviceMetrics);
+            LOGGER.info("{}: {}", metricName, serviceMetrics);
+        }
+    }
+
+    private void verifyTraces(LocalDateTime minutesAgo) throws Exception {
+        final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
+
+        final List<Trace> traces = queryClient.traces(
+            new TracesQuery()
+                .start(minutesAgo)
+                .end(now)
+                .orderByDuration()
+        );
+        LOGGER.info("traces: {}", traces);
+
+        InputStream expectedInputStream =
+            new 
ClassPathResource("expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml").getInputStream();
+
+        final TracesMatcher tracesMatcher = new 
Yaml().loadAs(expectedInputStream, TracesMatcher.class);
+        tracesMatcher.verify(traces);
+    }
+
+    private void verifyServiceInstanceRelationMetrics(List<Call> calls, final 
LocalDateTime minutesAgo) throws Exception {
+        verifyRelationMetrics(calls, minutesAgo, 
ALL_SERVICE_INSTANCE_RELATION_CLIENT_METRICS, 
ALL_SERVICE_INSTANCE_RELATION_SERVER_METRICS);
+    }
+
+    private void verifyServiceRelationMetrics(List<Call> calls, final 
LocalDateTime minutesAgo) throws Exception {
+        verifyRelationMetrics(calls, minutesAgo, 
ALL_SERVICE_RELATION_CLIENT_METRICS, ALL_SERVICE_RELATION_SERVER_METRICS);
+    }
+
+    private void verifyRelationMetrics(List<Call> calls, final LocalDateTime 
minutesAgo, String[] relationClientMetrics, String[] relationServerMetrics) 
throws Exception {
+        for (Call call : calls) {
+            for (String detectPoint : call.getDetectPoints()) {
+                switch (detectPoint) {
+                    case "CLIENT": {
+                        for (String metricName : relationClientMetrics) {
+                            verifyMetrics(queryClient, metricName, 
call.getId(), minutesAgo);
+                        }
+                        break;
+                    }
+                    case "SERVER": {
+                        for (String metricName : relationServerMetrics) {
+                            verifyMetrics(queryClient, metricName, 
call.getId(), minutesAgo);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    private void doRetryableVerification(Runnable runnable) throws 
InterruptedException {
+        while (true) {
+            try {
+                runnable.run();
+                break;
+            } catch (Throwable ignored) {
+                Thread.sleep(retryInterval);
+            }
+        }
+    }
+}
diff --git 
a/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml
 
b/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml
new file mode 100644
index 0000000..a1f5b45
--- /dev/null
+++ 
b/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml
@@ -0,0 +1,27 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+endpoints:
+  - key: not null
+    label: /e2e/health-check
+  - key: not null
+    label: /e2e/users
diff --git 
a/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml
 
b/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml
new file mode 100644
index 0000000..26bb314
--- /dev/null
+++ 
b/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml
@@ -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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+instances:
+  - key: 2
+    label: not null
+    attributes:
+      - name: os_name
+        value: not null
+      - name: host_name
+        value: not null
+      - name: process_no
+        value: gt 0
+      - name: ipv4s
+        value: not null
diff --git 
a/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml
 
b/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml
new file mode 100644
index 0000000..d312bd8
--- /dev/null
+++ 
b/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml
@@ -0,0 +1,41 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+nodes:
+  - id: 1
+    name: User
+    type: USER
+    serviceId: 1
+    serviceName: User
+    isReal: false
+  - id: 2
+    name: not null
+    serviceId: 2
+    serviceName: Your_ApplicationName
+    type: Tomcat
+    isReal: true
+calls:
+  - id: 1_2
+    source: 1
+    detectPoints:
+      - SERVER
+    target: 2
diff --git 
a/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml
 
b/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml
new file mode 100644
index 0000000..07ff835
--- /dev/null
+++ 
b/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml
@@ -0,0 +1,25 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+services:
+  - key: 2
+    label: "Your_ApplicationName"
diff --git 
a/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml
 
b/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml
new file mode 100644
index 0000000..3a455f5
--- /dev/null
+++ 
b/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml
@@ -0,0 +1,46 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+nodes:
+  - id: 1
+    name: User
+    type: USER
+    isReal: false
+  - id: 2
+    name: Your_ApplicationName
+    type: Tomcat
+    isReal: true
+  - id: 3
+    name: "localhost:-1"
+    type: H2
+    isReal: false
+calls:
+  - id: 2_3
+    source: 2
+    detectPoints:
+      - CLIENT
+    target: 3
+  - id: 1_2
+    source: 1
+    detectPoints:
+      - SERVER
+    target: 2
diff --git 
a/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml
 
b/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml
new file mode 100644
index 0000000..2052aad
--- /dev/null
+++ 
b/test/e2e/e2e-agent-auth/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml
@@ -0,0 +1,31 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+traces:
+  - key: not null
+    endpointNames:
+      - /e2e/users
+    duration: ge 0
+    start: gt 0
+    isError: false
+    traceIds:
+      - not null
diff --git a/test/e2e/pom.xml b/test/e2e/pom.xml
index 83872f5..9ab648d 100644
--- a/test/e2e/pom.xml
+++ b/test/e2e/pom.xml
@@ -38,6 +38,7 @@
         <module>e2e-cluster</module>
         <module>e2e-cluster-with-gateway</module>
         <module>e2e-agent-reboot</module>
+        <module>e2e-agent-auth</module>
         <module>e2e-ttl</module>
         <module>e2e-6.x-agent-7.x-oap-compatibility</module>
         <module>e2e-profile</module>
diff --git a/test/plugin/containers/jvm-container/docker/run.sh 
b/test/plugin/containers/jvm-container/docker/run.sh
index d2d5cd9..da532ca 100644
--- a/test/plugin/containers/jvm-container/docker/run.sh
+++ b/test/plugin/containers/jvm-container/docker/run.sh
@@ -69,6 +69,7 @@ export 
agent_opts="-javaagent:${SCENARIO_HOME}/agent/skywalking-agent.jar
     -Dskywalking.collector.backend_service=localhost:19876
     -Dskywalking.agent.service_name=${SCENARIO_NAME}
     -Dskywalking.logging.dir=/usr/local/skywalking/scenario/logs
+    -Dskywalking.agent.authentication=test-token
     -Xms256m -Xmx256m ${agent_opts}"
 exec /var/run/${SCENARIO_NAME}/${SCENARIO_START_SCRIPT} 1>/dev/null &
 
diff --git a/test/plugin/containers/tomcat-container/docker/catalina.sh 
b/test/plugin/containers/tomcat-container/docker/catalina.sh
index 22ca290..e82ac52 100644
--- a/test/plugin/containers/tomcat-container/docker/catalina.sh
+++ b/test/plugin/containers/tomcat-container/docker/catalina.sh
@@ -113,6 +113,7 @@ if [ -f "${AGENT_FILE_PATH}/skywalking-agent.jar" ]; then
     -Dskywalking.collector.discovery_check_interval=2
     -Dskywalking.collector.backend_service=localhost:19876
     -Dskywalking.agent.service_name=${SCENARIO_NAME}
+    -Dskywalking.agent.authentication=test-token
     -Dskywalking.logging.dir=/usr/local/skywalking/scenario/logs
     -Xms256m -Xmx256m -XX:PermSize=64M -XX:MaxPermSize=64"
 fi

Reply via email to