/* * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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.wso2.carbon.identity.application.common.processors; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.application.common.model.RandomPassword; import org.wso2.carbon.identity.application.common.model.RandomPasswordContainer; import org.wso2.carbon.identity.application.common.cache.RandomPasswordContainerCache; import org.wso2.carbon.identity.application.common.cache.RandomPasswordContainerCacheEntry; import org.wso2.carbon.identity.application.common.cache.RandomPasswordContainerCacheKey; import org.wso2.carbon.identity.application.common.model.Property; import org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants; import org.wso2.carbon.identity.application.common.util.IdentityApplicationManagementUtil; import java.util.ArrayList; import java.util.UUID; /** * Use this class to secure sensitive properties display on html front-end */ public class RandomPasswordProcessor { private static final Log log = LogFactory.getLog(RandomPasswordProcessor.class); private static volatile RandomPasswordProcessor randomPasswordProcessor = null; private RandomPasswordProcessor (){ } public static RandomPasswordProcessor getInstance(){ if(randomPasswordProcessor == null){ synchronized (RandomPassword.class){ if(randomPasswordProcessor == null){ randomPasswordProcessor = new RandomPasswordProcessor(); } } } return randomPasswordProcessor; } /** * Remove original passwords with random passwords when sending password properties to UI front-end * @param properties */ public Property[] removeOriginalPasswords(Property[] properties){ if (ArrayUtils.isEmpty(properties)){ return new Property[0]; } properties = addUniqueIdProperty(properties); String uuid = IdentityApplicationManagementUtil .getPropertyValue(properties, IdentityApplicationConstants.UNIQUE_ID_CONSTANT); String randomPhrase = IdentityApplicationConstants.RANDOM_PHRASE_PREFIX + uuid; RandomPassword[] randomPasswords = replaceOriginalPasswordsWithRandomPasswords( randomPhrase, properties); if (!ArrayUtils.isEmpty(randomPasswords)) { addPasswordContainerToCache(randomPasswords, uuid); } return properties; } /** * Remove random passwords with original passwords when sending password properties to Service Back-end * @param properties */ public Property[] removeRandomPasswords(Property[] properties, boolean withCacheClear) { if (ArrayUtils.isEmpty(properties)) { return new Property[0]; } String uuid = IdentityApplicationManagementUtil.getPropertyValue(properties, IdentityApplicationConstants.UNIQUE_ID_CONSTANT); if (StringUtils.isBlank(uuid)) { if (log.isDebugEnabled()) { log.debug("Cache Key not found for Random Password Container"); } } else { properties = removeUniqueIdProperty(properties); RandomPassword[] randomPasswords = getRandomPasswordContainerFromCache(uuid, withCacheClear); if (!ArrayUtils.isEmpty(randomPasswords)) { replaceRandomPasswordsWithOriginalPasswords(properties, randomPasswords); } } return properties; } private void addPasswordContainerToCache(RandomPassword[] randomPasswords, String uuid) { if(randomPasswords == null){ if (log.isDebugEnabled()) { log.debug("Random passwords not available for Password Container"); } } RandomPasswordContainer randomPasswordContainer = new RandomPasswordContainer(); randomPasswordContainer.setRandomPasswords(randomPasswords); randomPasswordContainer.setUniqueID(uuid); RandomPasswordContainerCacheKey cacheKey = new RandomPasswordContainerCacheKey(uuid); RandomPasswordContainerCacheEntry cacheEntry = new RandomPasswordContainerCacheEntry(randomPasswordContainer); if (log.isDebugEnabled()){ log.debug("Adding Random passwords to Cache with Key: " + uuid); } RandomPasswordContainerCache.getInstance().addToCache(cacheKey, cacheEntry); } private RandomPassword[] getRandomPasswordContainerFromCache(String uuid, boolean withCacheClear) { RandomPasswordContainerCacheKey cacheKey = new RandomPasswordContainerCacheKey(uuid); RandomPasswordContainerCache cache = RandomPasswordContainerCache.getInstance(); RandomPasswordContainerCacheEntry cacheEntry = cache.getValueFromCache(cacheKey); if (cacheEntry == null) { if (log.isDebugEnabled()) { log.debug("Cache entry not found for cache key :" + uuid); } return new RandomPassword[0]; } RandomPasswordContainer randomPasswordContainer = cacheEntry.getRandomPasswordContainer(); if (randomPasswordContainer == null || randomPasswordContainer.getRandomPasswords() == null) { if (log.isDebugEnabled()) { log.debug("Could not find Random Passwords from Random Password Container"); } return new RandomPassword[0]; } if (withCacheClear){ if (log.isDebugEnabled()){ log.debug("Removing Cache Entry with Key: " + uuid); } cache.clearCacheEntry(cacheKey); } return randomPasswordContainer.getRandomPasswords(); } /** * Replace original passwords with provided random phrase * @param randomPhrase * @param properties * @return */ private RandomPassword[] replaceOriginalPasswordsWithRandomPasswords(String randomPhrase, Property[] properties) { ArrayList<RandomPassword> randomPasswordArrayList = new ArrayList<RandomPassword>(); if (properties != null) { for (Property property : properties) { if (property == null || property.getName() == null || property.getValue() == null) { continue; } if (property.getName().contains(IdentityApplicationConstants.PASSWORD)) { if (log.isDebugEnabled()){ log.debug("Found Password Property :" + property.getValue()); } RandomPassword randomPassword = new RandomPassword(); randomPassword.setPropertyName(property.getName()); randomPassword.setPassword(property.getValue()); randomPassword.setRandomPhrase(randomPhrase); randomPasswordArrayList.add(randomPassword); property.setValue(randomPhrase); } } } return randomPasswordArrayList.toArray(new RandomPassword[randomPasswordArrayList.size()]); } /** * Remove random password list with corresponding old original password if value has not been changed * @param properties * @param randomPasswords */ private void replaceRandomPasswordsWithOriginalPasswords(Property[] properties, RandomPassword randomPasswords[]) { if (ArrayUtils.isEmpty(properties) || ArrayUtils.isEmpty(randomPasswords)) { return; } for (Property property : properties) { if (property == null || StringUtils.isBlank(property.getName()) || StringUtils.isBlank(property.getValue())) { continue; } if (property.getName().contains(IdentityApplicationConstants.PASSWORD)) { for (RandomPassword randomPassword : randomPasswords) { if (property.getName().equals(randomPassword.getPropertyName())) { //if password property value equal to random phrase, user didn't change the password hence set // old password if (property.getValue().equals(randomPassword.getRandomPhrase())) { if (log.isDebugEnabled()){ log.debug("User didn't changed password property: " + property.getName() + " hence replace Random Password with Original Password"); } property.setValue(randomPassword.getPassword()); } } } } } } private Property[] addUniqueIdProperty(Property [] properties) { if (ArrayUtils.isEmpty(properties)){ return new Property[0]; } String uuid = UUID.randomUUID().toString(); Property uniqueIdProperty = new Property(); uniqueIdProperty.setName(IdentityApplicationConstants.UNIQUE_ID_CONSTANT); uniqueIdProperty.setValue(uuid); if (log.isDebugEnabled()){ log.debug("Adding uniqueId property: " + uuid); } properties = (Property[]) ArrayUtils.add(properties, uniqueIdProperty); return properties; } private Property[] removeUniqueIdProperty(Property [] properties) { if (ArrayUtils.isEmpty(properties)){ return new Property[0]; } for (int i=0 ; i < properties.length; i++) { if (properties[i] == null){ continue; } if (IdentityApplicationConstants.UNIQUE_ID_CONSTANT.equals(properties[i].getName())) { Property[] propertiesTemp = properties; if (log.isDebugEnabled()){ log.debug("Removing uniqueId property: " + properties[i].getName()); } properties = (Property[])ArrayUtils.removeElement(properties, properties[i]); //Removing uniqueId property from existing properties too propertiesTemp[i] = null; } } return properties; } }