gov.nist.appvet.tool.AsynchronousService.java Source code

Java tutorial

Introduction

Here is the source code for gov.nist.appvet.tool.AsynchronousService.java

Source

/* This software was developed by employees of the National Institute of
 * Standards and Technology (NIST), an agency of the Federal Government.
 * Pursuant to title 15 United States Code Section 105, works of NIST
 * employees are not subject to copyright protection in the United States
 * and are considered to be in the public domain.  As a result, a formal
 * license is not needed to use the software.
 * 
 * This software is provided by NIST as a service and is expressly
 * provided "AS IS".  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
 * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
 * AND DATA ACCURACY.  NIST does not warrant or make any representations
 * regarding the use of the software or the results thereof including, but
 * not limited to, the correctness, accuracy, reliability or usefulness of
 * the software.
 * 
 * Permission to use this software is contingent upon your acceptance
 * of the terms of this agreement.
 */
package gov.nist.appvet.tool;

import gov.nist.appvet.tool.util.Logger;
import gov.nist.appvet.tool.util.SSLWrapper;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

@WebServlet("/AsynchronousService")
public class AsynchronousService extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private static final Logger log = Properties.log;

    public AsynchronousService() {
        super();
        log.info("Master Key and Extra Field service ready.");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        FileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        List items = null;
        FileItem fileItem = null;
        String appId = null;

        try {
            items = upload.parseRequest(request);
        } catch (FileUploadException e) {
            e.printStackTrace();
        }

        // Get form fields
        Iterator iter = items.iterator();
        FileItem item = null;
        while (iter.hasNext()) {
            item = (FileItem) iter.next();
            if (item.isFormField()) {
                String incomingParameter = item.getFieldName();
                String incomingValue = item.getString();
                if (incomingParameter.equals("appid")) {
                    appId = incomingValue;
                }
                log.debug("Received: " + incomingParameter + " = " + incomingValue);
            } else {
                // item should now hold the received file
                if (item != null) {
                    fileItem = item;
                }
            }
        }

        // If app ID and file were received, send back HTTP 202 now
        if (appId != null && fileItem != null) {
            sendHttp202(response, "Received app " + appId + " for processing.");
        } else {
            sendHttp400(response, "Did not receive proper request.");
            return;
        }

        String appFilePath = null;
        String reportPath = null;
        String fileName = null;

        if (item != null) {
            fileName = getFileName(fileItem.getName());
            if (!fileName.endsWith(".apk")) {
                sendHttp400(response, "Invalid app file: " + fileItem.getName());
                return;
            }

            appFilePath = Properties.TEMP_DIR + "/" + appId + fileName;
            reportPath = Properties.TEMP_DIR + "/" + appId + "_report.txt";
            log.debug("appFilePath: " + appFilePath);

            if (!saveFileUpload(fileItem, appFilePath)) {
                sendHttp500(response, "Could not save uploaded file");
                return;
            }
        } else {
            log.error("File item was null.");
            return;
        }

        // Test app
        AndroidVulnerabilityScanner vulnerabilityScanner = new AndroidVulnerabilityScanner(appFilePath);

        boolean masterKeyFound = vulnerabilityScanner.hasMasterKey();

        boolean extraFieldFound = vulnerabilityScanner.hasExtraField();
        vulnerabilityScanner.close();

        // Generate report
        String htmlReport = null;
        ToolStatus reportStatus = null;
        if (masterKeyFound) {
            reportStatus = ToolStatus.FAIL;
            htmlReport = generateReport(fileName, reportStatus, "Master Key vulnerability detected.");
        }
        if (extraFieldFound) {
            reportStatus = ToolStatus.FAIL;
            htmlReport = generateReport(fileName, reportStatus, "Extra Field vulnerability detected.");
        }

        if (!masterKeyFound && !extraFieldFound) {
            reportStatus = ToolStatus.PASS;
            htmlReport = generateReport(fileName, reportStatus,
                    "No Master Key or Extra Field vulnerablity detected.");
        }

        // Write report file
        PrintWriter out = new PrintWriter(reportPath);
        out.write(htmlReport);
        out.close();

        // Now send report
        sendReport(appId, reportStatus.name(), reportPath);

        boolean deleted = deleteFile(appFilePath);
        if (deleted) {
            log.debug("Deleted app " + appFilePath);
        } else {
            log.error("Could not delete app file " + appFilePath);
        }

        deleted = deleteFile(reportPath);
        if (deleted) {
            log.debug("Deleted report " + reportPath);
        } else {
            log.error("Could not delete report file " + reportPath);
        }

        // Clean up
        System.gc();
    }

    private String generateReport(String fileName, ToolStatus status, String report) {
        StringBuffer htmlBuffer = new StringBuffer();
        //      htmlBuffer.append("ANDROID MASTER KEY AND EXTRA FIELD REPORT\n\n" 
        //            + new Date().toString() + "\n\n"
        //            + "This report indicates the presence of the Android "
        //            + "'Master Key' or 'Extra Field' vulnerabilities. This report "
        //            + "will generate a FAIL if one or both of these vulnerabilities "
        //            + "are detected, or a PASS if no vulnerabilities are detected. "
        //            + "\n\n------------------------\n");

        htmlBuffer.append("<HTML>\n");
        htmlBuffer.append("<head>\n");
        htmlBuffer.append("<style type=\"text/css\">\n");
        htmlBuffer.append("h3 {font-family:arial;}\n");
        htmlBuffer.append("p {font-family:arial;}\n");
        htmlBuffer.append("</style>\n");
        htmlBuffer.append("<title>Master Key Extra Field Report</title>\n");
        htmlBuffer.append("</head>\n");
        htmlBuffer.append("<body>\n");
        String appVetImagesUrl = Properties.mainURL + "/images/nist-gray.png";
        htmlBuffer.append("<img border=\"0\" width=\"100px\" src=\"" + appVetImagesUrl + "\" alt=\"appvet\" />");
        htmlBuffer.append("<HR>\n");
        htmlBuffer.append("<h3>Master Key Extra Field Report</h3>\n");
        htmlBuffer.append("<pre>\n");
        htmlBuffer.append("File: \t\t" + fileName + "\n");
        final Date date = new Date();
        final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd' 'HH:mm:ss.SSSZ");
        final String currentDate = format.format(date);
        htmlBuffer.append("Date: \t\t" + currentDate + "\n\n");
        if (status == ToolStatus.PASS) {
            htmlBuffer.append("Status: \t<font color=\"green\">" + status.name() + "</font>\n");
        } else {
            htmlBuffer.append("Status: \t<font color=\"red\">" + status.name() + "</font>\n");
        }
        htmlBuffer.append("Description: \t" + report + "\n\n");
        htmlBuffer.append("</body>\n");
        htmlBuffer.append("</HTML>\n");
        return htmlBuffer.toString();
    }

    public static String getFileName(String filePath) {
        String fileName = null;
        int lastBackSlash = filePath.lastIndexOf("\\");
        int lastForwardSlash = filePath.lastIndexOf("/");

        if (lastBackSlash == -1 && lastForwardSlash == -1)
            // No slashes found in file path
            fileName = filePath;
        else if (lastBackSlash >= 0)
            // Back slash detected
            fileName = filePath.substring(lastBackSlash + 1, filePath.length());
        else
            // Forward slash detected
            fileName = filePath.substring(lastForwardSlash + 1, filePath.length());
        return fileName;
    }

    private void sendHttp202(HttpServletResponse response, String message) {
        try {
            response.setStatus(HttpServletResponse.SC_ACCEPTED);
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println(message);
            out.flush();
            out.close();
            log.debug("Sent HTTP 202: " + message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void sendHttp400(HttpServletResponse response, String message) {
        try {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println(message);
            out.flush();
            out.close();
            log.debug("Sent HTTP 400: " + message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void sendHttp500(HttpServletResponse response, String message) {
        try {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println(message);
            out.flush();
            out.close();
            log.debug("Sent HTTP 500: " + message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean saveFileUpload(FileItem fileItem, String outputFilePath) {
        try {
            if (fileItem == null) {
                log.error("fileItem is NULL");
                return false;
            }

            File file = new File(outputFilePath);
            fileItem.write(file);
            log.debug("Saved file " + outputFilePath);
            return true;
        } catch (IOException e) {
            log.error(e.getMessage());
            return false;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }

    public void sendReport(String appid, String toolrisk, String reportPath) {
        HttpParams httpParameters = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParameters, 30000);
        HttpConnectionParams.setSoTimeout(httpParameters, 1200000);
        HttpClient httpclient = new DefaultHttpClient(httpParameters);
        httpclient = SSLWrapper.wrapClient(httpclient);

        try {
            // To send reports back to AppVet, the following parameters must
            // be sent:
            // * command: SUBMIT_REPORT
            // * username: AppVet username
            // * password: AppVet password
            // * appid: The app ID
            // * toolid: The ID of this tool
            // * toolrisk: The risk assessment (PASS,FAIL,WARNING,ERROR)
            // * file: The report file.
            MultipartEntity entity = new MultipartEntity();
            entity.addPart("command", new StringBody("SUBMIT_REPORT", Charset.forName("UTF-8")));
            entity.addPart("username", new StringBody(Properties.appVetUsername, Charset.forName("UTF-8")));
            entity.addPart("password", new StringBody(Properties.appVetPassword, Charset.forName("UTF-8")));
            entity.addPart("appid", new StringBody(appid, Charset.forName("UTF-8")));
            entity.addPart("toolid", new StringBody(Properties.toolId, Charset.forName("UTF-8")));
            entity.addPart("toolrisk", new StringBody(toolrisk, Charset.forName("UTF-8")));

            File report = new File(reportPath);
            FileBody fileBody = new FileBody(report);
            entity.addPart("file", fileBody);

            HttpPost httpPost = new HttpPost(Properties.appVetURL);
            httpPost.setEntity(entity);
            log.debug("Sending report to AppVet");

            // Send the app to the tool
            final HttpResponse response = httpclient.execute(httpPost);
            httpPost = null;
            log.debug("Received: " + response.getStatusLine());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // TODO Return Common Vulnerability Scoring System (CVSS) here in lieu of
    // statuses.
    public boolean returnReport(HttpServletResponse response, ToolStatus reportStatus, String report) {
        try {
            response.setStatus(HttpServletResponse.SC_OK); // HTTP 200
            response.setContentType("text/html");
            response.setHeader("toolrisk", reportStatus.name());
            PrintWriter out = response.getWriter();
            out.println(report.toString());
            out.flush();
            out.close();
            log.debug("Sent HTTP 200");
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean deleteFile(String sourceFilePath) {
        File file = new File(sourceFilePath);
        if (file.exists()) {
            return file.delete();
        } else {
            log.error("File " + sourceFilePath + " does not exist");
            return false;
        }
    }
}