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

Copyright © 2012-2015 Basis Technology. Generated on: Wed Apr 6 2016
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.