/**
* Copyright (c) 2011, SOCIETIES Consortium (WATERFORD INSTITUTE OF TECHNOLOGY (TSSG), HERIOT-WATT UNIVERSITY (HWU), SOLUTA.NET
* (SN), GERMAN AEROSPACE CENTRE (Deutsches Zentrum fuer Luft- und Raumfahrt e.V.) (DLR), Zavod za varnostne tehnologije
* informacijske družbe in elektronsko poslovanje (SETCCE), INSTITUTE OF COMMUNICATION AND COMPUTER SYSTEMS (ICCS), LAKE
* COMMUNICATIONS (LAKE), INTEL PERFORMANCE LEARNING SOLUTIONS LTD (INTEL), PORTUGAL TELECOM INOVAÇÃO, SA (PTIN), IBM Corp.,
* INSTITUT TELECOM (ITSUD), AMITEC DIACHYTI EFYIA PLIROFORIKI KAI EPIKINONIES ETERIA PERIORISMENIS EFTHINIS (AMITEC), TELECOM
* ITALIA S.p.a.(TI), TRIALOG (TRIALOG), Stiftelsen SINTEF (SINTEF), NEC EUROPE LTD (NEC))
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 org.societies.context.broker.impl.security;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.societies.api.comm.xmpp.interfaces.ICommManager;
import org.societies.api.context.broker.CtxAccessControlException;
import org.societies.api.context.model.CtxIdentifier;
import org.societies.api.context.model.CtxIdentifierFactory;
import org.societies.api.context.model.CtxModelObject;
import org.societies.api.identity.IIdentity;
import org.societies.api.identity.Requestor;
import org.societies.api.identity.RequestorCis;
import org.societies.api.identity.RequestorService;
import org.societies.api.identity.util.RequestorUtils;
import org.societies.api.internal.privacytrust.privacyprotection.IPrivacyDataManager;
import org.societies.api.osgi.event.EventTypes;
import org.societies.api.osgi.event.IEventMgr;
import org.societies.api.osgi.event.InternalEvent;
import org.societies.api.privacytrust.privacy.util.privacypolicy.ResourceUtils;
import org.societies.api.privacytrust.trust.evidence.TrustEvidenceType;
import org.societies.api.privacytrust.trust.model.TrustEvidence;
import org.societies.api.privacytrust.trust.model.TrustedEntityId;
import org.societies.api.privacytrust.trust.model.util.TrustedEntityIdFactory;
import org.societies.api.schema.identity.DataIdentifier;
import org.societies.api.schema.privacytrust.privacy.model.privacypolicy.Action;
import org.societies.api.schema.privacytrust.privacy.model.privacypolicy.ActionConstants;
import org.societies.api.schema.privacytrust.privacy.model.privacypolicy.Decision;
import org.societies.api.schema.privacytrust.privacy.model.privacypolicy.ResponseItem;
import org.societies.context.broker.api.security.CtxAccessControllerException;
import org.societies.context.broker.api.security.ICtxAccessController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.osgi.service.ServiceUnavailableException;
import org.springframework.stereotype.Service;
/**
* Implementation of the {@link ICtxAccessController} interface that uses the
* {@link IPrivacyDataManager} for determining whether access requests should
* be allowed or denied.
*
* @author <a href="mailto:nicolas.liampotis@cn.ntua.gr">Nicolas Liampotis</a> (ICCS)
* @since 0.4
*/
@Service
public class CtxAccessController implements ICtxAccessController {
/** The logging facility. */
private static final Logger LOG = LoggerFactory.getLogger(CtxAccessController.class);
/** The Privacy Data Mgr service reference. */
@Autowired(required=false)
private IPrivacyDataManager privacyDataMgr;
/** The Event Mgr service reference. */
@Autowired(required=true)
private IEventMgr eventMgr;
/** The Comms Mgr service reference. */
@Autowired(required=true)
private ICommManager commMgr;
/** The executor service. */
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
CtxAccessController() {
LOG.info("{} instantiated", this.getClass());
}
/*
* @see org.societies.context.broker.api.security.ICtxAccessController#checkPermission(org.societies.api.identity.Requestor, org.societies.api.context.model.CtxIdentifier, org.societies.api.schema.privacytrust.privacy.model.privacypolicy.ActionConstants)
*/
@Override
public void checkPermission(final Requestor requestor,
final CtxIdentifier ctxId, final ActionConstants actionConst)
throws CtxAccessControlException, CtxAccessControllerException {
if (requestor == null) {
throw new NullPointerException("requestor can't be null");
}
if (ctxId == null) {
throw new NullPointerException("ctxId can't be null");
}
if (actionConst == null) {
throw new NullPointerException("actionConst can't be null");
}
LOG.debug("checkPermission: requestor={}, ctxId={}, actionConst={}",
new Object[] { requestor, ctxId, actionConst.name() });
boolean accessDenied = true;
try {
final Action action = new Action();
action.setActionConstant(actionConst);
final List<ResponseItem> responses = this.privacyDataMgr.checkPermission(
RequestorUtils.toRequestorBean(requestor), ctxId, action);
for (final ResponseItem response : responses) {
LOG.debug("response: decision={}", response.getDecision());
if (Decision.PERMIT == response.getDecision()) {
accessDenied = false;
}
}
} catch (ServiceUnavailableException sue) {
throw new CtxAccessControllerException("Failed to perform access control: "
+ "PrivacyDataManager service is not available");
} catch (Exception e) {
throw new CtxAccessControllerException("Failed to perform access control: "
+ e.getLocalizedMessage(), e);
}
if (accessDenied) {
this.executorService.submit(new TrustEvidenceDispatcher(
requestor, ctxId, TrustEvidenceType.WITHHELD_CONTEXT));
throw new CtxAccessControlException("'" + actionConst.name()
+ "' access to '" + ctxId + "' denied for requestor '"
+ requestor + "'");
} else {
this.executorService.submit(new TrustEvidenceDispatcher(
requestor, ctxId, TrustEvidenceType.SHARED_CONTEXT));
}
}
/*
* @see org.societies.context.broker.api.security.ICtxAccessController#checkPermission(org.societies.api.identity.Requestor, java.util.List, org.societies.api.schema.privacytrust.privacy.model.privacypolicy.ActionConstants)
*/
public List<CtxIdentifier> checkPermission(final Requestor requestor,
final List<? extends CtxIdentifier> ctxIdList,
final ActionConstants actionConst) throws
CtxAccessControlException, CtxAccessControllerException {
if (requestor == null) {
throw new NullPointerException("requestor can't be null");
}
if (ctxIdList == null) {
throw new NullPointerException("ctxIdList can't be null");
}
if (actionConst == null) {
throw new NullPointerException("actionConst can't be null");
}
LOG.debug("checkPermission: requestor={}, ctxIdList={}, actionConst={}",
new Object[] { requestor, ctxIdList, actionConst.name() });
final List<CtxIdentifier> result = new ArrayList<CtxIdentifier>(ctxIdList.size());
try {
final Action action = new Action();
action.setActionConstant(actionConst);
final List<DataIdentifier> dataIdList = new ArrayList<DataIdentifier>(ctxIdList.size());
for (final CtxIdentifier ctxId : ctxIdList)
dataIdList.add(ctxId);
final List<ResponseItem> responses = this.privacyDataMgr.checkPermission(
RequestorUtils.toRequestorBean(requestor), dataIdList, action);
for (final ResponseItem response : responses) {
final String ctxIdStr = ResourceUtils.getDataIdUri(
response.getRequestItem().getResource());
final CtxIdentifier ctxId = CtxIdentifierFactory.getInstance().fromString(ctxIdStr);
LOG.debug("response: ctxId={}, decision={}",
ctxId, response.getDecision());
if (Decision.PERMIT == response.getDecision()) {
result.add(ctxId);
this.executorService.submit(new TrustEvidenceDispatcher(
requestor, ctxId, TrustEvidenceType.SHARED_CONTEXT));
} else {
this.executorService.submit(new TrustEvidenceDispatcher(
requestor, ctxId, TrustEvidenceType.WITHHELD_CONTEXT));
}
}
} catch (ServiceUnavailableException sue) {
throw new CtxAccessControllerException("Failed to perform access control: "
+ "PrivacyDataManager service is not available");
} catch (Exception e) {
throw new CtxAccessControllerException("Failed to perform access control: "
+ e.getLocalizedMessage(), e);
}
if (result.isEmpty() && !ctxIdList.isEmpty()) {
throw new CtxAccessControlException("'" + actionConst.name()
+ "' access to '" + ctxIdList + "' denied for requestor '"
+ requestor + "'");
}
LOG.debug("checkPermission: result={}", result);
return result;
}
/*
* @see org.societies.context.broker.api.security.ICtxAccessController#obfuscate(org.societies.api.identity.Requestor, org.societies.api.context.model.CtxModelObject)
*/
@Override
public CtxModelObject obfuscate(final Requestor requestor,
final CtxModelObject ctxModelObject)
throws CtxAccessControllerException {
if (ctxModelObject == null) {
throw new NullPointerException("ctxModelObject can't be null");
}
final List<CtxModelObject> ctxModelObjectList = new ArrayList<CtxModelObject>(1);
ctxModelObjectList.add(ctxModelObject);
return this.obfuscate(requestor, ctxModelObjectList).get(0);
}
/*
* @see org.societies.context.broker.api.security.ICtxAccessController#obfuscate(org.societies.api.identity.Requestor, java.util.List)
*/
@Override
public List<CtxModelObject> obfuscate(final Requestor requestor,
final List<CtxModelObject> ctxModelObjectList)
throws CtxAccessControllerException {
if (requestor == null) {
throw new NullPointerException("requestor can't be null");
}
if (ctxModelObjectList == null) {
throw new NullPointerException("ctxModelObjectList can't be null");
}
LOG.debug("obfuscate: requestor={}, ctxModelObjectList={}",
requestor, ctxModelObjectList);
final List<CtxModelObject> result = new ArrayList<CtxModelObject>(ctxModelObjectList.size());
try {
result.addAll(this.privacyDataMgr.obfuscateData(
RequestorUtils.toRequestorBean(requestor), ctxModelObjectList).get());
// TODO Check with Obfuscation Mgmt
if (result.isEmpty()) {
result.addAll(ctxModelObjectList);
}
} catch (ServiceUnavailableException sue) {
throw new CtxAccessControllerException("Failed to perform obfuscation: "
+ "PrivacyDataManager service is not available");
} catch (Exception e) {
throw new CtxAccessControllerException("Failed to perform obfuscation: "
+ e.getLocalizedMessage(), e);
}
LOG.debug("obfuscate: result={}", result);
return result;
}
private class TrustEvidenceDispatcher implements Runnable {
private final Requestor requestor;
private final CtxIdentifier ctxId;
private final TrustEvidenceType evidenceType;
private TrustEvidenceDispatcher(final Requestor requestor,
final CtxIdentifier ctxId, final TrustEvidenceType evidenceType) {
this.requestor = requestor;
this.ctxId = ctxId;
this.evidenceType = evidenceType;
}
/*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
LOG.debug("TrustEvidenceDispatcher: requestor={}, ctxId={}, evidenceType={}",
new Object[] { this.requestor, this.ctxId, this.evidenceType });
try {
final TrustedEntityId subjectId = this.extractSubjectId(this.ctxId);
final TrustedEntityId objectId = this.extractObjectId(this.requestor);
final Date timestamp = new Date();
final Serializable info = this.ctxId.getType();
final TrustEvidence trustEvidence = new TrustEvidence(
subjectId, objectId, this.evidenceType, timestamp, info, null);
LOG.debug("TrustEvidenceDispatcher: trustEvidence={}", trustEvidence);
eventMgr.publishInternalEvent(new InternalEvent(
EventTypes.TRUST_EVIDENCE_EVENT, // eventType
this.evidenceType.name(), // eventName
CtxAccessController.class.getSimpleName(), // eventType
trustEvidence // eventInfo
));
} catch (Exception e) {
LOG.error("Could not dispatch trust evidence: " + e.getLocalizedMessage(), e);
}
}
private TrustedEntityId extractSubjectId(final CtxIdentifier ctxId) throws Exception {
final IIdentity ownerId = commMgr.getIdManager().fromJid(ctxId.getOwnerId());
return TrustedEntityIdFactory.fromIIdentity(ownerId);
}
private TrustedEntityId extractObjectId(final Requestor requestor) throws Exception {
if (requestor instanceof RequestorService) { // S E R V I C E
return TrustedEntityIdFactory.fromServiceResourceIdentifier(
((RequestorService) requestor).getRequestorServiceId());
} else if (requestor instanceof RequestorCis) { // C O M M U N I T Y
return TrustedEntityIdFactory.fromIIdentity(
((RequestorCis) requestor).getCisRequestorId());
} else { // U S E R
return TrustedEntityIdFactory.fromIIdentity(
requestor.getRequestorId());
}
}
}
}