You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ro...@apache.org on 2022/01/20 15:34:23 UTC

[iotdb] branch master updated: [IOTDB-2444] Refine /ping API and fix unauthorized NPE error (#4910)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 09a46f3  [IOTDB-2444] Refine /ping API and fix unauthorized NPE error (#4910)
09a46f3 is described below

commit 09a46f34ed6e12ab978ed372f658c9910d3d38e4
Author: BaiJian <er...@hotmail.com>
AuthorDate: Thu Jan 20 23:32:28 2022 +0800

    [IOTDB-2444] Refine /ping API and fix unauthorized NPE error (#4910)
---
 docs/UserGuide/API/RestService.md                  | 47 ++++++++++++----
 docs/zh/UserGuide/API/RestService.md               | 46 +++++++++++-----
 .../protocol/rest/filter/AuthorizationFilter.java  | 17 +++++-
 .../iotdb/db/protocol/rest/IoTDBRestServiceIT.java | 64 +++++++++++++++++++++-
 4 files changed, 146 insertions(+), 28 deletions(-)

diff --git a/docs/UserGuide/API/RestService.md b/docs/UserGuide/API/RestService.md
index 12e7552..534564e 100644
--- a/docs/UserGuide/API/RestService.md
+++ b/docs/UserGuide/API/RestService.md
@@ -39,13 +39,46 @@ RESTful services are disabled by default.
   ```
 
 ### Authentication
-RESTful services use the basic authentication. Each URL request needs to carry `'Authorization': 'Basic ' + base64.encode(username + ':' + password)`.
+Except the liveness probe API `/ping`, RESTful services use the basic authentication. Each URL request needs to carry `'Authorization': 'Basic ' + base64.encode(username + ':' + password)`.
 
+The username used in the following examples is: `root`, and password is: `root`.
+
+And the authorization header is
+
+```
+Authorization: Basic cm9vdDpyb2901
+```
+
+- If a user authorized with incorrect username or password, the following error is returned:
+
+  HTTP Status Code:`401`
+
+  HTTP response body:
+    ```json
+    {
+      "code": 600,
+      "message": "WRONG_LOGIN_PASSWORD_ERROR"
+    }
+    ```
+
+- If the `Authorization` header is missing,the following error is returned:
+
+  HTTP Status Code:`401`
+
+  HTTP response body:
+    ```json
+    {
+      "code": 603,
+      "message": "UNINITIALIZED_AUTH_ERROR"
+    }
+    ```
 
 ### Interface
 
 #### ping
 
+The `/ping` API can be used for service liveness probing.
+
 Request method: `GET`
 
 Request path: http://ip:port/ping
@@ -55,7 +88,7 @@ The user name used in the example is: root, password: root
 Example request: 
 
 ```shell
-$ curl -H "Authorization:Basic cm9vdDpyb2901" http://127.0.0.1:18080/ping
+$ curl http://127.0.0.1:18080/ping
 ```
 Response parameters:
 
@@ -71,15 +104,8 @@ Sample response:
   "message": "SUCCESS_STATUS"
 }
 ```
-Example Of user name and password authentication failure:
-```json
-{
-  "code": 600,
-  "message": "WRONG_LOGIN_PASSWORD_ERROR"
-}
-```
-
 
+> `/ping` can be accessed without authorization.
 
 #### query
 
@@ -882,4 +908,3 @@ trust_store_pwd=
 ```properties
 idle_timeout=5000
 ```
-
diff --git a/docs/zh/UserGuide/API/RestService.md b/docs/zh/UserGuide/API/RestService.md
index e772bed..6a579a0 100644
--- a/docs/zh/UserGuide/API/RestService.md
+++ b/docs/zh/UserGuide/API/RestService.md
@@ -37,24 +37,52 @@ RESTful 服务默认情况是关闭的
     ```
 
 ### 鉴权
-RESTful 服务使用了基础(basic)鉴权,每次 URL 请求都需要在 header 中携带 `'Authorization': 'Basic ' + base64.encode(username + ':' + password)`。
+除了检活接口 `/ping`,RESTful 服务使用了基础(basic)鉴权,每次 URL 请求都需要在 header 中携带 `'Authorization': 'Basic ' + base64.encode(username + ':' + password)`。
 
+示例中使用的用户名为:`root`,密码为:`root`,对应的 Basic 鉴权 Header 格式为
 
+```
+Authorization: Basic cm9vdDpyb2901
+```
+
+- 若用户名密码认证失败,则返回如下信息:
+
+    HTTP 状态码:`401`
+
+    返回结构体如下
+    ```json
+    {
+      "code": 600,
+      "message": "WRONG_LOGIN_PASSWORD_ERROR"
+    }
+    ```
+
+- 若未设置 `Authorization`,则返回如下信息:
+
+  HTTP 状态码:`401`
+
+  返回结构体如下
+    ```json
+    {
+      "code": 603,
+      "message": "UNINITIALIZED_AUTH_ERROR"
+    }
+    ```
 
 ### 接口
 
 #### ping
 
+ping 接口可以用于线上服务检活。
+
 请求方式:`GET`
 
 请求路径:http://ip:port/ping
 
-示例中使用的用户名为:root,密码为:root
-
 请求示例:
 
 ```shell
-$ curl -H "Authorization:Basic cm9vdDpyb2901" http://127.0.0.1:18080/ping
+$ curl http://127.0.0.1:18080/ping
 ```
 响应参数:
 
@@ -70,15 +98,8 @@ $ curl -H "Authorization:Basic cm9vdDpyb2901" http://127.0.0.1:18080/ping
   "message": "SUCCESS_STATUS"
 }
 ```
-用户名密码认证失败示例:
-```json
-{
-  "code": 600,
-  "message": "WRONG_LOGIN_PASSWORD_ERROR"
-}
-```
-
 
+> `/ping` 接口访问不需要鉴权。
 
 #### query
 
@@ -900,4 +921,3 @@ trust_store_pwd=
 ```properties
 idle_timeout=5000
 ```
-
diff --git a/server/src/main/java/org/apache/iotdb/db/protocol/rest/filter/AuthorizationFilter.java b/server/src/main/java/org/apache/iotdb/db/protocol/rest/filter/AuthorizationFilter.java
index 555adf2..4ee0b51 100644
--- a/server/src/main/java/org/apache/iotdb/db/protocol/rest/filter/AuthorizationFilter.java
+++ b/server/src/main/java/org/apache/iotdb/db/protocol/rest/filter/AuthorizationFilter.java
@@ -51,11 +51,24 @@ public class AuthorizationFilter implements ContainerRequestFilter {
   @Override
   public void filter(ContainerRequestContext containerRequestContext) throws IOException {
     if ("OPTIONS".equals(containerRequestContext.getMethod())
-        || "swagger.json".equals(containerRequestContext.getUriInfo().getPath())) {
+        || "swagger.json".equals(containerRequestContext.getUriInfo().getPath())
+        || "ping".equals(containerRequestContext.getUriInfo().getPath())) {
       return;
     }
 
     String authorizationHeader = containerRequestContext.getHeaderString("authorization");
+    if (authorizationHeader == null) {
+      Response resp =
+          Response.status(Status.UNAUTHORIZED)
+              .type(MediaType.APPLICATION_JSON)
+              .entity(
+                  new ExecutionStatus()
+                      .code(TSStatusCode.UNINITIALIZED_AUTH_ERROR.getStatusCode())
+                      .message(TSStatusCode.UNINITIALIZED_AUTH_ERROR.name()))
+              .build();
+      containerRequestContext.abortWith(resp);
+      return;
+    }
     User user = userCache.getUser(authorizationHeader);
     if (user == null) {
       user = checkLogin(containerRequestContext, authorizationHeader);
@@ -97,7 +110,7 @@ public class AuthorizationFilter implements ContainerRequestFilter {
     try {
       if (!authorizer.login(split[0], split[1])) {
         Response resp =
-            Response.status(Status.OK)
+            Response.status(Status.UNAUTHORIZED)
                 .type(MediaType.APPLICATION_JSON)
                 .entity(
                     new ExecutionStatus()
diff --git a/server/src/test/java/org/apache/iotdb/db/protocol/rest/IoTDBRestServiceIT.java b/server/src/test/java/org/apache/iotdb/db/protocol/rest/IoTDBRestServiceIT.java
index bbd1161..607b46f 100644
--- a/server/src/test/java/org/apache/iotdb/db/protocol/rest/IoTDBRestServiceIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/protocol/rest/IoTDBRestServiceIT.java
@@ -73,8 +73,6 @@ public class IoTDBRestServiceIT {
     HttpGet httpGet = new HttpGet("http://127.0.0.1:18080/ping");
     CloseableHttpResponse response = null;
     try {
-      String authorization = getAuthorization("root", "root");
-      httpGet.setHeader("Authorization", authorization);
       response = httpClient.execute(httpGet);
       HttpEntity responseEntity = response.getEntity();
       String message = EntityUtils.toString(responseEntity, "utf-8");
@@ -194,6 +192,68 @@ public class IoTDBRestServiceIT {
     }
   }
 
+  @Test
+  public void queryWithUnsetAuthorization() {
+    CloseableHttpResponse response = null;
+    try {
+      CloseableHttpClient httpClient = HttpClientBuilder.create().build();
+      HttpPost httpPost = new HttpPost("http://127.0.0.1:18080/rest/v1/query");
+      httpPost.addHeader("Content-type", "application/json; charset=utf-8");
+      httpPost.setHeader("Accept", "application/json");
+      String sql = "{\"sql\":\"select *,s4+1,s4+1 from root.sg25\"}";
+      httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset()));
+      response = httpClient.execute(httpPost);
+      Assert.assertEquals(401, response.getStatusLine().getStatusCode());
+      String message = EntityUtils.toString(response.getEntity(), "utf-8");
+      JsonObject result = JsonParser.parseString(message).getAsJsonObject();
+      assertEquals(603, Integer.parseInt(result.get("code").toString()));
+    } catch (IOException e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    } finally {
+      try {
+        if (response != null) {
+          response.close();
+        }
+      } catch (IOException e) {
+        e.printStackTrace();
+        fail(e.getMessage());
+      }
+    }
+  }
+
+  @Test
+  public void queryWithWrongAuthorization() {
+    CloseableHttpResponse response = null;
+    try {
+      CloseableHttpClient httpClient = HttpClientBuilder.create().build();
+      HttpPost httpPost = new HttpPost("http://127.0.0.1:18080/rest/v1/query");
+      httpPost.addHeader("Content-type", "application/json; charset=utf-8");
+      httpPost.setHeader("Accept", "application/json");
+      String authorization = getAuthorization("abc", "def");
+      httpPost.setHeader("Authorization", authorization);
+      String sql = "{\"sql\":\"select *,s4+1,s4+1 from root.sg25\"}";
+      httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset()));
+      response = httpClient.execute(httpPost);
+      Assert.assertEquals(401, response.getStatusLine().getStatusCode());
+      String message = EntityUtils.toString(response.getEntity(), "utf-8");
+      JsonObject result = JsonParser.parseString(message).getAsJsonObject();
+      assertEquals(600, Integer.parseInt(result.get("code").toString()));
+    } catch (IOException e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    } finally {
+      try {
+        if (response != null) {
+          response.close();
+        }
+      } catch (IOException e) {
+        e.printStackTrace();
+        fail(e.getMessage());
+      }
+    }
+  }
+
   public void query(CloseableHttpClient httpClient) {
     CloseableHttpResponse response = null;
     try {