/**
* 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.android.privacytrust.datamanagement;
import java.util.ArrayList;
import java.util.List;
import org.societies.android.api.identity.util.DataIdentifierFactory;
import org.societies.android.api.internal.privacytrust.IPrivacyDataManager;
import org.societies.android.api.privacytrust.privacy.model.PrivacyException;
import org.societies.android.api.utilities.MissingClientPackageException;
import org.societies.android.privacytrust.api.IDataObfuscator;
import org.societies.android.privacytrust.api.IPrivacyDataManagerInternal;
import org.societies.android.privacytrust.datamanagement.callback.PrivacyDataIntentSender;
import org.societies.android.privacytrust.dataobfuscation.obfuscator.util.ObfuscatorFactory;
import org.societies.api.internal.schema.privacytrust.privacy.model.dataobfuscation.DataWrapper;
import org.societies.api.internal.schema.privacytrust.privacyprotection.privacydatamanagement.MethodType;
import org.societies.api.schema.identity.DataIdentifier;
import org.societies.api.schema.identity.DataIdentifierScheme;
import org.societies.api.schema.identity.RequestorBean;
import org.societies.api.schema.privacytrust.privacy.model.privacypolicy.Action;
import org.societies.api.schema.privacytrust.privacy.model.privacypolicy.ResponseItem;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
/**
* @author Olivier Maridat (Trialog)
*/
public class PrivacyDataManager implements IPrivacyDataManager {
private final static String TAG = PrivacyDataManager.class.getSimpleName();
private Context context;
private IPrivacyDataManagerInternal privacyDataManagerInternal;
private PrivacyDataManagerRemote privacyDataManagerRemote;
private PrivacyDataIntentSender intentSender;
public PrivacyDataManager(Context context) {
this.context = context;
// Init tools
privacyDataManagerInternal = new PrivacyDataManagerInternal();
privacyDataManagerRemote = new PrivacyDataManagerRemote(context);
intentSender = new PrivacyDataIntentSender(context);
}
@Override
public void checkPermission(String clientPackage, RequestorBean requestor, DataIdentifier dataId, List<Action> actions) throws PrivacyException {
List<DataIdentifier> dataIds = new ArrayList<DataIdentifier>();
dataIds.add(dataId);
checkPermission(clientPackage, requestor, dataIds, actions);
}
@Override
public void checkPermission(String clientPackage, RequestorBean requestor, DataIdentifier dataId, Action action) throws PrivacyException {
List<Action> actions = new ArrayList<Action>();
actions.add(action);
checkPermission(clientPackage, requestor, dataId, actions);
}
@Override
public void checkPermission(String clientPackage, RequestorBean requestor, List<DataIdentifier> dataIds, List<Action> actions) throws PrivacyException {
// -- Verify parameters
if (null == clientPackage || "".equals(clientPackage)) {
throw new PrivacyException(new MissingClientPackageException());
}
if (null == requestor) {
Log.e(TAG, "verifyParemeters: Not enought information: requestor is missing");
throw new NullPointerException("Not enought information: requestor is missing");
}
if (null == dataIds) {
Log.e(TAG, "verifyParemeters: Not enought information: data id is missing");
throw new NullPointerException("Not enought information: data id is missing");
}
// -- Launch action
CheckPermissionTask task = new CheckPermissionTask(context, clientPackage);
task.execute(requestor, dataIds, actions);
}
@Override
public void checkPermission(String clientPackage, RequestorBean requestor, List<DataIdentifier> dataIds, Action action) throws PrivacyException {
List<Action> actions = new ArrayList<Action>();
actions.add(action);
checkPermission(clientPackage, requestor, dataIds, actions);
}
private class CheckPermissionTask extends AsyncTask<Object, Object, Boolean> {
private Context context;
private String clientPackage;
private int progress = 0;
public CheckPermissionTask(Context context, String clientPackage) {
this.context = context;
this.clientPackage = clientPackage;
}
@Override
protected void onPreExecute() {
publishProgress(progress, "Loading...");
}
protected Boolean doInBackground(Object... args) {
RequestorBean requestor = (RequestorBean) args[0];
List<DataIdentifier> dataIds = (List<DataIdentifier>) args[1];
List<Action> actions = (List<Action>) args[2];
try {
// -- Retrieve a stored permission
// ResponseItem privacyPermission = privacyDataManagerInternal.getPermission(requestor, dataId, actions);
// if (null != privacyPermission) {
// Log.d(TAG, "Local Permission retrieved");
// // Publish progress
// if (!checkAndPublishProgress((progress = 100), "Local permission retrieved")) {
// return false;
// }
// intentSender.sendIntentCheckPermission(clientPackage, privacyPermission);
// return true;
// }
// -- Permission not available: remote call
Log.d(TAG, "No Local Permission retrieved: remote call");
privacyDataManagerRemote.checkPermission(clientPackage, requestor, dataIds, actions);
// Publish progress
if (!checkAndPublishProgress((progress = progress+30), "Remote access control required: request sent")) {
return false;
}
}
catch (PrivacyException e) {
intentSender.sendIntentError(clientPackage, MethodType.CHECK_PERMISSION.name(), "Unexpected error during access control: "+e.getMessage());
publishProgress((progress = 100), "Unexpected error during access control: "+e.getMessage());
return false;
}
publishProgress((progress = 100), "Access control finished");
return true;
}
/**
* Publish progress and if cancel is required: send cancel intent
* @param progress Progress number
* @param msg Progress message description
* @return true if the process can continue, false if it needs to stop
*/
private boolean checkAndPublishProgress(int progress, String msg) {
publishProgress(progress, msg);
if (isCancelled()) {
intentSender.sendIntentCancel(clientPackage, MethodType.CHECK_PERMISSION.name());
return false;
}
return true;
}
}
@Override
public void obfuscateData(String clientPackage, RequestorBean requestor, DataWrapper dataWrapper) throws PrivacyException {
// -- Verify parameters
if (null == clientPackage || "".equals(clientPackage)) {
throw new PrivacyException(new MissingClientPackageException());
}
if (null == requestor) {
Log.e(TAG, "verifyParemeters: Not enought information: requestor is missing");
throw new NullPointerException("Not enought information: requestor is missing");
}
if (null == dataWrapper) {
Log.e(TAG, "verifyParemeters: Not enought information: data wrapper is missing");
throw new NullPointerException("Not enought information: data wrapper is missing");
}
if (null == dataWrapper.getData()) {
Log.e(TAG, "verifyParemeters: Not enought information: data is missing");
throw new NullPointerException("Not enought information: data is missing");
}
if (null == dataWrapper.getDataType()) {
Log.e(TAG, "verifyParemeters: Not enought information: data type is missing");
throw new NullPointerException("Not enought information: data type is missing");
}
// -- Launch action
ObfuscationTask task = new ObfuscationTask(context, clientPackage);
task.execute(requestor, dataWrapper);
}
private class ObfuscationTask extends AsyncTask<Object, Object, Boolean> {
private Context context;
private String clientPackage;
private int progress = 0;
public ObfuscationTask(Context context, String clientPackage) {
this.context = context;
this.clientPackage = clientPackage;
}
@Override
protected void onPreExecute() {
publishProgress(progress, "Loading...");
}
protected Boolean doInBackground(Object... args) {
RequestorBean requestor = (RequestorBean) args[0];
DataWrapper dataWrapper = (DataWrapper) args[1];
try {
// -- Retrieve the obfuscation level
double obfuscationLevel = privacyDataManagerInternal.getObfuscationLevel(requestor, DataIdentifierFactory.fromType(DataIdentifierScheme.CONTEXT, dataWrapper.getDataType()));
// If no obfuscation is required: return directly the wrapped data
if (-1 == obfuscationLevel || obfuscationLevel >= 1) {
publishProgress(100, "Obfuscation finished");
intentSender.sendIntentDataObfuscation(clientPackage, dataWrapper);
}
// Obfuscation level in [0, 1]
if (obfuscationLevel < 0) {
obfuscationLevel = 0.001;
}
// Publish progress
if (!checkAndPublishProgress((progress = progress+10), "Obfuscation level retrieved")) {
return false;
}
// -- Mapping: retrieve the relevant obfuscator
IDataObfuscator obfuscator = ObfuscatorFactory.getDataObfuscator(dataWrapper);
// Publish progress
if (!checkAndPublishProgress((progress = progress+5), "Obfuscator algorithm identified")) {
return false;
}
// -- Obfuscate
DataWrapper obfuscatedDataWrapper = null;
// - Obfuscation
// Local obfuscation
if (obfuscator.getObfuscatorInfo().isObfuscable()) {
Log.d(TAG, "Local obfuscation");
obfuscatedDataWrapper = obfuscator.obfuscateData(obfuscationLevel);
// Publish progress
if (!checkAndPublishProgress((progress = 100), "Obfuscation done")) {
return false;
}
// Send data
intentSender.sendIntentDataObfuscation(clientPackage, obfuscatedDataWrapper);
}
// Remote obfuscation needed
else {
Log.d(TAG, "Remote obfuscation required");
privacyDataManagerRemote.obfuscateData(clientPackage, requestor, dataWrapper);
// Publish progress
if (!checkAndPublishProgress((progress = progress+30), "Remote obfuscation required: request sent")) {
return false;
}
}
}
catch(PrivacyException e) {
intentSender.sendIntentError(clientPackage, MethodType.OBFUSCATE_DATA.name(), "Unexpected error during obfuscation: "+e.getMessage());
publishProgress(100, "Unexpected error during obfuscation: "+e.getMessage());
return false;
}
catch(Exception e) {
intentSender.sendIntentError(clientPackage, MethodType.OBFUSCATE_DATA.name(), "Unexpected error during obfuscation: "+e.getMessage());
publishProgress(100, "Unexpected error during obfuscation: "+e.getMessage());
return false;
}
publishProgress(100, "Obfuscation finished");
return true;
}
/**
* Publish progress and if cancel is required: send cancel intent
* @param progress Progress number
* @param msg Progress message description
* @return true if the process can continue, false if it needs to stop
*/
private boolean checkAndPublishProgress(int progress, String msg) {
publishProgress(progress, msg);
if (isCancelled()) {
intentSender.sendIntentCancel(clientPackage, MethodType.OBFUSCATE_DATA.name());
return false;
}
return true;
}
}
@Override
public boolean startService() {
privacyDataManagerRemote.bindToComms();
return true;
}
@Override
public boolean stopService() {
privacyDataManagerRemote.unbindFromComms();
return true;
}
// -- Private methods
private boolean containsAction(List<Action> actions, Action action) {
if (null == actions || actions.size() <= 0 || null == action) {
return false;
}
for(Action actionTmp : actions) {
if (actionTmp.equals(action)) {
return true;
}
}
return false;
}
}