mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
cloud http client with proxy
This commit is contained in:
parent
0c3394e88f
commit
38ad881023
@ -0,0 +1,378 @@
|
||||
/** *************************************************************************
|
||||
** This data and information is proprietary to, and a valuable trade secret
|
||||
** of, Basis Technology Corp. It is given in confidence by Basis Technology
|
||||
** and may only be used as permitted under the license agreement under which
|
||||
** it has been distributed, and in no other way.
|
||||
**
|
||||
** Copyright (c) 2023 Basis Technology Corp. All rights reserved.
|
||||
**
|
||||
** The technical data and information provided herein are provided with
|
||||
** `limited rights', and the computer software provided herein is provided
|
||||
** with `restricted rights' as those terms are defined in DAR and ASPR
|
||||
** 7-104.9(a).
|
||||
************************************************************************** */
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi;
|
||||
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.io.IOException;
|
||||
import java.net.Authenticator;
|
||||
import java.net.InetAddress;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.NTCredentials;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.client.config.AuthSchemes;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
|
||||
import org.apache.http.impl.client.WinHttpClients;
|
||||
|
||||
/**
|
||||
* Actually makes the http requests to CT cloud.
|
||||
*/
|
||||
public class CTCloudHttpClient {
|
||||
|
||||
private static final CTCloudHttpClient instance = new CTCloudHttpClient();
|
||||
private static final Logger LOGGER = Logger.getLogger(CTCloudHttpClient.class.getName());
|
||||
|
||||
private static final List<String> DEFAULT_SCHEME_PRIORITY
|
||||
= new ArrayList<>(Arrays.asList(
|
||||
AuthSchemes.SPNEGO,
|
||||
AuthSchemes.KERBEROS,
|
||||
AuthSchemes.NTLM,
|
||||
AuthSchemes.CREDSSP,
|
||||
AuthSchemes.DIGEST,
|
||||
AuthSchemes.BASIC));
|
||||
|
||||
private static final int CONNECTION_TIMEOUT_MS = 58 * 1000; // milli sec
|
||||
|
||||
public static CTCloudHttpClient getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private final ObjectMapper mapper = ObjectMapperUtil.getInstance().getDefaultObjectMapper();
|
||||
private final SSLContext sslContext;
|
||||
private String hostName = null;
|
||||
|
||||
private CTCloudHttpClient() {
|
||||
SSLContext tmpSslContext;
|
||||
try {
|
||||
tmpSslContext = SSLContext.getInstance("TLSv1.2");
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
LOGGER.log(Level.WARNING, "Unable to setup ssl context instance", ex);
|
||||
tmpSslContext = null;
|
||||
}
|
||||
this.sslContext = tmpSslContext;
|
||||
}
|
||||
|
||||
private ProxySettingArgs getProxySettings() {
|
||||
if (StringUtils.isBlank(hostName)) {
|
||||
try {
|
||||
hostName = InetAddress.getLocalHost().getCanonicalHostName();
|
||||
} catch (UnknownHostException ex) {
|
||||
LOGGER.log(Level.WARNING, "An error occurred while fetching the hostname", ex);
|
||||
}
|
||||
}
|
||||
|
||||
int proxyPort = 0;
|
||||
try {
|
||||
proxyPort = Integer.parseInt(ProxySettings.getHttpsPort());
|
||||
} catch (NumberFormatException ex) {
|
||||
LOGGER.log(Level.WARNING, "An exception occurred while converting port number to integer", ex);
|
||||
}
|
||||
|
||||
return new ProxySettingArgs(
|
||||
ProxySettings.getProxyType() != ProxySettings.DIRECT_CONNECTION,
|
||||
hostName,
|
||||
ProxySettings.getHttpsHost(),
|
||||
proxyPort,
|
||||
ProxySettings.getAuthenticationUsername(),
|
||||
ProxySettings.getAuthenticationPassword(),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
public <O> O doPost(String urlPath, Object jsonBody, Class<O> classType) throws CTCloudException {
|
||||
String url = Constants.CT_CLOUD_SERVER + urlPath;
|
||||
try {
|
||||
|
||||
LOGGER.log(Level.INFO, "initiating http connection to ctcloud server");
|
||||
try (CloseableHttpClient httpclient = createConnection(getProxySettings(), sslContext)) {
|
||||
URIBuilder builder = new URIBuilder(url);
|
||||
URI postURI = builder.build();
|
||||
HttpPost postRequest = new HttpPost(postURI);
|
||||
|
||||
configureRequestTimeout(postRequest);
|
||||
postRequest.setHeader("Content-type", "application/json");
|
||||
|
||||
if (jsonBody != null) {
|
||||
String requestBody = mapper.writeValueAsString(jsonBody);
|
||||
if (StringUtils.isNotBlank(requestBody)) {
|
||||
HttpEntity entity = new StringEntity(requestBody, "UTF-8");
|
||||
postRequest.setEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.log(Level.INFO, "initiating http post request to ctcloud server " + postRequest.getURI());
|
||||
try (CloseableHttpResponse response = httpclient.execute(postRequest)) {
|
||||
|
||||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
|
||||
LOGGER.log(Level.INFO, "Response Received. - Status OK");
|
||||
// Parse Response
|
||||
HttpEntity entity = response.getEntity();
|
||||
String entityStr = EntityUtils.toString(entity);
|
||||
O respObj = mapper.readValue(entityStr, classType);
|
||||
return respObj;
|
||||
} else {
|
||||
LOGGER.log(Level.WARNING, "Response Received. - Status Error {}", response.getStatusLine());
|
||||
handleNonOKResponse(response, "");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOGGER.log(Level.WARNING, "Error when parsing response from CyberTriage Cloud", ex);
|
||||
throw new CTCloudException(CTCloudException.parseUnknownException(ex), ex);
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.WARNING, "IO Exception raised when connecting to CT Cloud using " + url, ex);
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR, ex);
|
||||
} catch (URISyntaxException ex) {
|
||||
LOGGER.log(Level.WARNING, "Wrong URL syntax for CT Cloud " + url, ex);
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.UNKNOWN, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic way to handle the HTTP response - when the response code is NOT
|
||||
* 200 OK.
|
||||
*
|
||||
* @param response
|
||||
* @param fileName - used only for logging.
|
||||
* @throws MalwareScannerException
|
||||
* @throws IOException
|
||||
*/
|
||||
private void handleNonOKResponse(CloseableHttpResponse response, String fileName) throws CTCloudException, IOException {
|
||||
LOGGER.log(Level.WARNING, MessageFormat.format(
|
||||
"Response code {0}. Message Body {1}",
|
||||
response.getStatusLine().getStatusCode(),
|
||||
EntityUtils.toString(response.getEntity())));
|
||||
|
||||
switch (response.getStatusLine().getStatusCode()) {
|
||||
|
||||
case HttpStatus.SC_BAD_REQUEST:
|
||||
//400: Bad request => Unsupported HTTP method or invalid http request (e.g., empty body).
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.BAD_REQUEST);
|
||||
case HttpStatus.SC_UNAUTHORIZED:
|
||||
//401 Invalid API key => An invalid API key, or no API key, has been provided
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.INVALID_KEY);
|
||||
case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
|
||||
// 407 Proxy server authentication required.
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.PROXY_UNAUTHORIZED);
|
||||
case HttpStatus.SC_FORBIDDEN:
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.UN_AUTHORIZED);
|
||||
case HttpStatus.SC_INTERNAL_SERVER_ERROR:
|
||||
//500 Internal error Server temporarily unavailable; please try again later. If the issue persists, please contact RL.
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.TEMP_UNAVAILABLE);
|
||||
case HttpStatus.SC_SERVICE_UNAVAILABLE:
|
||||
//503 Server is too busy. Try again later.
|
||||
//503 Failed to request scan. Try again later. The server is currently unable to handle the request due to a temporary overloading or maintenance of the server. If the issue persists, please contact RL.
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.TEMP_UNAVAILABLE);
|
||||
case HttpStatus.SC_GATEWAY_TIMEOUT:
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.GATEWAY_TIMEOUT);
|
||||
default:
|
||||
String returnData = EntityUtils.toString(response.getEntity());
|
||||
LOGGER.log(Level.WARNING, MessageFormat.format("upload response content for {0}:\n {1}", fileName, returnData));
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE That this is not a perfect solution as timeouts set this way does
|
||||
* not terminate a connection forcefully after a specified interval. so if
|
||||
* there is data streaming in from the server at a small speed the
|
||||
* connection will be kept open.
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
private void configureRequestTimeout(HttpRequestBase request) {
|
||||
RequestConfig config = RequestConfig.custom()
|
||||
.setConnectionRequestTimeout(CONNECTION_TIMEOUT_MS)
|
||||
.setConnectTimeout(CONNECTION_TIMEOUT_MS)
|
||||
.setSocketTimeout(CONNECTION_TIMEOUT_MS)
|
||||
.build();
|
||||
request.setConfig(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a CloseableHttpClient SYSTEM and MANUAL looks up from
|
||||
* runtime proxy config settings. These are updated accordingly from the
|
||||
* Proxy Config UI. This allows us to keep the CreateConnection call fairly
|
||||
* simple and not have to deal with the System Proxy settings and such.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static CloseableHttpClient createConnection(ProxySettingArgs proxySettings, SSLContext sslContext) {
|
||||
HttpClientBuilder builder = getHttpClientBuilder(proxySettings);
|
||||
|
||||
if (sslContext != null) {
|
||||
builder.setSSLContext(sslContext);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static HttpClientBuilder getHttpClientBuilder(ProxySettingArgs proxySettings) {
|
||||
|
||||
if (proxySettings.isSystemOrManualProxy()) {
|
||||
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
LOGGER.info("Requesting Password Authentication...");
|
||||
return super.getPasswordAuthentication();
|
||||
}
|
||||
});
|
||||
|
||||
HttpClientBuilder builder = null;
|
||||
HttpHost proxyHost = null;
|
||||
CredentialsProvider proxyCredsProvider = null;
|
||||
RequestConfig config = null;
|
||||
|
||||
if (Objects.nonNull(proxySettings.getProxyHostname()) && proxySettings.getProxyPort() > 0) {
|
||||
proxyHost = new HttpHost(proxySettings.getProxyHostname(), proxySettings.getProxyPort());
|
||||
|
||||
proxyCredsProvider = getProxyCredentialsProvider(proxySettings);
|
||||
if (StringUtils.isNotBlank(proxySettings.getAuthScheme())) {
|
||||
if (!DEFAULT_SCHEME_PRIORITY.get(0).equalsIgnoreCase(proxySettings.getAuthScheme())) {
|
||||
DEFAULT_SCHEME_PRIORITY.removeIf(s -> s.equalsIgnoreCase(proxySettings.getAuthScheme()));
|
||||
DEFAULT_SCHEME_PRIORITY.add(0, proxySettings.getAuthScheme());
|
||||
}
|
||||
}
|
||||
config = RequestConfig.custom().setProxyPreferredAuthSchemes(DEFAULT_SCHEME_PRIORITY).build();
|
||||
}
|
||||
|
||||
if (Objects.isNull(proxyCredsProvider) && WinHttpClients.isWinAuthAvailable()) {
|
||||
builder = WinHttpClients.custom();
|
||||
builder.useSystemProperties();
|
||||
LOGGER.log(Level.WARNING, "Using Win HTTP Client");
|
||||
} else {
|
||||
builder = HttpClients.custom();
|
||||
builder.setDefaultRequestConfig(config);
|
||||
if (Objects.nonNull(proxyCredsProvider)) { // make sure non null proxycreds before setting it
|
||||
builder.setDefaultCredentialsProvider(proxyCredsProvider);
|
||||
}
|
||||
LOGGER.log(Level.WARNING, "Using default http client");
|
||||
}
|
||||
if (Objects.nonNull(proxyHost)) {
|
||||
builder.setProxy(proxyHost);
|
||||
LOGGER.log(Level.WARNING, MessageFormat.format("Using proxy {0}", proxyHost));
|
||||
}
|
||||
|
||||
return builder;
|
||||
} else {
|
||||
return HttpClients.custom();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CredentialsProvider for proxy, if one is configured.
|
||||
*
|
||||
* @return CredentialsProvider, if a proxy is configured with credentials,
|
||||
* null otherwise
|
||||
*/
|
||||
private static CredentialsProvider getProxyCredentialsProvider(ProxySettingArgs proxySettings) {
|
||||
CredentialsProvider proxyCredsProvider = null;
|
||||
if (proxySettings.isSystemOrManualProxy()) {
|
||||
if (StringUtils.isNotBlank(proxySettings.getProxyUserId())) {
|
||||
if (null != proxySettings.getProxyPassword() && proxySettings.getProxyPassword().length > 0) { // Password will be blank for KERBEROS / NEGOTIATE schemes.
|
||||
proxyCredsProvider = new SystemDefaultCredentialsProvider();
|
||||
String userId = proxySettings.getProxyUserId();
|
||||
String domain = null;
|
||||
if (userId.contains("\\")) {
|
||||
domain = userId.split("\\\\")[0];
|
||||
userId = userId.split("\\\\")[1];
|
||||
}
|
||||
String workStation = proxySettings.getHostName();
|
||||
proxyCredsProvider.setCredentials(new AuthScope(proxySettings.getProxyHostname(), proxySettings.getProxyPort()),
|
||||
new NTCredentials(userId, new String(proxySettings.getProxyPassword()), workStation, domain));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return proxyCredsProvider;
|
||||
}
|
||||
|
||||
private static class ProxySettingArgs {
|
||||
|
||||
private final boolean systemOrManualProxy;
|
||||
private final String hostName;
|
||||
private final String proxyHostname;
|
||||
private final int proxyPort;
|
||||
private final String proxyUserId;
|
||||
private final char[] proxyPassword;
|
||||
private final String authScheme;
|
||||
|
||||
ProxySettingArgs(boolean systemOrManualProxy, String hostName, String proxyHostname, int proxyPort, String proxyUserId, char[] proxyPassword, String authScheme) {
|
||||
this.systemOrManualProxy = systemOrManualProxy;
|
||||
this.hostName = hostName;
|
||||
this.proxyHostname = proxyHostname;
|
||||
this.proxyPort = proxyPort;
|
||||
this.proxyUserId = proxyUserId;
|
||||
this.proxyPassword = proxyPassword;
|
||||
this.authScheme = authScheme;
|
||||
}
|
||||
|
||||
boolean isSystemOrManualProxy() {
|
||||
return systemOrManualProxy;
|
||||
}
|
||||
|
||||
String getHostName() {
|
||||
return hostName;
|
||||
}
|
||||
|
||||
String getProxyHostname() {
|
||||
return proxyHostname;
|
||||
}
|
||||
|
||||
int getProxyPort() {
|
||||
return proxyPort;
|
||||
}
|
||||
|
||||
String getProxyUserId() {
|
||||
return proxyUserId;
|
||||
}
|
||||
|
||||
char[] getProxyPassword() {
|
||||
return proxyPassword;
|
||||
}
|
||||
|
||||
public String getAuthScheme() {
|
||||
return authScheme;
|
||||
}
|
||||
}
|
||||
}
|
@ -15,50 +15,52 @@ package com.basistech.df.cybertriage.autopsy.ctapi;
|
||||
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenRequest;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenResponse;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthenticatedRequestData;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationRequest;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationResponse;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationResult;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseRequest;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseResponse;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.util.CTHostIDGenerationUtil;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.sleuthkit.autopsy.coreutils.Version;
|
||||
|
||||
/**
|
||||
*
|
||||
* Data access layer for handling the CT api.
|
||||
*/
|
||||
public class CtApiDAO {
|
||||
public class CTApiDAO {
|
||||
|
||||
private static final String LICENSE_REQUEST_PATH = "/_ah/api/license/v1/activate";
|
||||
private static final String AUTH_TOKEN_REQUEST_PATH = "/_ah/api/auth/v2/generate_token";
|
||||
private static final String CTCLOUD_SERVER_HASH_PATH = "/_ah/api/reputation/v1/query/file/hash/md5?query_types=CORRELATION,MALWARE";
|
||||
|
||||
private static final CtApiDAO instance = new CtApiDAO();
|
||||
private final ObjectMapper mapper = ObjectMapperUtil.getInstance().getDefaultObjectMapper();
|
||||
private static final CTApiDAO instance = new CTApiDAO();
|
||||
|
||||
|
||||
private CtApiDAO() {
|
||||
private CTApiDAO() {
|
||||
}
|
||||
|
||||
public static CtApiDAO getInstance() {
|
||||
public static CTApiDAO getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
private static String getAppVersion() {
|
||||
return Version.getName() + " " + Version.getVersion();
|
||||
}
|
||||
|
||||
private final CTCloudHttpClient httpClient = CTCloudHttpClient.getInstance();
|
||||
|
||||
private <T> T doPost(String urlPath, Object requestBody, Class<T> responseTypeRef) throws CTCloudException {
|
||||
return null;
|
||||
// TODO
|
||||
}
|
||||
|
||||
public LicenseResponse getLicenseInfo(String licenseString) throws CTCloudException {
|
||||
LicenseRequest licenseRequest = new LicenseRequest()
|
||||
.setBoostLicenseCode(licenseString)
|
||||
.setHostId(CTHostIDGenerationUtil.generateLicenseHostID())
|
||||
.setProduct(getAppVersion());
|
||||
|
||||
return doPost(LICENSE_REQUEST_PATH, licenseRequest, LicenseResponse.class);
|
||||
|
||||
return httpClient.doPost(LICENSE_REQUEST_PATH, licenseRequest, LicenseResponse.class);
|
||||
|
||||
}
|
||||
|
||||
@ -67,14 +69,25 @@ public class CtApiDAO {
|
||||
.setAutopsyVersion(getAppVersion())
|
||||
.setRequestFileUpload(true)
|
||||
.setBoostLicenseId(boostLicenseId);
|
||||
|
||||
return doPost(AUTH_TOKEN_REQUEST_PATH, authTokenRequest, AuthTokenResponse.class);
|
||||
|
||||
return httpClient.doPost(AUTH_TOKEN_REQUEST_PATH, authTokenRequest, AuthTokenResponse.class);
|
||||
}
|
||||
|
||||
public List<FileReputationResult> getReputationResults(String authToken, List<String> md5Hashes) throws CTCloudException {
|
||||
// TODO
|
||||
// return cloudServiceApi.lookupFileResults(md5Hashes, HashTypes.md5);
|
||||
return null;
|
||||
public List<FileReputationResult> getReputationResults(AuthenticatedRequestData authenticatedRequestData, List<String> md5Hashes) throws CTCloudException {
|
||||
if (CollectionUtils.isEmpty(md5Hashes)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
FileReputationRequest fileRepReq = new FileReputationRequest()
|
||||
.setApiKey(authenticatedRequestData.getApiKey())
|
||||
.setHostId(CTHostIDGenerationUtil.generateLicenseHostID())
|
||||
.setToken(authenticatedRequestData.getToken())
|
||||
.setHashes(md5Hashes);
|
||||
|
||||
FileReputationResponse resp = httpClient.doPost(CTCLOUD_SERVER_HASH_PATH, fileRepReq, FileReputationResponse.class);
|
||||
return resp == null || resp.getItems() == null
|
||||
? Collections.emptyList()
|
||||
: resp.getItems();
|
||||
}
|
||||
|
||||
public enum ResultType {
|
||||
|
@ -20,9 +20,7 @@ import java.time.ZonedDateTime;
|
||||
/**
|
||||
* POJO for an auth token response.
|
||||
*/
|
||||
public class AuthTokenResponse {
|
||||
private final String token;
|
||||
private final String apiKey;
|
||||
public class AuthTokenResponse extends AuthenticatedRequestData {
|
||||
private final Long hashLookupCount;
|
||||
private final Long hashLookupLimit;
|
||||
private final Long fileUploadLimit;
|
||||
@ -51,14 +49,6 @@ public class AuthTokenResponse {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public String getApiKey() {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
public Long getHashLookupCount() {
|
||||
return hashLookupCount;
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
/** *************************************************************************
|
||||
** This data and information is proprietary to, and a valuable trade secret
|
||||
** of, Basis Technology Corp. It is given in confidence by Basis Technology
|
||||
** and may only be used as permitted under the license agreement under which
|
||||
** it has been distributed, and in no other way.
|
||||
**
|
||||
** Copyright (c) 2023 Basis Technology Corp. All rights reserved.
|
||||
**
|
||||
** The technical data and information provided herein are provided with
|
||||
** `limited rights', and the computer software provided herein is provided
|
||||
** with `restricted rights' as those terms are defined in DAR and ASPR
|
||||
** 7-104.9(a).
|
||||
************************************************************************** */
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Data required for an authenticated request.
|
||||
*/
|
||||
public abstract class AuthenticatedRequestData {
|
||||
|
||||
@JsonProperty("token")
|
||||
protected String token;
|
||||
@JsonProperty("api_key")
|
||||
protected String apiKey;
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public String getApiKey() {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/** *************************************************************************
|
||||
** This data and information is proprietary to, and a valuable trade secret
|
||||
** of, Basis Technology Corp. It is given in confidence by Basis Technology
|
||||
** and may only be used as permitted under the license agreement under which
|
||||
** it has been distributed, and in no other way.
|
||||
**
|
||||
** Copyright (c) 2023 Basis Technology Corp. All rights reserved.
|
||||
**
|
||||
** The technical data and information provided herein are provided with
|
||||
** `limited rights', and the computer software provided herein is provided
|
||||
** with `restricted rights' as those terms are defined in DAR and ASPR
|
||||
** 7-104.9(a).
|
||||
************************************************************************** */
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Request for file reputation results.
|
||||
*/
|
||||
public class FileReputationRequest extends AuthenticatedRequestData {
|
||||
|
||||
@JsonProperty("hashes")
|
||||
private List<String> hashes;
|
||||
|
||||
@JsonProperty("host_id")
|
||||
private String hostId;
|
||||
|
||||
public List<String> getHashes() {
|
||||
return hashes;
|
||||
}
|
||||
|
||||
public FileReputationRequest setHashes(List<String> hashes) {
|
||||
this.hashes = hashes;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileReputationRequest setToken(String token) {
|
||||
this.token = token;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileReputationRequest setApiKey(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getHostId() {
|
||||
return hostId;
|
||||
}
|
||||
|
||||
public FileReputationRequest setHostId(String hostId) {
|
||||
this.hostId = hostId;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/** *************************************************************************
|
||||
** This data and information is proprietary to, and a valuable trade secret
|
||||
** of, Basis Technology Corp. It is given in confidence by Basis Technology
|
||||
** and may only be used as permitted under the license agreement under which
|
||||
** it has been distributed, and in no other way.
|
||||
**
|
||||
** Copyright (c) 2023 Basis Technology Corp. All rights reserved.
|
||||
**
|
||||
** The technical data and information provided herein are provided with
|
||||
** `limited rights', and the computer software provided herein is provided
|
||||
** with `restricted rights' as those terms are defined in DAR and ASPR
|
||||
** 7-104.9(a).
|
||||
************************************************************************** */
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Container for file reputation result list response.
|
||||
*/
|
||||
public class FileReputationResponse {
|
||||
|
||||
private final List<FileReputationResult> items;
|
||||
|
||||
@JsonCreator
|
||||
public FileReputationResponse(
|
||||
@JsonProperty("items") List<FileReputationResult> items
|
||||
) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public List<FileReputationResult> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
}
|
@ -29,7 +29,7 @@ public class CTHostIDGenerationUtil {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(CTHostIDGenerationUtil.class.getName());
|
||||
private static final String USER_NAME = System.getProperty("user.name");
|
||||
private static String HOST_NAME = "";
|
||||
private static String cachedId = "";
|
||||
|
||||
/**
|
||||
* Host ID Algorithm: Get MAC address from License4J. Get MD5 hash of it and
|
||||
@ -41,17 +41,24 @@ public class CTHostIDGenerationUtil {
|
||||
* @return
|
||||
*/
|
||||
public static String generateLicenseHostID() {
|
||||
if (StringUtils.isBlank(HOST_NAME)) {
|
||||
|
||||
if (StringUtils.isBlank(cachedId)) {
|
||||
try {
|
||||
HOST_NAME = StringUtils.defaultString(InetAddress.getLocalHost().getCanonicalHostName());
|
||||
String hostName = StringUtils.defaultString(InetAddress.getLocalHost().getCanonicalHostName());
|
||||
String macAddressMd5 = StringUtils.isNotBlank(HardwareID.getHardwareIDFromEthernetAddress())
|
||||
? Md5HashUtil.getMD5MessageDigest(HardwareID.getHardwareIDFromEthernetAddress()).substring(0, 16)
|
||||
: Md5HashUtil.getMD5MessageDigest(hostName).substring(0, 16);
|
||||
|
||||
String usernameMd5 = StringUtils.isNotBlank(USER_NAME)
|
||||
? Md5HashUtil.getMD5MessageDigest(USER_NAME).substring(0, 16)
|
||||
: Md5HashUtil.getMD5MessageDigest(hostName).substring(0, 16);
|
||||
|
||||
cachedId = macAddressMd5 + "_" + usernameMd5;
|
||||
|
||||
} catch (UnknownHostException ex) {
|
||||
LOGGER.log(Level.WARNING, "UNable to determine host name.", ex);
|
||||
LOGGER.log(Level.WARNING, "Unable to determine host name.", ex);
|
||||
}
|
||||
}
|
||||
String macAddressMd5 = StringUtils.isNotBlank(HardwareID.getHardwareIDFromEthernetAddress()) ? Md5HashUtil.getMD5MessageDigest(HardwareID.getHardwareIDFromEthernetAddress()).substring(0, 16) : Md5HashUtil.getMD5MessageDigest(HOST_NAME).substring(0, 16);
|
||||
String usernameMd5 = StringUtils.isNotBlank(USER_NAME) ? Md5HashUtil.getMD5MessageDigest(USER_NAME).substring(0, 16) : Md5HashUtil.getMD5MessageDigest(HOST_NAME).substring(0, 16);
|
||||
String md5 = macAddressMd5 + "_" + usernameMd5;
|
||||
return md5;
|
||||
|
||||
return cachedId;
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ package com.basistech.df.cybertriage.autopsy.ctoptions.ctcloud;
|
||||
|
||||
import com.basistech.df.cybertriage.autopsy.ctoptions.subpanel.CTOptionsSubPanel;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.CTCloudException;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.CtApiDAO;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.CTApiDAO;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenResponse;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseInfo;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseResponse;
|
||||
@ -46,7 +46,7 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
private static final SimpleDateFormat LICENSE_EXPIRES_FORMAT = new SimpleDateFormat("MMMM d, YYYY");
|
||||
private static final SimpleDateFormat MALWARE_SCANS_RESET_FORMAT = new SimpleDateFormat("MMM d, YYYY' at 'h:mma");
|
||||
|
||||
private final CtApiDAO ctApiDAO = CtApiDAO.getInstance();
|
||||
private final CTApiDAO ctApiDAO = CTApiDAO.getInstance();
|
||||
private final CTLicensePersistence ctPersistence = CTLicensePersistence.getInstance();
|
||||
|
||||
private volatile LicenseInfo licenseInfo = null;
|
||||
|
@ -13,7 +13,7 @@
|
||||
************************************************************************** */
|
||||
package com.basistech.df.cybertriage.autopsy.malwarescan;
|
||||
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.CtApiDAO;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.CTApiDAO;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenResponse;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationResult;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseInfo;
|
||||
@ -101,7 +101,7 @@ public class MalwareScanIngestModule implements FileIngestModule {
|
||||
private final BatchProcessor<FileRecord> batchProcessor = new BatchProcessor<FileRecord>(BATCH_SIZE, BATCH_MILLIS_TIMEOUT, this::handleBatch);
|
||||
|
||||
private final CTLicensePersistence ctSettingsPersistence = CTLicensePersistence.getInstance();
|
||||
private final CtApiDAO ctApiDAO = CtApiDAO.getInstance();
|
||||
private final CTApiDAO ctApiDAO = CTApiDAO.getInstance();
|
||||
|
||||
private FileTypeDetector fileTypeDetector;
|
||||
private RunState runState = null;
|
||||
@ -256,7 +256,7 @@ public class MalwareScanIngestModule implements FileIngestModule {
|
||||
}
|
||||
|
||||
// using auth token, get results
|
||||
List<FileReputationResult> repResult = ctApiDAO.getReputationResults(authTokenResponse.getToken(), md5Hashes);
|
||||
List<FileReputationResult> repResult = ctApiDAO.getReputationResults(authTokenResponse, md5Hashes);
|
||||
|
||||
if (repResult != null && !repResult.isEmpty()) {
|
||||
SleuthkitCase.CaseDbTransaction trans = null;
|
||||
|
Loading…
x
Reference in New Issue
Block a user