1 /*
2  * Copyright (c) 2016 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you
5  * may not use this file except in compliance with the License. You may
6  * obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13  * implied. See the License for the specific language governing
14  * permissions and limitations under the License.
15  */
16 
17 package com.android.vts.api;
18 
19 import com.android.vts.proto.VtsReportMessage.TestReportMessage;
20 import com.android.vts.servlet.BaseServlet;
21 import com.android.vts.util.DatastoreHelper;
22 import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
23 import com.google.api.client.http.javanet.NetHttpTransport;
24 import com.google.api.client.json.jackson.JacksonFactory;
25 import com.google.api.services.oauth2.Oauth2;
26 import com.google.api.services.oauth2.model.Tokeninfo;
27 import com.google.protobuf.InvalidProtocolBufferException;
28 import java.io.BufferedReader;
29 import java.io.FileNotFoundException;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.util.Properties;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
35 import javax.servlet.ServletConfig;
36 import javax.servlet.ServletException;
37 import javax.servlet.http.HttpServlet;
38 import javax.servlet.http.HttpServletRequest;
39 import javax.servlet.http.HttpServletResponse;
40 import org.apache.commons.codec.binary.Base64;
41 import org.json.JSONException;
42 import org.json.JSONObject;
43 
44 /** REST endpoint for posting data JSON to the Dashboard. */
45 @Deprecated
46 public class BigtableLegacyJsonServlet extends HttpServlet {
47     private static String SERVICE_CLIENT_ID;
48     private static final String SERVICE_NAME = "VTS Dashboard";
49     private static final Logger logger =
50             Logger.getLogger(BigtableLegacyJsonServlet.class.getName());
51 
52     /** System Configuration Property class */
53     protected Properties systemConfigProp = new Properties();
54 
55     @Override
init(ServletConfig cfg)56     public void init(ServletConfig cfg) throws ServletException {
57         super.init(cfg);
58 
59         try {
60             InputStream defaultInputStream =
61                     BigtableLegacyJsonServlet.class
62                             .getClassLoader()
63                             .getResourceAsStream("config.properties");
64             systemConfigProp.load(defaultInputStream);
65 
66             SERVICE_CLIENT_ID = systemConfigProp.getProperty("appengine.serviceClientID");
67         } catch (FileNotFoundException e) {
68             e.printStackTrace();
69         } catch (IOException e) {
70             e.printStackTrace();
71         }
72     }
73 
74     @Override
doPost(HttpServletRequest request, HttpServletResponse response)75     public void doPost(HttpServletRequest request, HttpServletResponse response)
76             throws IOException {
77         // Retrieve the params
78         String payload = new String();
79         JSONObject payloadJson;
80         try {
81             String line = null;
82             BufferedReader reader = request.getReader();
83             while ((line = reader.readLine()) != null) {
84                 payload += line;
85             }
86             payloadJson = new JSONObject(payload);
87         } catch (IOException | JSONException e) {
88             response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
89             logger.log(Level.WARNING, "Invalid JSON: " + payload);
90             return;
91         }
92 
93         // Verify service account access token.
94         boolean authorized = false;
95         if (payloadJson.has("accessToken")) {
96             String accessToken = payloadJson.getString("accessToken").trim();
97             GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
98             Oauth2 oauth2 =
99                     new Oauth2.Builder(new NetHttpTransport(), new JacksonFactory(), credential)
100                             .setApplicationName(SERVICE_NAME)
101                             .build();
102             Tokeninfo tokenInfo = oauth2.tokeninfo().setAccessToken(accessToken).execute();
103             if (tokenInfo.getIssuedTo().equals(SERVICE_CLIENT_ID)) {
104                 authorized = true;
105             }
106         }
107 
108         if (!authorized) {
109             response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
110             return;
111         }
112 
113         // Parse the desired action and execute the command
114         try {
115             if (payloadJson.has("verb")) {
116                 switch (payloadJson.getString("verb")) {
117                     case "createTable":
118                         logger.log(Level.INFO, "Deprecated verb: createTable.");
119                         break;
120                     case "insertRow":
121                         insertData(payloadJson);
122                         break;
123                     default:
124                         logger.log(
125                                 Level.WARNING,
126                                 "Invalid Datastore REST verb: " + payloadJson.getString("verb"));
127                         throw new IOException("Unsupported POST verb.");
128                 }
129             }
130         } catch (IOException e) {
131             response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
132             return;
133         }
134         response.setStatus(HttpServletResponse.SC_OK);
135     }
136 
137     /**
138      * Inserts a data into the Cloud Datastore
139      *
140      * @param payloadJson The JSON object representing the row to be inserted. Of the form: {
141      *     (deprecated) 'tableName' : 'table', (deprecated) 'rowKey' : 'row', (deprecated) 'family'
142      *     : 'family', (deprecated) 'qualifier' : 'qualifier', 'value' : 'value' }
143      * @throws IOException
144      */
insertData(JSONObject payloadJson)145     private void insertData(JSONObject payloadJson) throws IOException {
146         if (!payloadJson.has("value")) {
147             logger.log(Level.WARNING, "Missing attributes for datastore api insertRow().");
148             return;
149         }
150         try {
151             byte[] value = Base64.decodeBase64(payloadJson.getString("value"));
152             TestReportMessage testReportMessage = TestReportMessage.parseFrom(value);
153         } catch (InvalidProtocolBufferException e) {
154             logger.log(Level.WARNING, "Invalid report posted to dashboard.");
155         }
156     }
157 }
158