Package com.denimgroup.threadfix.service.defects

Source Code of com.denimgroup.threadfix.service.defects.BugzillaDefectTracker

////////////////////////////////////////////////////////////////////////
//
//     Copyright (c) 2009-2014 Denim Group, Ltd.
//
//     The contents of this file are subject to the Mozilla Public 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.mozilla.org/MPL/
//
//     Software distributed under the License is distributed on an "AS IS"
//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//     License for the specific language governing rights and limitations
//     under the License.
//
//     The Original Code is ThreadFix.
//
//     The Initial Developer of the Original Code is Denim Group, Ltd.
//     Portions created by Denim Group, Ltd. are Copyright (C)
//     Denim Group, Ltd. All Rights Reserved.
//
//     Contributor(s): Denim Group, Ltd.
//
////////////////////////////////////////////////////////////////////////
package com.denimgroup.threadfix.service.defects;

import com.denimgroup.threadfix.data.entities.Defect;
import com.denimgroup.threadfix.data.entities.Vulnerability;
import com.denimgroup.threadfix.service.defects.utils.bugzilla.BugzillaClient;
import com.denimgroup.threadfix.service.defects.utils.bugzilla.BugzillaClientImpl;
import org.apache.xmlrpc.XmlRpcException;

import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.denimgroup.threadfix.CollectionUtils.list;

/**
* @author dcornell
* @author mcollins
*/
public class BugzillaDefectTracker extends AbstractDefectTracker {
   
  private static Map<String, String> versionMap = new HashMap<>();

    BugzillaClient bugzillaClient = BugzillaClientImpl.getInstance();

  private List<String> statuses = list();
  private List<String> components = list();
  private List<String> severities = list();
  private List<String> versions = list();
  private List<String> priorities = list();

    private BugzillaClient.ConnectionStatus configureClientAndGetStatus() {

        BugzillaClient.ConnectionStatus status = null;
        try {
            status = bugzillaClient.configure(getServerURLWithRpc(), username, password);
        } catch (XmlRpcException e) {
            setLastError(e.getMessage());
            return BugzillaClient.ConnectionStatus.INVALID;
        }

        if (status != BugzillaClient.ConnectionStatus.VALID) {
            log.error("Received Bugzilla connection status " + status + ", please fix the error before continuing.");
        }
        return status;
    }

  @Override
  public String createDefect(List<Vulnerability> vulnerabilities, DefectMetadata metadata) {
    String bugzillaId = null;

    // TODO Better handle error cases
    try {

            if (configureClientAndGetStatus() != BugzillaClient.ConnectionStatus.VALID) {
                return null;
            }

      if (!projectExists(projectName)) {
        log.warn("The project name wasn't found on the server.");
        return null;
      }

      String description = makeDescription(vulnerabilities, metadata);
      if (description.length() > 65500) {
        description = description.substring(0, 65499);
      }
     
      if (metadata.getDescription() == null    || metadata.getComponent() == null
          || metadata.getVersion() == null || metadata.getSeverity() == null
          || metadata.getStatus() == null  || metadata.getPriority() == null) {
                log.error("DefectMetadata was missing a field. Please fix this and try again.");

        return null;
      }

      Map<String, String> bugMap = new HashMap<>();
      bugMap.put("product", projectName);
      bugMap.put("component", metadata.getComponent());
      bugMap.put("summary", metadata.getDescription());
      bugMap.put("version", metadata.getVersion());
      bugMap.put("description", description);
      bugMap.put("op_sys", "All");
      bugMap.put("platform", "All");
      bugMap.put("priority", metadata.getPriority());
      bugMap.put("severity", metadata.getSeverity());
      bugMap.put("status", metadata.getStatus());

      Map<String, Integer> actualResult = bugzillaClient.createBug(bugMap);

      Integer returnId = actualResult.get("id");
      bugzillaId = returnId.toString();
    } catch (IllegalArgumentException e2) {
      log.error("Got IllegalArgumentException.", e2);
    } catch (XmlRpcException e) {
            log.error("Got XmlRpcException.", e);
        }

    return bugzillaId;
  }

  /**
   * Retrieve all the variable fields that Bugzilla installations have.
   */
  @Override
  public ProjectMetadata getProjectMetadata() {
    getPermissibleBugFieldValues();
   
    return new ProjectMetadata(components, versions,
        severities, statuses, priorities);
  }

  @SuppressWarnings("unchecked")
  @Override
  public Map<Defect, Boolean> getMultipleDefectStatus(List<Defect> defectList) {
        if (configureClientAndGetStatus() != BugzillaClient.ConnectionStatus.VALID) {
            return null;
        }

    Map<String, Defect> idDefectMap = new HashMap<>();
   
    for (Defect defect : defectList) {
      if (defect != null && defect.getNativeId() != null) {
        idDefectMap.put(defect.getNativeId(), defect);
      }
    }
   
    Map<String, Object[]> queryMap = new HashMap<>();
    queryMap.put("ids", idDefectMap.keySet().toArray(
        new Object[idDefectMap.keySet().size()]));

        Object queryResult = null;
        try {
            queryResult = bugzillaClient.executeMethod("Bug.get", queryMap);
        } catch (XmlRpcException e) {
            log.error("Encountered XmlRpcException while trying to get bug information", e);
        }

        Map<Defect, Boolean> returnList = new HashMap<>();

    if (queryResult instanceof HashMap) {
      Map<String,Object[]> returnedData = (HashMap<String, Object[]>) queryResult;
      Object[] bugsArray = returnedData.get("bugs");
      for (int i = 0; i < bugsArray.length; i++) {
        Object currentBug = bugsArray[i];
        Map<String,Object> currentBugHash = (HashMap<String, Object>) currentBug;
        if (currentBugHash == null) {
          continue;
        }

        Boolean isOpen = (Boolean) currentBugHash.get("is_open");
        Object result = currentBugHash.get("status");
       
        Integer id = (Integer) currentBugHash.get("id");
       
        if (idDefectMap.containsKey(id.toString()) &&
            idDefectMap.get(id.toString()) != null) {
          Defect defect = idDefectMap.get(id.toString());
         
          if (result instanceof String) {
            defect.setStatus((String) result);
          }
         
          returnList.put(defect, isOpen);
        }
      }
    } else {
      log.error("Expected a HashMap return value, but got something else instead: " + queryResult);
    }
   
    return returnList;
  }

  @Override
  public String getTrackerError() {
        if (configureClientAndGetStatus() != BugzillaClient.ConnectionStatus.VALID) {
            return null;
        }

    if (!projectExists(projectName)) {
      return "The project specified does not exist - please specify a different"
          + " one or create " + projectName + " in Bugzilla.";
    }

    return null;
  }
 
  private void getPermissibleBugFieldValues(){
        if (configureClientAndGetStatus() != BugzillaClient.ConnectionStatus.VALID) {
            return;
        }

        try {
            Map<String, String> bugMap = new HashMap<>();
            bugMap.put("field", "bug_severity");
            Object[] bugArray = new Object[] { bugMap };
            Object createResult = bugzillaClient.executeMethod("Bug.legal_values", bugArray);
            severities.addAll(getValues(createResult));

            bugMap.put("field", "bug_status");
            bugArray = new Object[] { bugMap }; // maybe useless line
            createResult = bugzillaClient.executeMethod("Bug.legal_values", bugArray);
            statuses.addAll(getValues(createResult));

            if (statuses.contains("UNCONFIRMED")) {
                statuses.remove("UNCONFIRMED");
            }

            bugMap.put("field", "priority");
            createResult = bugzillaClient.executeMethod("Bug.legal_values", bugMap);
            priorities.addAll(getValues(createResult));

            projectId = getProjectIdByName();

            Map<String, String> queryMap = new HashMap<>();
            queryMap.put("field", "version");
            queryMap.put("product_id", projectId);
            createResult = bugzillaClient.executeMethod("Bug.legal_values", queryMap);
            versions.addAll(getValues(createResult));

            queryMap = new HashMap<>();
            queryMap.put("field", "component");
            queryMap.put("product_id", projectId);
            createResult = bugzillaClient.executeMethod("Bug.legal_values", queryMap);
            components.addAll(getValues(createResult));
        } catch (XmlRpcException e) {
            log.error("Encountered XmlRpcException while trying to read fields from Bugzilla.", e);
        }
  }

  /**
   * If the Object given is a map containing a mapping for "values" to
   * an object array containing string values, this method will return
   * a List containing those items.
   * @param rpcResponse
   * @return
   */
  private List<String> getValues(Object rpcResponse) {
    List<String> responseList = list();
    if (rpcResponse != null && rpcResponse instanceof HashMap) {
      Map<?, ?> returnedData = (HashMap<?, ?>) rpcResponse;
      Object componentsObject = returnedData.get("values");
      if (componentsObject != null && componentsObject instanceof Object[]) {
        Object[] componentsArray = (Object[]) componentsObject;
                for (Object component : componentsArray) {
                    if (component != null) {
                        responseList.add(component.toString());
                    }
                }
      }
    }
    return responseList;
  }
 
  public String getVersion() {
    if (versionMap.get(url) != null) {
      return versionMap.get(url);
    }

        Object createResult = null;
        try {
            createResult = bugzillaClient.executeMethod("Bugzilla.version");
        } catch (XmlRpcException e) {
            log.error("Got XmlRpcException while trying to get the bugzilla version.", e);
        }

        if (createResult instanceof Map<?,?>) {
      Map<?,?> item = (Map<?,?>) createResult;
      if (item.get("version") != null) {
        log.info("Bugzilla instance is version " + item.get("version"));
        versionMap.put(url, item.get("version").toString());
      }
    }
    return versionMap.get(url);
  }

  public boolean projectExists(String projectName) {
    this.projectName = projectName;
    return getProjectIdByName() != null;
  }

  @SuppressWarnings("unchecked")
    @Nonnull
  private List<String> getProducts() {
        List<String> returnList = list();

    try {
      Map<String,Object[]> productsMap = (HashMap<String, Object[]>) bugzillaClient.executeMethod(
                    "Product.get_accessible_products");
      Object[] ids = productsMap.get("ids");


      Map<String,Object[]> params = new HashMap<>();
      params.put("ids", ids);

      Map<String,Object[]> productMap = (HashMap<String, Object[]>) bugzillaClient.executeMethod(
          "Product.get", params);
      Object[] products = productMap.get("products");
     
      for (Object item : products) {
        Map<String,Object> product = (HashMap<String, Object>) item;
        String productName = (String) product.get("name");
                returnList.add(productName);
      }

    } catch (XmlRpcException e) {
            log.error(e.getMessage());
            setLastError(e.getMessage());
            return list(e.getMessage());
//      e.printStackTrace();
    } catch (IllegalArgumentException e2) {
      if (e2.getMessage().contains("Host name may not be null")) {
        return list(BAD_CONFIGURATION);
      } else {
        e2.printStackTrace();
        return list(BAD_CONFIGURATION);
      }
    }
    if (returnList.isEmpty()){
      setLastError("There were problems communicating with the Bugzilla server.");
      return list("Authentication failed");
    }

    return returnList;
  }

  public String getProjectIdByName() {
    String version = getVersion();
   
    if (version == null) {
      log.info("Unable to get Bugzilla version. Exiting.");
    } else if (version.charAt(0) == '3') {
      return getProjectIdByNameVersion3();
    } else if (version.charAt(0) == '4'){
      return getProjectIdByNameVersion4();
    } else {
      log.warn("Bugzilla version was not 3 or 4, exiting.");
    }
    return null;
  }
 
  @SuppressWarnings("unchecked")
  private String getProjectIdByNameVersion3() {
    if (projectName == null)
      return null;

        if (configureClientAndGetStatus() != BugzillaClient.ConnectionStatus.VALID) {
            return null;
        }

    try {
      Map<String,Object[]> productsMap = (HashMap<String, Object[]>) bugzillaClient.executeMethod(
          "Product.get_enterable_products");
      Object[] ids = productsMap.get("ids");

      Map<String,Object[]> params = new HashMap<>();
      params.put("ids", ids);

      Map<String, Object[]> productMap = (HashMap<String, Object[]>) bugzillaClient.executeMethod(
          "Product.get", params);
      Object[] products = productMap.get("products");
      if (products == null)
        return null;
            for (Object product1 : products) {
                Map<String, Object> product = (HashMap<String, Object>) product1;
                String productName = (String) product.get("name");
                if (projectName.equals(productName)) {
                    Integer temp = (Integer) product.get("id");
                    projectId = Integer.toString(temp);
                    return projectId;
                }
            }
    } catch (XmlRpcException xre) {
      xre.printStackTrace();
    } catch (IllegalArgumentException e2) {
      return null;
    }
    return null;
  }
 
  private String getProjectIdByNameVersion4() {
        if (configureClientAndGetStatus() != BugzillaClient.ConnectionStatus.VALID) {
            return null;
        }

    // get Product info
    Map<String, Object[]> bugMap = new HashMap<>();
    bugMap.put("names", new Object[] { projectName });

        Object createResult = null;
        try {
            createResult = bugzillaClient.executeMethod("Product.get", bugMap);
        } catch (XmlRpcException e) {
            log.error("Encountered XmlRpcException while getting project information.", e);
        }
        if (createResult != null && createResult instanceof Map<?, ?>) {
      Map<?, ?> mapVersion = (Map<?, ?>) createResult;
      if (mapVersion.containsKey("products")) {
        Object result = mapVersion.get("products");
        if (result instanceof Object[]) {
          Object[] stuff = (Object[]) result;
          for (Object item : stuff) {
            if (item instanceof Map<?, ?>) {
              Map<?,?> map = (Map<?,?>) item;
              if (map.get("id") != null) {
                return map.get("id").toString();
              }
            }
          }
        }
      }
    }
   
    return null;
  }

  @Nonnull
    @Override
  public List<String> getProductNames() {
        BugzillaClient.ConnectionStatus status = configureClientAndGetStatus();

    if (status == BugzillaClient.ConnectionStatus.INVALID) {
      if (getLastError() == null || getLastError().isEmpty())
                setLastError(status.toString());
      return list();
    } else {
            setLastError(null);
      return getProducts();
    }
  }

  @Override
  public boolean hasValidCredentials() {
    return configureClientAndGetStatus() == BugzillaClient.ConnectionStatus.VALID;
  }

  @Override
  public boolean hasValidProjectName() {
    return projectName != null && projectExists(projectName);
  }

  @Override
  public String getBugURL(String endpointURL, String bugID) {
    if (endpointURL != null && bugID != null && endpointURL.endsWith("xmlrpc.cgi")) {
      return endpointURL.replace("xmlrpc.cgi", "show_bug.cgi?id="+bugID);
    } else  if (endpointURL != null) {
      if (endpointURL.endsWith("/")) {
        return endpointURL + "show_bug.cgi?id=" + bugID;
      } else {
        return endpointURL + "/show_bug.cgi?id=" + bugID;
      }
    } else {
      log.error("getBugURL() in BugzillaDefectTracker was given a null endpointURL.");
      return null;
    }
  }

  @Override
  public boolean hasValidUrl() {
    log.info("Checking Bugzilla URL.");
    return bugzillaClient.checkUrl(getServerURLWithRpc());
  }
 
  public String getServerURLWithRpc() {
    if (url == null || url.trim().equals("")) {
      return null;
    }
 
    if (url.contains("xmlrpc.cgi")) {
      return url;
    }
 
    String tempUrl = url.trim();
    if (tempUrl.endsWith("/")) {
      tempUrl = tempUrl.concat("xmlrpc.cgi");
    } else {
      tempUrl = tempUrl.concat("/xmlrpc.cgi");
    }
 
    return tempUrl;
  }

  @SuppressWarnings("unchecked")
  @Override
  public List<Defect> getDefectList() {

        if (configureClientAndGetStatus() != BugzillaClient.ConnectionStatus.VALID) {
            return null;
        }
   
    List<Defect> returnList = list();
    Map<String, String> queryMap = new HashMap<>();
    queryMap.put("product", projectName);

        Object queryResult;

        try {
            queryResult = bugzillaClient.executeMethod("Bug.search", queryMap);
        } catch (XmlRpcException e) {
            log.error("Encountered XmlRpcException while getting defect information");
            return list(); // TODO see if this is the right thing
        }

        if (queryResult instanceof HashMap) {
      Map<String,Object[]> returnedData = (HashMap<String, Object[]>) queryResult;
      Object[] bugsArray = returnedData.get("bugs");
            for (Object currentBug : bugsArray) {
                Map<String, Object> currentBugHash = (HashMap<String, Object>) currentBug;
                if (currentBugHash == null) {
                    continue;
                }
                Integer id = (Integer) currentBugHash.get("id");
                Defect defect = new Defect();
                defect.setNativeId(String.valueOf(id));
                returnList.add(defect);
            }
    } else {
      log.error("Expected a HashMap return value, but got something else instead.");
    }
   
    return returnList;
  }
}
TOP

Related Classes of com.denimgroup.threadfix.service.defects.BugzillaDefectTracker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.