package org.societies.webapp.controller; /** * 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. */ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import javax.validation.Valid; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.societies.api.cis.management.ICis; import org.societies.api.cis.management.ICisManager; import org.societies.api.comm.xmpp.interfaces.ICommManager; import org.societies.api.context.model.CtxAttributeTypes; import org.societies.api.context.model.MalformedCtxIdentifierException; import org.societies.api.identity.IIdentity; import org.societies.api.identity.InvalidFormatException; import org.societies.api.identity.RequestorCis; import org.societies.api.identity.RequestorService; import org.societies.api.internal.privacytrust.privacyprotection.IPrivacyPolicyManager; import org.societies.api.internal.privacytrust.privacyprotection.model.listener.IPrivacyPolicyManagerListener; import org.societies.api.internal.privacytrust.privacyprotection.remote.IPrivacyPolicyManagerRemote; import org.societies.api.internal.servicelifecycle.IServiceDiscovery; import org.societies.api.internal.servicelifecycle.ServiceDiscoveryException; import org.societies.api.internal.servicelifecycle.ServiceModelUtils; import org.societies.api.privacytrust.privacy.model.PrivacyException; import org.societies.api.privacytrust.privacy.model.privacypolicy.Action; import org.societies.api.privacytrust.privacy.model.privacypolicy.Condition; import org.societies.api.privacytrust.privacy.model.privacypolicy.RequestItem; import org.societies.api.privacytrust.privacy.model.privacypolicy.RequestPolicy; import org.societies.api.privacytrust.privacy.model.privacypolicy.Resource; import org.societies.api.privacytrust.privacy.model.privacypolicy.constants.ActionConstants; import org.societies.api.privacytrust.privacy.model.privacypolicy.constants.ConditionConstants; import org.societies.api.privacytrust.privacy.util.privacypolicy.RequestPolicyUtils; import org.societies.api.schema.identity.DataIdentifierScheme; import org.societies.api.schema.servicelifecycle.model.Service; import org.societies.api.schema.servicelifecycle.model.ServiceResourceIdentifier; import org.societies.webapp.models.PrivacyPolicyForm; import org.societies.webapp.models.privacy.PrivacyPolicyCriteriaForm; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; @Controller public class PrivacyPolicyController { private static Logger LOG = LoggerFactory.getLogger(PrivacyPolicyController.class); private static String[] resourceList; private static String[] resourceHumanList; private static String[] resourceSchemeList; /** * OSGI service get auto injected */ @Autowired(required=false) private IPrivacyPolicyManager privacyPolicyManager; @Autowired(required=false) private IPrivacyPolicyManagerRemote privacyPolicyManagerRemote; @Autowired(required=false) private ICommManager commMngrRef; @Autowired(required=false) private ICisManager cisManager; @Autowired(required=false) private IServiceDiscovery serviceDiscovery; @RequestMapping(value = "/privacy-policies.html", method = RequestMethod.GET) public ModelAndView indexAction() { LOG.debug("privacy policy index HTTP GET"); Map<String, Object> model = new HashMap<String, Object>(); model.put("privacyPolicyCriteria", new PrivacyPolicyCriteriaForm()); return new ModelAndView("privacy/privacy-policy/index", model); } @RequestMapping(value = "/privacy-policies.html", method = RequestMethod.POST) public ModelAndView indexAction(@Valid PrivacyPolicyCriteriaForm privacyPolicyCriteria, BindingResult result, Map model) { LOG.debug("privacy policy update HTTP POST"); // -- Verification if (result.hasErrors()) { LOG.warn("BindingResult has errors"); model.put("errormsg", "Privacy policy criteria form error<br />"+result.toString()+"<br />"+result.getFieldErrors().get(0).getObjectName()); return new ModelAndView("error", model); } LOG.info("[indexAction] "+privacyPolicyCriteria.toString()); // -- Retrieve the CIS owner Id boolean allowRemoteCall = true; String ownerId = privacyPolicyCriteria.getOwnerId(); if ("local".equals(privacyPolicyCriteria.getCisLocation())) { allowRemoteCall = true; ownerId = commMngrRef.getIdManager().getThisNetworkNode().getJid(); privacyPolicyCriteria.setOwnerId(ownerId); LOG.info("[indexAction local] "+privacyPolicyCriteria.toString()); } return showCisAction(privacyPolicyCriteria.getOwnerId(), privacyPolicyCriteria.getCisId(), false, allowRemoteCall); } @RequestMapping(value = "/cis-privacy-policy-show.html", method = RequestMethod.GET) public ModelAndView showCisAction(@RequestParam(value="cisOwnerId", required=false) String cisOwnerId, @RequestParam(value="cisId", required=true) String cisId, @RequestParam(value="test", required=false, defaultValue="false") boolean test, @RequestParam(value="allowRemoteCall", required=false, defaultValue="true") boolean allowRemoteCall) { LOG.debug("Show CIS privacy policy: "+cisId+" "+cisOwnerId); StringBuffer infoMsg = new StringBuffer(); StringBuffer errorMsg = new StringBuffer(); // -- Retrieve the privacy policy RequestorCis provider = null; RequestPolicy privacyPolicy = null; IIdentity cisOwnerIdentity = null; ICis cis = null; try { cisOwnerIdentity = commMngrRef.getIdManager().fromJid(cisOwnerId); IIdentity cisIdentity = commMngrRef.getIdManager().fromJid(cisId); provider = new RequestorCis(cisOwnerIdentity, cisIdentity); privacyPolicy = privacyPolicyManager.getPrivacyPolicy(provider); cis = cisManager.getCis(cisId); } catch (PrivacyException e) { LOG.error("Can't retrieve the privacy policy of this CIS", e); } catch (InvalidFormatException e) { LOG.error("Can't retrieve parameters of this CIS", e); } // -- Display the privacy policy // - No privacy policy if (null == privacyPolicy) { LOG.error("The CIS privacy policy of "+provider+" can not be retrieved. It doesn't exist on the local node, or identifiers are incorrect."); // - Try remote call if (allowRemoteCall) { PrivacyPolicyManagerRemoteListener listener = new PrivacyPolicyManagerRemoteListener(); try { if (null == privacyPolicyManagerRemote) { LOG.error("privacyPolicyManagerRemote not ready!"); throw new PrivacyException("privacyPolicyManagerRemote not ready!"); } privacyPolicyManagerRemote.getPrivacyPolicy(provider, cisOwnerIdentity, listener); synchronized(listener) { listener.wait(10000); if (listener.ack) { privacyPolicy = listener.privacyPolicy; } } } catch (PrivacyException e) { LOG.error("Can't retrieve the remote CIS privacy policy", e); errorMsg.append("Can't retrieve the remote CIS privacy policy"); } catch (InterruptedException e) { LOG.error("Timeout: Can't retrieve the remote CIS privacy policy", e); errorMsg.append("Timeout: Can't retrieve the remote CIS privacy policy"); } } if (null == privacyPolicy) { LOG.error("The CIS privacy policy of "+provider+" can not be retrieved. It doesn't exist on local and remote node, or identifiers are incorrect."); errorMsg.append("Can't retrieve the privacy policy of this CIS."); } // - Create an example one for testing purpose if (null == privacyPolicy && test) { LOG.error("Let's create one"); errorMsg.append("\nFor testing purpose: lets create one."); // -- Create a privacy policy List<RequestItem> requests = createTestPrivacyPolicy(); privacyPolicy = new RequestPolicy(provider, requests); } } else { LOG.debug(privacyPolicy.toXMLString()); } LOG.error(errorMsg.toString()); LOG.info(infoMsg.toString()); Map<String, Object> model = new HashMap<String, Object>(); model.put("error", errorMsg.toString()); model.put("info", infoMsg.toString()); model.put("PrivacyPolicy", privacyPolicy); model.put("Cis", cis); model.put("Element", "CIS"); return new ModelAndView("privacy/privacy-policy/show-cis", model); } @RequestMapping(value = "/service-privacy-policy-show.html", method = RequestMethod.GET) public ModelAndView showServiceAction(@RequestParam(value="serviceOwnerId", required=false) String serviceOwnerId, @RequestParam(value="serviceId", required=true) String serviceId, @RequestParam(value="test", required=false, defaultValue="false") boolean test) { LOG.debug("Show 3P service privacy policy: "+serviceId+" "+serviceOwnerId); StringBuffer infoMsg = new StringBuffer(); StringBuffer errorMsg = new StringBuffer(); // -- Retrieve the privacy policy RequestorService provider = null; RequestPolicy privacyPolicy = null; Service service = null; //Service service = ServiceModelUtils.getServiceFromServiceInstance(serviceId, serviceDiscovery); //service.setServiceName(serviceId); try { ServiceResourceIdentifier serviceIdentity = ServiceModelUtils.getServiceId64Decode(serviceId); IIdentity serviceOwnerIdentity = commMngrRef.getIdManager().fromJid(ServiceModelUtils.getJidFromServiceIdentifier(serviceIdentity)); provider = new RequestorService(serviceOwnerIdentity, serviceIdentity); privacyPolicy = privacyPolicyManager.getPrivacyPolicy(provider); Future<Service> serviceFuture = serviceDiscovery.getService(serviceIdentity); service = serviceFuture.get(); } catch (PrivacyException e) { LOG.error("Can't retrieve the privacy policy of this Service", e); errorMsg.append("Can't retrieve the privacy policy of this Service\n"); } catch (InvalidFormatException e) { LOG.error("Can't retrieve parameters of this Service", e); errorMsg.append("Can't retrieve parameters of this Service\n"); } catch (ServiceDiscoveryException e) { LOG.error("Can't retrieve this Service", e); errorMsg.append("Can't retrieve this Service\n"); } catch (InterruptedException e) { LOG.error("Can't retrieve this Service: interruption", e); errorMsg.append("Can't retrieve this Service: interruption\n"); } catch (ExecutionException e) { LOG.error("Can't retrieve this Service: execution", e); errorMsg.append("Can't retrieve this Service: execution\n"); } // -- Display the privacy policy // - No privacy policy if (null == privacyPolicy) { // errorMsg.append("The CIS privacy policy of "+provider+" can not be retrieved. It doesn't exist on this node, or identifiers are incorrect."); LOG.error("The Service privacy policy of "+provider+" can not be retrieved. It doesn't exist on this node, or identifiers are incorrect."); errorMsg.append("Can't retrieve the privacy policy of this Service."); if (test) { LOG.error("Let's create one"); errorMsg.append("\nFor testing purpose: lets create one."); // -- Create a privacy policy List<RequestItem> requests = createTestPrivacyPolicy(); privacyPolicy = new RequestPolicy(provider, requests); } } else { LOG.debug(privacyPolicy.toXMLString()); } LOG.error(errorMsg.toString()); LOG.info(infoMsg.toString()); Map<String, Object> model = new HashMap<String, Object>(); model.put("error", errorMsg.toString()); model.put("info", infoMsg.toString()); model.put("PrivacyPolicy", privacyPolicy); model.put("Service", service); model.put("Element", "service"); return new ModelAndView("privacy/privacy-policy/show-3p-service", model); } private List<RequestItem> createTestPrivacyPolicy() { List<Action> actionsRw = new ArrayList<Action>(); actionsRw.add(new Action(ActionConstants.READ)); actionsRw.add(new Action(ActionConstants.WRITE, true)); List<Action> actionsR = new ArrayList<Action>(); actionsR.add(new Action(ActionConstants.READ)); List<Condition> conditionsMembersOnly = new ArrayList<Condition>(); conditionsMembersOnly.add(new Condition(ConditionConstants.SHARE_WITH_CIS_MEMBERS_ONLY, "1")); conditionsMembersOnly.add(new Condition(ConditionConstants.STORE_IN_SECURE_STORAGE, "1")); List<Condition> conditionsPublic = new ArrayList<Condition>(); conditionsPublic.add(new Condition(ConditionConstants.SHARE_WITH_3RD_PARTIES, "1")); conditionsPublic.add(new Condition(ConditionConstants.STORE_IN_SECURE_STORAGE, "1")); List<Condition> conditionsPrivate = new ArrayList<Condition>(); conditionsPrivate.add(new Condition(ConditionConstants.SHARE_WITH_CIS_OWNER_ONLY, "1")); conditionsPrivate.add(new Condition(ConditionConstants.STORE_IN_SECURE_STORAGE, "1")); conditionsPrivate.add(new Condition(ConditionConstants.MAY_BE_INFERRED, "1")); List<RequestItem> requests = new ArrayList<RequestItem>(); requests.add(new RequestItem(new Resource(DataIdentifierScheme.CONTEXT, CtxAttributeTypes.LOCATION_SYMBOLIC), actionsRw, conditionsMembersOnly)); requests.add(new RequestItem(new Resource(DataIdentifierScheme.CONTEXT, CtxAttributeTypes.BIRTHDAY), actionsR, conditionsPublic)); requests.add(new RequestItem(new Resource(DataIdentifierScheme.CONTEXT, CtxAttributeTypes.LAST_ACTION), actionsR, conditionsPrivate)); requests.add(new RequestItem(new Resource(DataIdentifierScheme.CIS, "cis-member-list"), actionsRw, conditionsMembersOnly)); return requests; } @RequestMapping(value = "/privacy-policy.html", method = RequestMethod.GET) public ModelAndView updateAction() { LOG.debug("privacy policy update HTTP GET"); Map<String, Object> model = new HashMap<String, Object>(); PrivacyPolicyForm privacyPolicyFrom = new PrivacyPolicyForm(); privacyPolicyFrom.createEmptyPrivacyPolicyFrom(); StringBuffer resultMsg = new StringBuffer(); try { generateResourceLists(); model.put("privacyPolicy", privacyPolicyFrom); model.put("ActionList", ActionConstants.values()); model.put("ConditionList", ConditionConstants.values()); model.put("ResourceList", resourceList); model.put("ResourceHumanList", resourceHumanList); model.put("ResourceSchemeList", DataIdentifierScheme.values()); } catch(IllegalArgumentException e) { resultMsg.append("Error during the generation of the privacy policy form: can't retrieve data type (scheme) "+e.getMessage()); LOG.error("Error during the generation of the privacy policy form: can't retrieve data type (scheme)", e); } catch (IllegalAccessException e) { resultMsg.append("Error during the generation of the privacy policy form: error when retrievint data type (scheme) "+e.getMessage()); LOG.error("Error during the generation of the privacy policy form: error when retrievint data type (scheme)", e); } model.put("ResultMsg", resultMsg.toString()); return new ModelAndView("privacy/privacy-policy/update", model); } @SuppressWarnings("unchecked") @RequestMapping(value = "/privacy-policy.html", method = RequestMethod.POST) public ModelAndView updateAction(@Valid PrivacyPolicyForm privacyPolicyFrom, BindingResult result, Map model) { LOG.debug("privacy policy update HTTP POST"); // -- Verification if (result.hasErrors()) { LOG.warn("BindingResult has errors"); model.put("errormsg", "privacy policy form error<br />"+result.toString()+"<br />"+result.getFieldErrors().get(0).getObjectName()); return new ModelAndView("error", model); } LOG.info(privacyPolicyFrom.toString()); // -- Storage RequestPolicy privacyPolicy; StringBuffer resultMsg = new StringBuffer(); if (isDepencyInjectionDone()) { try { privacyPolicy = privacyPolicyFrom.toRequestPolicy(commMngrRef.getIdManager()); LOG.info(privacyPolicy.toXMLString()); // privacyPolicyManager.updatePrivacyPolicy(privacyPolicy); resultMsg.append("\nPrivacy policy successfully created."); resultMsg.append("\n"+privacyPolicyFrom.toString()); } catch (InvalidFormatException e) { resultMsg.append("Error during privacy policy saving: "+e.getLocalizedMessage()); LOG.error("Error during privacy policy saving", e); } catch (MalformedCtxIdentifierException e) { resultMsg.append("Error during privacy policy saving: can't retrieve data type (scheme) "+e.getMessage()); LOG.error("Error during privacy policy saving: can't retrieve data type (scheme)", e); } } else { resultMsg.append("Error with dependency injection"); LOG.error("Error with dependency injection"); } // -- Display the privacy policy try { generateResourceLists(); model.put("privacyPolicy", privacyPolicyFrom); model.put("ActionList", ActionConstants.values()); model.put("ConditionList", ConditionConstants.values()); model.put("ResourceList", resourceList); model.put("ResourceHumanList", resourceHumanList); model.put("ResourceSchemeList", DataIdentifierScheme.values()); } catch(IllegalArgumentException e) { resultMsg.append("Error during the generation of the privacy policy form: can't retrieve data type (scheme) "+e.getMessage()); LOG.error("Error during the generation of the privacy policy form: can't retrieve data type (scheme)", e); } catch (IllegalAccessException e) { resultMsg.append("Error during the generation of the privacy policy form: error when retrievint data type (scheme) "+e.getMessage()); LOG.error("Error during the generation of the privacy policy form: error when retrievint data type (scheme)", e); } model.put("ResultMsg", resultMsg.toString()); return new ModelAndView("privacy/privacy-policy/update", model); } public static void generateResourceLists() throws IllegalArgumentException, IllegalAccessException { Field[] resourceTypeList = CtxAttributeTypes.class.getDeclaredFields(); resourceList = new String[resourceTypeList.length]; resourceHumanList = new String[resourceTypeList.length]; for(int i=0; i<resourceTypeList.length; i++) { resourceList[i] = DataIdentifierScheme.CONTEXT+":///"+((String)resourceTypeList[i].get(null)); resourceHumanList[i] = DataIdentifierScheme.CONTEXT+": "+((String)resourceTypeList[i].get(null)); } DataIdentifierScheme[] schemes = DataIdentifierScheme.values(); resourceSchemeList = new String[schemes.length]; for(int j=0; j<schemes.length; j++) { resourceSchemeList[j] = schemes[j].value(); } } private boolean isDepencyInjectionDone() { return isDepencyInjectionDone(0); } private boolean isDepencyInjectionDone(int level) { if (null == commMngrRef) { LOG.info("[Dependency Injection] Missing ICommManager"); return false; } if (null == commMngrRef.getIdManager()) { LOG.info("[Dependency Injection] Missing IIdentityManager"); return false; } return true; } // -- Dependency Injection public void setPrivacyPolicyManager(IPrivacyPolicyManager privacyPolicyManager) { this.privacyPolicyManager = privacyPolicyManager; LOG.info("[DepencyInjection] IPrivacyPolicyManager injected"); } public void setPrivacyPolicyManagerRemote(IPrivacyPolicyManagerRemote privacyPolicyManagerRemote) { this.privacyPolicyManagerRemote = privacyPolicyManagerRemote; LOG.info("[DepencyInjection] IPrivacyPolicyManagerRemote injected"); } public void setCommMngrRef(ICommManager commMngrRef) { this.commMngrRef = commMngrRef; LOG.info("[DepencyInjection] ICommManager injected"); } public void setCisManager(ICisManager cisManager) { this.cisManager = cisManager; LOG.info("[DepencyInjection] ICisManager injected"); } public void setServiceDiscovery(IServiceDiscovery serviceDiscovery) { this.serviceDiscovery = serviceDiscovery; LOG.info("[DepencyInjection] IServiceDiscovery injected"); } public class PrivacyPolicyManagerRemoteListener implements IPrivacyPolicyManagerListener { public RequestPolicy privacyPolicy; public boolean ack; public String ackMessage; @Override public void onPrivacyPolicyRetrieved(org.societies.api.schema.privacytrust.privacy.model.privacypolicy.RequestPolicy privacyPolicy) { LOG.error("onPrivacyPolicyRetrieved"); ack = true; try { this.privacyPolicy = RequestPolicyUtils.toRequestPolicy(privacyPolicy, commMngrRef.getIdManager()); } catch (InvalidFormatException e) { onOperationAborted("Privacy policy retrieved, but it is ununderstandable", e); } notifyAll(); } @Override public void onPrivacyPolicyRetrieved(RequestPolicy privacyPolicy) { LOG.error("onPrivacyPolicyRetrieved"); ack = true; this.privacyPolicy = privacyPolicy; notifyAll(); } @Override public void onOperationSucceed(String msg) { LOG.error("onOperationSucceed"); ack = true; ackMessage = msg; notifyAll(); } @Override public void onOperationCancelled(String msg) { LOG.error("onOperationCancelled"); ack = false; ackMessage = msg; notifyAll(); } @Override public void onOperationAborted(String msg, Exception e) { LOG.error("onOperationAborted: "+e.getMessage(), e); ack = false; ackMessage = msg; notifyAll(); } } }