Autopsy  4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
SolrSearchService.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2015 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.keywordsearch;
20 
21 import java.io.IOException;
22 import java.util.HashMap;
23 import org.apache.solr.client.solrj.SolrServerException;
24 import org.apache.solr.client.solrj.impl.HttpSolrServer;
25 import org.sleuthkit.datamodel.BlackboardArtifact;
26 import org.sleuthkit.datamodel.BlackboardAttribute;
27 import org.sleuthkit.datamodel.TskCoreException;
29 import org.apache.solr.common.util.ContentStreamBase.StringStream;
30 import org.openide.util.lookup.ServiceProvider;
33 import org.sleuthkit.datamodel.AbstractFile;
34 import org.sleuthkit.datamodel.Content;
35 import org.sleuthkit.datamodel.SleuthkitCase;
36 import org.openide.util.NbBundle;
37 import java.net.InetAddress;
38 import java.util.MissingResourceException;
40 
45 @ServiceProvider(service = KeywordSearchService.class)
46 public class SolrSearchService implements KeywordSearchService {
47 
48  private static final String BAD_IP_ADDRESS_FORMAT = "ioexception occurred when talking to server"; //NON-NLS
49  private static final String SERVER_REFUSED_CONNECTION = "server refused connection"; //NON-NLS
50  private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
51 
52  @Override
53  public void indexArtifact(BlackboardArtifact artifact) throws TskCoreException {
54  if (artifact == null) {
55  return;
56  }
57 
58  // We only support artifact indexing for Autopsy versions that use
59  // the negative range for artifact ids.
60  long artifactId = artifact.getArtifactID();
61 
62  if (artifactId > 0) {
63  return;
64  }
65 
66  Case currentCase;
67  try {
68  currentCase = Case.getCurrentCase();
69  } catch (IllegalStateException ignore) {
70  // thorown by Case.getCurrentCase() if currentCase is null
71  return;
72  }
73 
74  SleuthkitCase sleuthkitCase = currentCase.getSleuthkitCase();
75  if (sleuthkitCase == null) {
76  return;
77  }
78 
79  Content dataSource;
80  AbstractFile abstractFile = sleuthkitCase.getAbstractFileById(artifact.getObjectID());
81  if (abstractFile != null) {
82  dataSource = abstractFile.getDataSource();
83  } else {
84  dataSource = sleuthkitCase.getContentById(artifact.getObjectID());
85  }
86 
87  if (dataSource == null) {
88  return;
89  }
90 
91  // Concatenate the string values of all attributes into a single
92  // "content" string to be indexed.
93  StringBuilder artifactContents = new StringBuilder();
94 
95  for (BlackboardAttribute attribute : artifact.getAttributes()) {
96  artifactContents.append(attribute.getAttributeType().getDisplayName());
97  artifactContents.append(" : ");
98 
99  // This is ugly since it will need to updated any time a new
100  // TSK_DATETIME_* attribute is added. A slightly less ugly
101  // alternative would be to assume that all date time attributes
102  // will have a name of the form "TSK_DATETIME*" and check
103  // attribute.getAttributeTypeName().startsWith("TSK_DATETIME*".
104  // The major problem with that approach is that it would require
105  // a round trip to the database to get the type name string.
106  // We have also discussed modifying BlackboardAttribute.getDisplayString()
107  // to magically format datetime attributes but that is complicated by
108  // the fact that BlackboardAttribute exists in Sleuthkit data model
109  // while the utility to determine the timezone to use is in ContentUtils
110  // in the Autopsy datamodel.
111  if (attribute.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID()
112  || attribute.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID()
113  || attribute.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID()
114  || attribute.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED.getTypeID()
115  || attribute.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_RCVD.getTypeID()
116  || attribute.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID()
117  || attribute.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID()
118  || attribute.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID()) {
119 
120  artifactContents.append(ContentUtils.getStringTime(attribute.getValueLong(), dataSource));
121  } else {
122  artifactContents.append(attribute.getDisplayString());
123  }
124  artifactContents.append(System.lineSeparator());
125  }
126 
127  if (artifactContents.length() == 0) {
128  return;
129  }
130 
131  // To play by the rules of the existing text markup implementations,
132  // we need to (a) index the artifact contents in a "chunk" and
133  // (b) create a separate index entry for the base artifact.
134  // We distinguish artifact content from file content by applying a
135  // mask to the artifact id to make its value > 0x8000000000000000 (i.e. negative).
136  // First, create an index entry for the base artifact.
137  HashMap<String, String> solrFields = new HashMap<>();
138  String documentId = Long.toString(artifactId);
139 
140  solrFields.put(Server.Schema.ID.toString(), documentId);
141 
142  // Set the IMAGE_ID field.
143  solrFields.put(Server.Schema.IMAGE_ID.toString(), Long.toString(dataSource.getId()));
144 
145  try {
146  Ingester.getDefault().ingest(new StringStream(""), solrFields, 0);
147  } catch (Ingester.IngesterException ex) {
148  throw new TskCoreException(ex.getCause().getMessage(), ex);
149  }
150 
151  // Next create the index entry for the document content.
152  // The content gets added to a single chunk. We may need to add chunking
153  // support later.
154  long chunkId = 1;
155 
156  documentId += "_" + Long.toString(chunkId);
157  solrFields.replace(Server.Schema.ID.toString(), documentId);
158 
159  StringStream contentStream = new StringStream(artifactContents.toString());
160 
161  try {
162  Ingester.getDefault().ingest(contentStream, solrFields, contentStream.getSize());
163  } catch (Ingester.IngesterException ex) {
164  throw new TskCoreException(ex.getCause().getMessage(), ex);
165  }
166  }
167 
185  @Override
186  public void tryConnect(String host, int port) throws KeywordSearchServiceException {
187  HttpSolrServer solrServer = null;
188  if (host == null || host.isEmpty()) {
189  throw new KeywordSearchServiceException(NbBundle.getMessage(SolrSearchService.class, "SolrConnectionCheck.MissingHostname")); //NON-NLS
190  }
191  try {
192  solrServer = new HttpSolrServer("http://" + host + ":" + Integer.toString(port) + "/solr"); //NON-NLS;
193  KeywordSearch.getServer().connectToSolrServer(solrServer);
194  } catch (SolrServerException ex) {
195  throw new KeywordSearchServiceException(NbBundle.getMessage(SolrSearchService.class, "SolrConnectionCheck.HostnameOrPort")); //NON-NLS
196  } catch (IOException ex) {
197  String result = NbBundle.getMessage(SolrSearchService.class, "SolrConnectionCheck.HostnameOrPort"); //NON-NLS
198  String message = ex.getCause().getMessage().toLowerCase();
199  if (message.startsWith(SERVER_REFUSED_CONNECTION)) {
200  try {
201  if (InetAddress.getByName(host).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
202  // if we can reach the host, then it's probably port problem
203  result = Bundle.SolrConnectionCheck_Port();
204  } else {
205  result = NbBundle.getMessage(SolrSearchService.class, "SolrConnectionCheck.HostnameOrPort"); //NON-NLS
206  }
207  } catch (IOException | MissingResourceException any) {
208  // it may be anything
209  result = NbBundle.getMessage(SolrSearchService.class, "SolrConnectionCheck.HostnameOrPort"); //NON-NLS
210  }
211  } else if (message.startsWith(BAD_IP_ADDRESS_FORMAT)) {
212  result = NbBundle.getMessage(SolrSearchService.class, "SolrConnectionCheck.Hostname"); //NON-NLS
213  }
214  throw new KeywordSearchServiceException(result);
215  } catch (NumberFormatException ex) {
216  throw new KeywordSearchServiceException(Bundle.SolrConnectionCheck_Port());
217  } catch (IllegalArgumentException ex) {
218  throw new KeywordSearchServiceException(ex.getMessage());
219  } finally {
220  if (null != solrServer) {
221  solrServer.shutdown();
222  }
223  }
224  }
225 
226  @Override
227  public void close() throws IOException {
228  }
229 }
static String getStringTime(long epochSeconds, TimeZone tzone)

Copyright © 2012-2016 Basis Technology. Generated on: Tue Oct 25 2016
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.