/*******************************************************************************
* Open Behavioral Health Information Technology Architecture (OBHITA.org)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package gov.samhsa.acs.contexthandler;
import gov.samhsa.acs.common.dto.XacmlRequest;
import gov.samhsa.acs.common.log.AcsLogger;
import gov.samhsa.acs.common.log.AcsLoggerFactory;
import gov.samhsa.acs.contexthandler.exception.NoPolicyFoundException;
import gov.samhsa.acs.contexthandler.exception.PolicyProviderException;
import gov.samhsa.acs.xdsb.common.XdsbDocumentType;
import gov.samhsa.acs.xdsb.registry.wsclient.adapter.XdsbRegistryAdapter;
import gov.samhsa.acs.xdsb.repository.wsclient.adapter.XdsbRepositoryAdapter;
import ihe.iti.xds_b._2007.RetrieveDocumentSetRequest;
import ihe.iti.xds_b._2007.RetrieveDocumentSetResponse;
import ihe.iti.xds_b._2007.RetrieveDocumentSetResponse.DocumentResponse;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import oasis.names.tc.ebxml_regrep.xsd.query._3.AdhocQueryResponse;
import org.herasaf.xacml.core.SyntaxException;
import org.herasaf.xacml.core.policy.Evaluatable;
import org.herasaf.xacml.core.policy.PolicyMarshaller;
/**
* The Class XdsbPolicyProvider.
*/
public class XdsbPolicyProvider implements PolicyProvider {
/** The Constant URN_POLICY_COMBINING_ALGORITHM_PERMIT_OVERRIDES. */
public static final String URN_POLICY_COMBINING_ALGORITHM_PERMIT_OVERRIDES = "urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:permit-overrides";
/** The urn policy combining algorithm. */
String urnPolicyCombiningAlgorithm;
/** The logger. */
private final AcsLogger logger = AcsLoggerFactory
.getLogger(this.getClass());
/** The xdsb registry. */
private XdsbRegistryAdapter xdsbRegistry;
/** The xdsb repository. */
private XdsbRepositoryAdapter xdsbRepository;
/** The policy list filter. */
private XacmlPolicyListFilter policyListFilter;
/**
* Instantiates a new policy decision point impl data xdsb.
*
* @param xdsbRegistry
* the xdsb registry
* @param xdsbRepository
* the xdsb repository
* @param policyListFilter
* the policy list filter
*/
public XdsbPolicyProvider(XdsbRegistryAdapter xdsbRegistry,
XdsbRepositoryAdapter xdsbRepository,
XacmlPolicyListFilter policyListFilter) {
this.xdsbRegistry = xdsbRegistry;
this.xdsbRepository = xdsbRepository;
this.policyListFilter = policyListFilter;
this.urnPolicyCombiningAlgorithm = URN_POLICY_COMBINING_ALGORITHM_PERMIT_OVERRIDES;
}
/**
* Instantiates a new policy decision point impl data xdsb.
*
* @param xdsbRegistry
* the xdsb registry
* @param xdsbRepository
* the xdsb repository
* @param policyListFilter
* the policy list filter
* @param urnPolicyCombiningAlgorithm
* the urn policy combining algorithm
*/
public XdsbPolicyProvider(XdsbRegistryAdapter xdsbRegistry,
XdsbRepositoryAdapter xdsbRepository,
XacmlPolicyListFilter policyListFilter,
String urnPolicyCombiningAlgorithm) {
this.xdsbRegistry = xdsbRegistry;
this.xdsbRepository = xdsbRepository;
this.policyListFilter = policyListFilter;
if (urnPolicyCombiningAlgorithm == null
|| "".equals(urnPolicyCombiningAlgorithm)) {
this.urnPolicyCombiningAlgorithm = URN_POLICY_COMBINING_ALGORITHM_PERMIT_OVERRIDES;
} else {
this.urnPolicyCombiningAlgorithm = urnPolicyCombiningAlgorithm;
}
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.acs.contexthandler.PolicyDecisionPointImplData#getPolicies
* (java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public List<Evaluatable> getPolicies(XacmlRequest xacmlRequest)
throws NoPolicyFoundException, PolicyProviderException {
final String patientUniqueId = xacmlRequest.getPatientUniqueId();
final String recipientSubjectNPI = xacmlRequest
.getRecipientSubjectNPI();
final String intermediarySubjectNPI = xacmlRequest
.getIntermediarySubjectNPI();
final String messageId = xacmlRequest.getMessageId();
List<Evaluatable> policies = new LinkedList<Evaluatable>();
List<String> policiesString = new LinkedList<String>();
try {
// Retrieve policy documents
AdhocQueryResponse response = xdsbRegistry.registryStoredQuery(
patientUniqueId, null, XdsbDocumentType.PRIVACY_CONSENT,
true, messageId);
// Extract doc.request from query response
RetrieveDocumentSetRequest retrieveDocumentSetRequest = xdsbRegistry
.extractXdsbDocumentReferenceListAsRetrieveDocumentSetRequest(response);
// If no policies at all, throw NoPolicyFoundException to be caught
// at PolicyEnforcementPointImpl
StringBuilder noConsentsFoundErrorStringBuilder = new StringBuilder();
noConsentsFoundErrorStringBuilder
.append("No consents found for patient ");
noConsentsFoundErrorStringBuilder.append(patientUniqueId);
noConsentsFoundErrorStringBuilder.append(".");
final String errMsg = noConsentsFoundErrorStringBuilder.toString();
if (retrieveDocumentSetRequest.getDocumentRequest().size() <= 0) {
logger.error(xacmlRequest.getMessageId(), errMsg);
throw new NoPolicyFoundException(errMsg);
}
// Retrieve all policies
RetrieveDocumentSetResponse retrieveDocumentSetResponse = xdsbRepository
.retrieveDocumentSet(retrieveDocumentSetRequest);
// Retrieve deprecated documentUniqueIds
List<String> deprecatedDocumentUniqueIds = this.xdsbRegistry
.findDeprecatedDocumentUniqueIds(patientUniqueId,
patientUniqueId, messageId);
// Add policy documents to a string list (if they are not
// deprecated)
for (DocumentResponse docResponse : retrieveDocumentSetResponse
.getDocumentResponse()) {
if (!deprecatedDocumentUniqueIds.contains(docResponse
.getDocumentUniqueId())) {
String docString = new String(docResponse.getDocument());
docString = docString.replace(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "");
policiesString.add(docString);
}
}
// Filter the policiesString List by recipientSubjectNPI and
// intermediarySubjectNPI to remove the unrelated policies (the
// policies about other providers)
policyListFilter.filterByNPI(policiesString, recipientSubjectNPI,
intermediarySubjectNPI);
// If no policies left in the list (no related policies), throw
// NoPolicyFoundException to be caught at
// PolicyEnforcementPointImpl
if (policiesString.size() <= 0) {
throw new NoPolicyFoundException(
noConsentsFoundErrorStringBuilder.toString());
}
// Wrap policies in a policy set
String policySet = makePolicySet(policiesString);
// Unmarshall policy set as an Evaluatable and add to policy list
Evaluatable policy = unmarshal(new ByteArrayInputStream(
policySet.getBytes()));
policies.add(policy);
} catch (NoPolicyFoundException e) {
// Log the exception, but throw it again to be caught at
// PolicyEnforcementPointImpl
logger.info(messageId, e.getMessage());
throw e;
} catch (Throwable t) {
logger.error(messageId, t.getMessage(), t);
throw new PolicyProviderException(
"Consent files cannot be queried/retrieved from XDS.b");
}
return policies;
}
/**
* Unmarshal.
*
* @param inputStream
* the input stream
* @return the evaluatable
* @throws SyntaxException
* the syntax exception
*/
Evaluatable unmarshal(InputStream inputStream) throws SyntaxException {
return PolicyMarshaller.unmarshal(inputStream);
}
/**
* Gets the policy set header.
*
* @return the policy set header
*/
private String getPolicySetHeader() {
StringBuilder builder = new StringBuilder();
builder.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><PolicySet xmlns=\"urn:oasis:names:tc:xacml:2.0:policy:schema:os\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:2.0:policy:schema:os http://docs.oasis-open.org/xacml/access_control-xacml-2.0-policy-schema-os.xsd\" PolicySetId=\"urn:oasis:names:tc:xacml:2.0:example:policysetid:1\" PolicyCombiningAlgId=\"");
builder.append(this.urnPolicyCombiningAlgorithm);
builder.append("\"><Description/><Target/>");
return builder.toString();
}
/**
* Gets the policy set footer.
*
* @return the policy set footer
*/
private String getPolicySetFooter() {
return "</PolicySet>";
}
/**
* Make policy set.
*
* @param policies
* the policies
* @return the string
*/
private String makePolicySet(List<String> policies) {
StringBuilder builder = new StringBuilder();
builder.append(getPolicySetHeader());
for (String policy : policies) {
builder.append(policy);
}
builder.append(getPolicySetFooter());
return builder.toString();
}
}