/*
* <p><b>License and Copyright: </b>The contents of this file is subject to the
* same open source license as the Fedora Repository System at www.fedora-commons.org
* Copyright © 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 by The Technical University of Denmark.
* All rights reserved.</p>
*/
package dk.defxws.fedoragsearch.server;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.dom.DOMSource;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import dk.defxws.fedoragsearch.server.errors.GenericSearchException;
import org.fcrepo.client.FedoraClient;
import org.fcrepo.common.Constants;
import org.fcrepo.server.access.FedoraAPIA;
import org.fcrepo.server.management.FedoraAPIM;
/**
* This demo implementation of SearchResultFiltering shall reflect the XACML policies
* for the two demo smiley roles SmileyAdmin and SmileyUser
*
* @author gsp@dtic.dtu.dk
* @version
*/
public class SearchResultFilteringDemoImpl implements SearchResultFiltering {
private static final Logger logger =
Logger.getLogger(SearchResultFilteringDemoImpl.class);
private static final Map<String, FedoraClient> fedoraClients = new HashMap<String, FedoraClient>();
public String selectIndexNameForPresearch(
String fgsUserName,
String indexNameParam,
Map<String, Set<String>> fgsUserAttributes,
Config config)
throws java.rmi.RemoteException {
String indexName = indexNameParam;
if (null != fgsUserAttributes) {
Set<String> roles = fgsUserAttributes.get("smileyRole");
if (null != roles && 0 < roles.size()) {
if (roles.contains("SmileyAdministrator")) {
indexName = "SmileyAdminIndex";
} else if (roles.contains("SmileyUser")) {
indexName = "SmileyUserIndex";
} else if (roles.contains("administrator")) {
indexName = "AllObjectsIndex";
}
}
}
return indexName;
}
public String rewriteQueryForInsearch(
String fgsUserName,
String indexName,
String query,
Map<String, Set<String>> fgsUserAttributes,
Config config)
throws java.rmi.RemoteException {
// query rewriting shall correspond to the additional index field(s) in the xslt indexing stylesheet.
String rewrittenQuery = query;
if (null != fgsUserAttributes) {
Set<String> roles = fgsUserAttributes.get("smileyRole");
if (null != roles && 0 < roles.size()) {
if (roles.contains("SmileyAdministrator")) {
rewrittenQuery = "( " + query + " ) AND smiley AND PID:demo*";
} else if (roles.contains("SmileyUser")) {
rewrittenQuery = "( " + query + " ) AND smiley AND PID:demo* NOT PID:\"demo:SmileyStuff\"";
}
}
}
return rewrittenQuery;
}
public StringBuffer filterResultsetForPostsearch(
String fgsUserName,
StringBuffer resultSetXml,
Map<String, Set<String>> fgsUserAttributes,
Config config)
throws java.rmi.RemoteException {
StringBuffer result = resultSetXml;
//foreach hit in resultset, evaluate XACML policies, if not deny (~permit) then include in result
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new GenericSearchException("filterResultsetForPostsearch:\n" + e.toString());
}
StringReader sr = new StringReader(resultSetXml.toString());
Document document = null;
try {
document = builder.parse(new InputSource(sr));
} catch (SAXException e) {
throw new GenericSearchException("filterResultsetForPostsearch:\n" + e.toString());
} catch (IOException e) {
throw new GenericSearchException("filterResultsetForPostsearch:\n" + e.toString());
}
Element gfindObjectsElement = (Element) document.getElementsByTagName("gfindObjects").item(0);
NodeList objects = document.getElementsByTagName("object");
int hitsDenied = 0;
for (int i=0; i<objects.getLength(); i++) {
Element objectElement = (Element) objects.item(i);
NodeList fieldNodes = objectElement.getElementsByTagName("field");
Element fieldElement = null;
String pid = null;
String repositoryName = config.getRepositoryName(null);
for (int j=0; j<fieldNodes.getLength(); j++) {
fieldElement = (Element) fieldNodes.item(j);
if ("PID".equals(fieldElement.getAttribute("name"))) {
pid = fieldElement.getTextContent();
}
if ("repositoryName".equals(fieldElement.getAttribute("name"))) {
repositoryName = fieldElement.getTextContent();
}
}
if (pid!=null) {
// FedoraAPIA apia = getAPIA(repositoryName,
// config.getFedoraSoap(repositoryName),
// fgsUserName,
// fgsUserName,
// config.getTrustStorePath(repositoryName),
// config.getTrustStorePass(repositoryName) );
// try {
// ObjectProfile profile = apia.getObjectProfile(pid, null);
// if (logger.isDebugEnabled())
// logger.debug("filterResultsetForPostsearch pid="+pid+" profile.label="+profile.getObjLabel());
FedoraAPIM apim = getAPIM(repositoryName,
config.getFedoraSoap(repositoryName),
fgsUserName,
fgsUserName,
config.getTrustStorePath(repositoryName),
config.getTrustStorePass(repositoryName) );
String fedoraVersion = config.getFedoraVersion(repositoryName);
String format = Constants.FOXML1_0.uri;
if(fedoraVersion != null && fedoraVersion.startsWith("2.")) {
format = "foxml1.0";
}
try {
byte[] foxmlRecord = apim.export(pid, format, "public");
if (logger.isDebugEnabled())
logger.debug("filterResultsetForPostsearch pid="+pid+" foxmlRecord="+foxmlRecord);
} catch (java.rmi.RemoteException e) {
hitsDenied++;
if (logger.isDebugEnabled())
logger.debug("filterResultsetForPostsearch hitsDenied="+hitsDenied+" pid="+pid+"\nexception="+e.getMessage());
objectElement.setAttribute("hitDeniedNo", Integer.toString(hitsDenied));
}
} else {
hitsDenied++;
if (logger.isDebugEnabled())
logger.debug("filterResultsetForPostsearch hitsDenied="+hitsDenied+" pid="+pid);
}
}
gfindObjectsElement.setAttribute("hitsDenied", Integer.toString(hitsDenied));
String xsltPath = config.getConfigName()+"/index/"+config.getIndexName(null)+"/copyXml";
result = (new GTransformer()).transform(
xsltPath,
new DOMSource(document),
new String[0]);
return result;
}
private static FedoraClient getFedoraClient(
String repositoryName,
String fedoraSoap,
String fedoraUser,
String fedoraPass)
throws GenericSearchException {
try {
String baseURL = getBaseURL(fedoraSoap);
String user = fedoraUser;
String clientId = user + "@" + baseURL;
synchronized (fedoraClients) {
if (fedoraClients.containsKey(clientId)) {
return fedoraClients.get(clientId);
} else {
FedoraClient client = new FedoraClient(baseURL,
user, fedoraPass);
fedoraClients.put(clientId, client);
return client;
}
}
} catch (Exception e) {
throw new GenericSearchException("Error getting FedoraClient"
+ " for repository: " + repositoryName, e);
}
}
private static String getBaseURL(String fedoraSoap)
throws Exception {
final String end = "/services";
String baseURL = fedoraSoap;
if (fedoraSoap.endsWith(end)) {
baseURL = fedoraSoap.substring(0, fedoraSoap.length() - end.length());
} else {
throw new Exception("Unable to determine baseURL from fedoraSoap"
+ " value (expected it to end with '" + end + "'): "
+ fedoraSoap);
}
return baseURL;
}
private static FedoraAPIA getAPIA(
String repositoryName,
String fedoraSoap,
String fedoraUser,
String fedoraPass,
String trustStorePath,
String trustStorePass)
throws GenericSearchException {
if (trustStorePath!=null)
System.setProperty("javax.net.ssl.trustStore", trustStorePath);
if (trustStorePass!=null)
System.setProperty("javax.net.ssl.trustStorePassword", trustStorePass);
FedoraClient client = getFedoraClient(repositoryName, fedoraSoap, fedoraUser, fedoraPass);
try {
return client.getAPIA();
} catch (Exception e) {
throw new GenericSearchException("Error getting API-A stub"
+ " for repository: " + repositoryName, e);
}
}
private static FedoraAPIM getAPIM(
String repositoryName,
String fedoraSoap,
String fedoraUser,
String fedoraPass,
String trustStorePath,
String trustStorePass)
throws GenericSearchException {
if (trustStorePath!=null)
System.setProperty("javax.net.ssl.trustStore", trustStorePath);
if (trustStorePass!=null)
System.setProperty("javax.net.ssl.trustStorePassword", trustStorePass);
FedoraClient client = getFedoraClient(repositoryName, fedoraSoap, fedoraUser, fedoraPass);
try {
return client.getAPIM();
} catch (Exception e) {
throw new GenericSearchException("Error getting API-M stub"
+ " for repository: " + repositoryName, e);
}
}
}