/*
* Password Management Servlets (PWM)
* http://www.pwm-project.org
*
* Copyright (c) 2006-2009 Novell, Inc.
* Copyright (c) 2009-2017 The PWM Project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package password.pwm.config.stored;
import org.jdom2.Document;
import org.jdom2.Element;
import password.pwm.bean.UserIdentity;
import password.pwm.config.PwmSetting;
import password.pwm.config.StoredValue;
import password.pwm.config.value.StringValue;
import password.pwm.config.value.ValueFactory;
import password.pwm.error.PwmException;
import password.pwm.error.PwmUnrecoverableException;
import password.pwm.util.java.JavaHelper;
import password.pwm.util.java.XmlUtil;
import password.pwm.util.logging.PwmLogger;
import password.pwm.util.secure.PwmSecurityKey;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.Map;
public class NGStoredConfigurationFactory {
private static final PwmLogger LOGGER = PwmLogger.forClass(NGStoredConfigurationFactory.class);
//@Override
public NGStoredConfiguration fromXml(final InputStream inputStream) throws PwmUnrecoverableException {
return XmlEngine.fromXmlImpl(inputStream);
}
//@Override
public void toXml(final OutputStream outputStream) {
}
private static class XmlEngine {
static NGStoredConfiguration fromXmlImpl(final InputStream inputStream)
throws PwmUnrecoverableException
{
final Map<StoredConfigReference, StoredValue> values = new LinkedHashMap<>();
final Map<StoredConfigReference, ValueMetaData> metaData = new LinkedHashMap<>();
final Document inputDocument = XmlUtil.parseXml(inputStream);
final Element rootElement = inputDocument.getRootElement();
final PwmSecurityKey pwmSecurityKey = readSecurityKey(rootElement);
final Element settingsElement = rootElement.getChild(StoredConfiguration.XML_ELEMENT_SETTINGS);
for (final Element loopElement : settingsElement.getChildren()) {
if (StoredConfiguration.XML_ELEMENT_PROPERTIES.equals(loopElement.getName())) {
for (final Element propertyElement : loopElement.getChildren(StoredConfiguration.XML_ELEMENT_PROPERTY)) {
readInterestingElement(propertyElement, pwmSecurityKey, values, metaData);
}
} else {
readInterestingElement(loopElement, pwmSecurityKey, values, metaData);
}
}
return new NGStoredConfiguration(values, metaData, readSecurityKey(rootElement));
}
static void readInterestingElement(
final Element loopElement,
final PwmSecurityKey pwmSecurityKey,
final Map<StoredConfigReference, StoredValue> values,
final Map<StoredConfigReference, ValueMetaData> metaData
)
{
final StoredConfigReference reference = referenceForElement(loopElement);
if (reference != null) {
switch (reference.getRecordType()) {
case SETTING:
{
final StoredValue storedValue = readSettingValue(reference, loopElement, pwmSecurityKey);
values.put(reference, storedValue);
}
break;
case PROPERTY:
{
final StoredValue storedValue = readPropertyValue(reference, loopElement);
}
break;
default:
throw new IllegalArgumentException("unimplemented setting recordtype in reader");
}
final ValueMetaData valueMetaData = readValueMetaData(loopElement);
if (valueMetaData != null) {
metaData.put(reference, valueMetaData);
}
}
}
static PwmSecurityKey readSecurityKey(final Element rootElement)
throws PwmUnrecoverableException
{
final String createTime = rootElement.getAttributeValue(StoredConfiguration.XML_ATTRIBUTE_CREATE_TIME);
return new PwmSecurityKey(createTime + "StoredConfiguration");
}
static StoredValue readSettingValue(
final StoredConfigReference storedConfigReference,
final Element settingElement,
final PwmSecurityKey pwmSecurityKey
)
{
final String key = storedConfigReference.getRecordID();
final PwmSetting pwmSetting = PwmSetting.forKey(key);
if (pwmSetting == null) {
LOGGER.debug("ignoring setting for unknown key: " + key);
} else {
LOGGER.trace("parsing setting key=" + key + ", profile=" + storedConfigReference.getProfileID());
if (settingElement.getChild(StoredConfiguration.XML_ELEMENT_DEFAULT) != null) {
try {
return ValueFactory.fromXmlValues(pwmSetting, settingElement, pwmSecurityKey);
} catch (PwmException e) {
LOGGER.error("error parsing configuration setting " + storedConfigReference + ", error: " + e.getMessage());
}
}
}
return null;
}
static StoredValue readPropertyValue(
final StoredConfigReference storedConfigReference,
final Element settingElement
)
{
final String key = storedConfigReference.getRecordID();
final ConfigurationProperty configProperty = ConfigurationProperty.valueOf(key);
if (configProperty == null) {
LOGGER.debug("ignoring property for unknown key: " + key);
} else {
LOGGER.trace("parsing property key=" + key + ", profile=" + storedConfigReference.getProfileID());
if (settingElement.getChild(StoredConfiguration.XML_ELEMENT_DEFAULT) != null) {
return new StringValue(settingElement.getValue());
}
}
return null;
}
static StoredConfigReference referenceForElement(final Element settingElement) {
final String key = settingElement.getAttributeValue(StoredConfiguration.XML_ATTRIBUTE_KEY);
final String profileID = readProfileID(settingElement);
final StoredConfigReference.RecordType recordType;
switch (settingElement.getName()) {
case StoredConfiguration.XML_ELEMENT_SETTING:
recordType = StoredConfigReference.RecordType.SETTING;
break;
case StoredConfiguration.XML_ELEMENT_PROPERTY:
recordType = StoredConfigReference.RecordType.PROPERTY;
break;
case StoredConfiguration.XML_ELEMENT_LOCALEBUNDLE:
recordType = StoredConfigReference.RecordType.LOCALE_BUNDLE;
break;
default:
LOGGER.warn("unrecognized xml element " + settingElement.getName() + " in configuration");
return null;
}
return new StoredConfigReferenceBean(
recordType,
key,
profileID
);
}
static String readProfileID(final Element settingElement) {
final String profileIDStr = settingElement.getAttributeValue(StoredConfiguration.XML_ATTRIBUTE_PROFILE);
return profileIDStr != null && !profileIDStr.isEmpty() ? profileIDStr : null;
}
static ValueMetaData readValueMetaData(final Element element)
{
final String modifyDateStr = element.getAttributeValue(StoredConfiguration.XML_ATTRIBUTE_MODIFY_TIME);
Instant modifyDate = null;
try {
modifyDate = modifyDateStr == null || modifyDateStr.isEmpty()
? null
: JavaHelper.parseIsoToInstant(modifyDateStr);
} catch (Exception e) {
LOGGER.warn("error parsing stored date: " + e.getMessage());
}
final String modifyUser = element.getAttributeValue(StoredConfiguration.XML_ATTRIBUTE_MODIFY_USER);
final String modifyUserProfile = element.getAttributeValue(StoredConfiguration.XML_ATTRIBUTE_MODIFY_USER_PROFILE);
final UserIdentity userIdentity;
userIdentity = modifyUser != null
? new UserIdentity(modifyUser, modifyUserProfile)
: null;
return new ValueMetaData(modifyDate, userIdentity);
}
}
}