/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of the License at the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ package org.apereo.portal.portlets.swapper; import java.security.Principal; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; import javax.portlet.PortletPreferences; import javax.portlet.PortletRequest; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apereo.portal.portlets.Attribute; import org.apereo.portal.security.IPerson; import org.apereo.portal.security.IPersonManager; import org.apereo.portal.url.IPortalRequestUtils; import org.jasig.services.persondir.IPersonAttributeDao; import org.jasig.services.persondir.IPersonAttributes; import org.jasig.services.persondir.support.MultivaluedPersonAttributeUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; import org.springframework.webflow.context.ExternalContext; /** */ public class AttributeSwapperHelperImpl implements IAttributeSwapperHelper { private static final String OVERRIDDEN_ATTRIBUTES = AttributeSwapperHelperImpl.class.getName() + ".OVERRIDDEN_ATTRIBUTES"; protected final Log logger = LogFactory.getLog(this.getClass()); private OverwritingPersonAttributeDao overwritingPersonAttributeDao; private IPersonManager personManager; private IPortalRequestUtils portalRequestUtils; public OverwritingPersonAttributeDao getPersonAttributeDao() { return overwritingPersonAttributeDao; } /** The {@link OverwritingPersonAttributeDao} instance to use to override attributes */ @Required public void setPersonAttributeDao(OverwritingPersonAttributeDao personAttributeDao) { this.overwritingPersonAttributeDao = personAttributeDao; } public IPersonManager getPersonManager() { return personManager; } /** The {@link IPersonManager} to use to access the current IPerson */ @Autowired public void setPersonManager(IPersonManager personManager) { this.personManager = personManager; } public IPortalRequestUtils getPortalRequestUtils() { return portalRequestUtils; } /** Utility class to access the original portal request */ @Autowired public void setPortalRequestUtils(IPortalRequestUtils portalRequestUtils) { this.portalRequestUtils = portalRequestUtils; } /* (non-Javadoc) * @see org.apereo.portal.portlets.swapper.IAttributeSwapperHelper#getSwappableAttributes(org.springframework.webflow.context.ExternalContext) */ public Set<String> getSwappableAttributes(ExternalContext externalContext) { final PortletRequest portletRequest = (PortletRequest) externalContext.getNativeRequest(); final PortletPreferences preferences = portletRequest.getPreferences(); final Set<String> swappableAttributes; //Use prefs configured list if available final String[] configuredAttributes = preferences.getValues(ATTRIBUTE_SWAPPER_ATTRIBUTES_FORM_SWAPPABLE_ATTRIBUTES, null); final String[] excludedAttributes = preferences.getValues( ATTRIBUTE_SWAPPER_ATTRIBUTES_FORM_SWAPPABLE_ATTRIBUTES_EXCLUDES, null); if (configuredAttributes != null) { swappableAttributes = new LinkedHashSet<String>(Arrays.asList(configuredAttributes)); } else { //If no prefs try the 'possibleUserAttributeNames' from the IPersonAttributeDao final Set<String> possibleAttributes = this.overwritingPersonAttributeDao.getPossibleUserAttributeNames(); if (possibleAttributes != null) { swappableAttributes = new TreeSet<String>(possibleAttributes); } //If no possible names try getting the current user's attributes and use the key set else { final Principal currentUser = externalContext.getCurrentUser(); final IPersonAttributes baseUserAttributes = this.getOriginalUserAttributes(currentUser.getName()); if (baseUserAttributes != null) { final Map<String, List<Object>> attributes = baseUserAttributes.getAttributes(); swappableAttributes = new LinkedHashSet<String>(attributes.keySet()); } else { swappableAttributes = Collections.emptySet(); } } } if (excludedAttributes != null) { for (final String excludedAttribute : excludedAttributes) { swappableAttributes.remove(excludedAttribute); } } return swappableAttributes; } /* (non-Javadoc) * @see org.apereo.portal.portlets.swapper.IAttributeSwapperHelper#getOriginalUserAttributes(java.lang.String) */ public IPersonAttributes getOriginalUserAttributes(String uid) { final IPersonAttributeDao delegatePersonAttributeDao = this.overwritingPersonAttributeDao.getDelegatePersonAttributeDao(); return delegatePersonAttributeDao.getPerson(uid); } /* (non-Javadoc) * @see org.apereo.portal.portlets.swapper.IAttributeSwapperHelper#populateSwapRequest(org.springframework.webflow.context.ExternalContext, org.apereo.portal.portlets.swapper.AttributeSwapRequest) */ public void populateSwapRequest( ExternalContext externalContext, AttributeSwapRequest attributeSwapRequest) { final Principal currentUser = externalContext.getCurrentUser(); final String uid = currentUser.getName(); final IPersonAttributes person = this.overwritingPersonAttributeDao.getPerson(uid); final Map<String, Attribute> currentAttributes = attributeSwapRequest.getCurrentAttributes(); currentAttributes.clear(); final Set<String> swappableAttributes = this.getSwappableAttributes(externalContext); for (final String attribute : swappableAttributes) { final Object value = person.getAttributeValue(attribute); if (value != null) { currentAttributes.put(attribute, new Attribute(String.valueOf(value))); } } } /* (non-Javadoc) * @see org.apereo.portal.portlets.swapper.IAttributeSwapperHelper#swapAttributes(org.springframework.webflow.context.ExternalContext, org.apereo.portal.portlets.swapper.AttributeSwapRequest) */ public void swapAttributes( ExternalContext externalContext, AttributeSwapRequest attributeSwapRequest) { //Collate the swap request into a single overrides map final Map<String, Object> attributes = new HashMap<String, Object>(); final Map<String, Attribute> currentAttributes = attributeSwapRequest.getCurrentAttributes(); this.copyAttributes(attributes, currentAttributes); final Map<String, Attribute> attributesToCopy = attributeSwapRequest.getAttributesToCopy(); this.copyAttributes(attributes, attributesToCopy); final Principal currentUser = externalContext.getCurrentUser(); final String uid = currentUser.getName(); final IPersonAttributes originalUserAttributes = this.getOriginalUserAttributes(uid); //Filter out unchanged attributes for (final Iterator<Map.Entry<String, Object>> overrideAttrEntryItr = attributes.entrySet().iterator(); overrideAttrEntryItr.hasNext(); ) { final Entry<String, Object> overrideAttrEntry = overrideAttrEntryItr.next(); final String attribute = overrideAttrEntry.getKey(); final Object originalValue = originalUserAttributes.getAttributeValue(attribute); final Object overrideValue = overrideAttrEntry.getValue(); if (originalValue == overrideValue || (originalValue != null && originalValue.equals(overrideValue))) { overrideAttrEntryItr.remove(); } } final PortletRequest portletRequest = (PortletRequest) externalContext.getNativeRequest(); final PortletPreferences preferences = portletRequest.getPreferences(); final String[] configuredAttributes = preferences.getValues(ATTRIBUTE_SWAPPER_ATTRIBUTES_FORM_SWAPPABLE_ATTRIBUTES, null); final String[] excludedAttributes = preferences.getValues( ATTRIBUTE_SWAPPER_ATTRIBUTES_FORM_SWAPPABLE_ATTRIBUTES_EXCLUDES, null); //Calculate the Set of attributes that are OK to be swapped final Set<String> allowedAttributes = new LinkedHashSet<String>(); if (configuredAttributes != null) { allowedAttributes.addAll(Arrays.asList(configuredAttributes)); } else { allowedAttributes.addAll(attributes.keySet()); } if (excludedAttributes != null) { allowedAttributes.removeAll(Arrays.asList(excludedAttributes)); } //Filter the attributes map for (final Iterator<String> attributeItr = attributes.keySet().iterator(); attributeItr.hasNext(); ) { final String attribute = attributeItr.next(); if (!allowedAttributes.contains(attribute)) { attributeItr.remove(); this.logger.warn( "User '" + uid + "' attempted overriding attribute '" + attribute + "' which is not allowed in the current configuration. The attribute will be ignored."); } } this.logger.warn("User '" + uid + "' setting attribute overrides: " + attributes); //Override attributes retrieved the person directory this.overwritingPersonAttributeDao.setUserAttributeOverride(uid, attributes); //Update the IPerson, setting the overridden attributes final HttpServletRequest portalRequest = this.portalRequestUtils.getPortletHttpRequest(portletRequest); final IPerson person = this.personManager.getPerson(portalRequest); final Map<String, List<Object>> multivaluedAttributes = MultivaluedPersonAttributeUtils.toMultivaluedMap(attributes); person.setAttributes(multivaluedAttributes); person.setAttribute(OVERRIDDEN_ATTRIBUTES, multivaluedAttributes.keySet()); } /* (non-Javadoc) * @see org.apereo.portal.portlets.swapper.IAttributeSwapperHelper#resetAttributes(java.lang.String) */ public void resetAttributes(ExternalContext externalContext) { final Principal currentUser = externalContext.getCurrentUser(); final String uid = currentUser.getName(); this.logger.warn("User '" + uid + "' reseting to default attributes"); //Remove the person directory override this.overwritingPersonAttributeDao.removeUserAttributeOverride(uid); //Remove the IPerson attribute override, bit of a hack as we really just remove all overrides //then re-add all attributes from person directory final PortletRequest portletRequest = (PortletRequest) externalContext.getNativeRequest(); final HttpServletRequest portalRequest = this.portalRequestUtils.getPortletHttpRequest(portletRequest); final IPerson person = this.personManager.getPerson(portalRequest); final Set<String> overriddenAttributes = (Set<String>) person.getAttribute(OVERRIDDEN_ATTRIBUTES); if (overriddenAttributes != null) { person.setAttribute(OVERRIDDEN_ATTRIBUTES, null); for (final String attribute : overriddenAttributes) { person.setAttribute(attribute, null); } } final IPersonAttributes originalUserAttributes = this.getOriginalUserAttributes(uid); final Map<String, List<Object>> attributes = originalUserAttributes.getAttributes(); person.setAttributes(attributes); } protected void copyAttributes( final Map<String, Object> destination, final Map<String, Attribute> source) { for (final Map.Entry<String, Attribute> sourceEntry : source.entrySet()) { final Attribute attribute = sourceEntry.getValue(); if (attribute != null && StringUtils.isNotEmpty(attribute.getValue())) { final String name = sourceEntry.getKey(); destination.put(name, attribute.getValue()); } } } }