/** * 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.privacytrust.privacyprotection.assessment.logic; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.societies.api.identity.IIdentity; import org.societies.api.internal.privacytrust.privacyprotection.model.privacyassessment.AssessmentException; import org.societies.api.internal.privacytrust.privacyprotection.model.privacyassessment.AssessmentResultBundle; import org.societies.api.internal.privacytrust.privacyprotection.model.privacyassessment.AssessmentResultClassName; import org.societies.api.internal.privacytrust.privacyprotection.model.privacyassessment.AssessmentResultIIdentity; import org.societies.api.internal.privacytrust.privacyprotection.model.privacyassessment.DataAccessLogEntry; import org.societies.api.internal.privacytrust.privacyprotection.model.privacyassessment.IAssessment; import org.societies.api.internal.privacytrust.privacyprotection.model.privacyassessment.PrivacyLogFilter; import org.societies.privacytrust.privacyprotection.assessment.log.PrivacyLog; /** * A wrapper around {@link DataTransferAnalyzer} * * Parses the log and tries to find potential privacy breaches that occurred in the past. * This can be used for the a-posteriori assessment. * * Estimates whether a particular data transmission is a potential privacy breach or not. * This can be used for the a-priori assessment. * * @author Mitja Vardjan * */ public class Assessment implements IAssessment { private static Logger LOG = LoggerFactory.getLogger(Assessment.class); private static final String PLATFORM_GROUP_ID_PREFIX = "org.societies."; private PrivacyLog privacyLog; private DataTransferAnalyzer dataTransferAnalyzer; private DataAccessAnalyzer dataAccessAnalyzer; private HashMap<IIdentity, AssessmentResultIIdentity> assessmentById = new HashMap<IIdentity, AssessmentResultIIdentity>(); private HashMap<String, AssessmentResultClassName> assessmentByClass = new HashMap<String, AssessmentResultClassName>(); private HashMap<String, AssessmentResultBundle> assessmentByBundle = new HashMap<String, AssessmentResultBundle>(); private Date resultsStart; private Date resultsEnd; public Assessment() { LOG.info("Constructor"); } // Getters and setters for beans public PrivacyLog getPrivacyLog() { LOG.debug("getPrivacyLog()"); return privacyLog; } public void setPrivacyLog(PrivacyLog privacyLog) { LOG.debug("setPrivacyLog()"); this.privacyLog = privacyLog; } public void init() { LOG.debug("init()"); dataTransferAnalyzer = new DataTransferAnalyzer(privacyLog); dataAccessAnalyzer = new DataAccessAnalyzer(privacyLog.getDataAccess()); assessAllNow(null, null); } @Override public void assessAllNow(Date start, Date end) { LOG.info("assessAllNow({}, {})", start, end); resultsStart = start; resultsEnd = end; start = nonNullStart(start); end = nonNullEnd(end); // For each sender identity: calculate result and update value in assessmentById for (IIdentity sender : privacyLog.getSenderIds()) { try { AssessmentResultIIdentity ass = dataTransferAnalyzer.estimatePrivacyBreach(sender, start, end); LOG.debug("assessAllNow(): updating for identity {}", sender); assessmentById.put(sender, ass); } catch (AssessmentException e) { LOG.warn("assessAllNow(): Skipped sender identity " + sender, e); } } // For each sender class: calculate result and update value in assessmentByClass for (String sender : privacyLog.getSenderClassNames()) { try { AssessmentResultClassName ass = dataTransferAnalyzer.estimatePrivacyBreach(sender, start, end); LOG.debug("assessAllNow(): updating for class {}", sender); assessmentByClass.put(sender, ass); } catch (AssessmentException e) { LOG.warn("assessAllNow(): Skipped sender class " + sender, e); } } // For each sender bundle: calculate result and update value in assessmentByBundle for (String sender : privacyLog.getSenderBundles()) { try { AssessmentResultBundle ass = dataTransferAnalyzer.estimatePrivacyBreachForBundle(sender, start, end); LOG.debug("assessAllNow(): updating for bundle {}", sender); assessmentByBundle.put(sender, ass); } catch (AssessmentException e) { LOG.warn("assessAllNow(): Skipped sender bundle " + sender, e); } } } @Override public HashMap<IIdentity, AssessmentResultIIdentity> getAssessmentAllIds(Date start, Date end) { LOG.info("getAssessmentAllIds({}, {})", start, end); updateResultsIfNeeded(start, end); return assessmentById; } @Override public HashMap<String, AssessmentResultClassName> getAssessmentAllClasses(boolean includePlatform, Date start, Date end) { LOG.info("getAssessmentAllClasses({}, {})", start, end); updateResultsIfNeeded(start, end); if (includePlatform) { return assessmentByClass; } else { return nonPlatformClasses(); } } @Override public HashMap<String, AssessmentResultBundle> getAssessmentAllBundles(boolean includePlatform, Date start, Date end) { LOG.info("getAssessmentAllBundles(" + includePlatform + ", {}, {})", start, end); updateResultsIfNeeded(start, end); if (includePlatform) { return assessmentByBundle; } else { return nonPlatformBundles(); } } private HashMap<String, AssessmentResultBundle> nonPlatformBundles() { HashMap<String, AssessmentResultBundle> nonPlatformEntities = new HashMap<String, AssessmentResultBundle>(); for (String id : assessmentByBundle.keySet()) { if (!isPlatformEntity(id)) { nonPlatformEntities.put(id, assessmentByBundle.get(id)); } } return nonPlatformEntities; } private HashMap<String, AssessmentResultClassName> nonPlatformClasses() { HashMap<String, AssessmentResultClassName> nonPlatformEntities = new HashMap<String, AssessmentResultClassName>(); for (String id : assessmentByClass.keySet()) { if (!isPlatformEntity(id)) { nonPlatformEntities.put(id, assessmentByClass.get(id)); } } return nonPlatformEntities; } private boolean isPlatformEntity(String entity) { // TODO: In far future, maybe replace this check with a more secure and reliable one, e.g. use bundle signatures return entity.startsWith(PLATFORM_GROUP_ID_PREFIX); } @Override public AssessmentResultIIdentity getAssessment(IIdentity sender, Date start, Date end) { LOG.info("getAssessment({})", sender); if (sender == null || sender.getJid() == null) { LOG.warn("getAssessment({}): invalid argument", sender); return null; } updateResultsIfNeeded(start, end); return assessmentById.get(sender); } @Override public AssessmentResultClassName getAssessment(String sender, Date start, Date end) { LOG.info("getAssessment({})", sender); if (sender == null) { LOG.warn("getAssessment({}): invalid argument", sender); return null; } updateResultsIfNeeded(start, end); return assessmentByClass.get(sender); } @Override public AssessmentResultBundle getAssessmentForBundle(String sender, Date start, Date end) { LOG.info("getAssessmentForBundle({})", sender); if (sender == null) { LOG.warn("getAssessmentForBundle({}): invalid argument", sender); return null; } updateResultsIfNeeded(start, end); return assessmentByBundle.get(sender); } @Override public long getNumDataTransmissionEvents(Date start, Date end) { LOG.info("getNumDataTransmissionEvents()"); PrivacyLogFilter filter = new PrivacyLogFilter(); filter.setStart(start); filter.setEnd(end); return privacyLog.search(filter).size(); } @Override public long getNumDataAccessEvents(Date start, Date end) { LOG.info("getNumDataAccessEvents()"); start = nonNullStart(start); end = nonNullEnd(end); List<DataAccessLogEntry> allDataAccessEvents = privacyLog.getDataAccess(); int count = 0; for (DataAccessLogEntry da : allDataAccessEvents) { if (da.getTime().after(start) && da.getTime().before(end)) { ++count; } } return count; } @Override public List<IIdentity> getDataAccessRequestors() { return dataAccessAnalyzer.getDataAccessRequestors(); } @Override public List<String> getDataAccessRequestorClasses() { return dataAccessAnalyzer.getDataAccessRequestorClasses(); } @Override public List<String> getDataAccessRequestorBundles() { return dataAccessAnalyzer.getDataAccessRequestorBundles(); } @Override public int getNumDataAccessEvents(IIdentity requestor, Date start, Date end) { start = nonNullStart(start); end = nonNullEnd(end); return dataAccessAnalyzer.getNumDataAccessEvents(requestor, start, end); } @Override public int getNumDataAccessEvents(String requestorClass, Date start, Date end) { start = nonNullStart(start); end = nonNullEnd(end); return dataAccessAnalyzer.getNumDataAccessEvents(requestorClass, start, end); } @Override public int getNumDataAccessEventsForBundle(String requestorBundle, Date start, Date end) { start = nonNullStart(start); end = nonNullEnd(end); return dataAccessAnalyzer.getNumDataAccessEventsForBundle(requestorBundle, start, end); } @Override public Map<IIdentity, Integer> getNumDataAccessEventsForAllIdentities(Date start, Date end) { start = nonNullStart(start); end = nonNullEnd(end); return dataAccessAnalyzer.getNumDataAccessEventsForAllIdentities(start, end); } @Override public Map<String, Integer> getNumDataAccessEventsForAllClasses(boolean includePlatform, Date start, Date end) { Map<String, Integer> resultAll; start = nonNullStart(start); end = nonNullEnd(end); resultAll = dataAccessAnalyzer.getNumDataAccessEventsForAllClasses(start, end); if (includePlatform) { return resultAll; } else { Map<String, Integer> result = new HashMap<String, Integer>(); for (String id : resultAll.keySet()) { if (!isPlatformEntity(id)) { result.put(id, resultAll.get(id)); } } return result; } } @Override public Map<String, Integer> getNumDataAccessEventsForAllBundles(boolean includePlatform, Date start, Date end) { Map<String, Integer> resultAll; start = nonNullStart(start); end = nonNullEnd(end); resultAll = dataAccessAnalyzer.getNumDataAccessEventsForAllBundles(start, end); if (includePlatform) { return resultAll; } else { Map<String, Integer> result = new HashMap<String, Integer>(); for (String id : resultAll.keySet()) { if (!isPlatformEntity(id)) { result.put(id, resultAll.get(id)); } } return result; } } @Override public List<IIdentity> getDataTransmissionReceivers() { return dataTransferAnalyzer.getDataTransmissionReceivers(); } @Override public int getNumDataTransmissionEvents(IIdentity receiver, Date start, Date end) { start = nonNullStart(start); end = nonNullEnd(end); return dataTransferAnalyzer.getNumDataTransmissionEvents(receiver, start, end); } @Override public Map<IIdentity, Integer> getNumDataTransmissionEventsForAllReceivers(Date start, Date end) { start = nonNullStart(start); end = nonNullEnd(end); return dataTransferAnalyzer.getNumDataTransmissionEventsForAllReceivers(start, end); } private Date nonNullStart(Date d) { if (d == null) { return new Date(0); } else { return d; } } private Date nonNullEnd(Date d) { if (d == null) { return new Date(); } else { return d; } } private boolean areDatesEqual(Date a, Date b) { if (a == null) { return b == null; } else { return a.equals(b); } } private void updateResultsIfNeeded(Date start, Date end) { if (!areDatesEqual(start, resultsStart) || !areDatesEqual(end, resultsEnd)) { LOG.debug("Previous results are for different time interval: from {} to {}. Updating...", resultsStart, resultsEnd); assessAllNow(start, end); } } }