/*
* Copyright (c) 2010-2016 Evolveum
*
* Licensed 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 com.evolveum.midpoint.prism.marshaller;
import javax.xml.namespace.QName;
import com.evolveum.midpoint.prism.ParsingContext;
import com.evolveum.midpoint.prism.xnode.RootXNode;
import org.apache.commons.lang.StringUtils;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.crypto.EncryptionException;
import com.evolveum.midpoint.prism.crypto.Protector;
import com.evolveum.midpoint.prism.xnode.MapXNode;
import com.evolveum.midpoint.prism.xnode.PrimitiveXNode;
import com.evolveum.midpoint.prism.xnode.XNode;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.prism.xml.ns._public.types_3.EncryptedDataType;
import com.evolveum.prism.xml.ns._public.types_3.HashedDataType;
import com.evolveum.prism.xml.ns._public.types_3.ProtectedDataType;
import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType;
public class XNodeProcessorUtil {
// @Deprecated // too slow - moved to PrismBeanInspector where it is cached
// public static <T> String findEnumFieldValue(Class classType, Object bean){
// String name = bean.toString();
// for (Field field: classType.getDeclaredFields()) {
// XmlEnumValue xmlEnumValue = field.getAnnotation(XmlEnumValue.class);
// if (xmlEnumValue != null && field.getName().equals(name)) {
// return xmlEnumValue.value();
// }
// }
// return null;
// }
public static <T> void parseProtectedType(ProtectedDataType<T> protectedType, MapXNode xmap, PrismContext prismContext) throws SchemaException {
parseProtectedType(protectedType, xmap, prismContext, ParsingContext.createDefault());
}
public static <T> void parseProtectedType(ProtectedDataType<T> protectedType, MapXNode xmap, PrismContext prismContext, ParsingContext pc) throws SchemaException {
RootXNode xEncryptedData = xmap.getEntryAsRoot(ProtectedDataType.F_ENCRYPTED_DATA);
if (xEncryptedData != null) {
if (!(xEncryptedData.getSubnode() instanceof MapXNode)) {
throw new SchemaException("Cannot parse encryptedData from "+xEncryptedData);
}
EncryptedDataType encryptedDataType = prismContext.parserFor(xEncryptedData).context(pc).parseRealValue(EncryptedDataType.class);
protectedType.setEncryptedData(encryptedDataType);
} else {
// Check for legacy EncryptedData
RootXNode xLegacyEncryptedData = xmap.getEntryAsRoot(ProtectedDataType.F_XML_ENC_ENCRYPTED_DATA);
if (xLegacyEncryptedData != null) {
if (!(xLegacyEncryptedData.getSubnode() instanceof MapXNode)) {
throw new SchemaException("Cannot parse EncryptedData from "+xEncryptedData);
}
RootXNode xConvertedEncryptedData = (RootXNode) xLegacyEncryptedData.cloneTransformKeys(in -> {
String elementName = StringUtils.uncapitalize(in.getLocalPart());
if (elementName.equals("type")) {
// this is rubbish, we don't need it, we don't want it
return null;
}
return new QName(null, elementName);
});
EncryptedDataType encryptedDataType = prismContext.parserFor(xConvertedEncryptedData).context(pc).parseRealValue(EncryptedDataType.class);
protectedType.setEncryptedData(encryptedDataType);
if (protectedType instanceof ProtectedStringType){
transformEncryptedValue(protectedType, prismContext);
}
}
}
RootXNode xHashedData = xmap.getEntryAsRoot(ProtectedDataType.F_HASHED_DATA);
if (xHashedData != null) {
if (!(xHashedData.getSubnode() instanceof MapXNode)) {
throw new SchemaException("Cannot parse hashedData from "+xHashedData);
}
HashedDataType hashedDataType = prismContext.parserFor(xHashedData).context(pc).parseRealValue(HashedDataType.class);
protectedType.setHashedData(hashedDataType);
}
// protected data empty..check for clear value
if (protectedType.isEmpty()){
XNode xClearValue = xmap.get(ProtectedDataType.F_CLEAR_VALUE);
if (xClearValue == null){
//TODO: try to use common namespace (only to be compatible with previous versions)
//FIXME maybe add some warning, info...
xClearValue = xmap.get(new QName(ProtectedDataType.F_CLEAR_VALUE.getLocalPart()));
}
if (xClearValue == null){
return;
}
if (!(xClearValue instanceof PrimitiveXNode)){
//this is maybe not good..
throw new SchemaException("Cannot parse clear value from " + xClearValue);
}
// TODO: clearValue
T clearValue = (T) ((PrimitiveXNode)xClearValue).getParsedValue(DOMUtil.XSD_STRING, String.class);
protectedType.setClearValue(clearValue);
}
}
private static void transformEncryptedValue(ProtectedDataType protectedType, PrismContext prismContext) throws SchemaException{
Protector protector = prismContext.getDefaultProtector();
if (protector == null) {
return;
}
// AESProtector protector = new AESProtector();
// protector.init();
try {
protector.decrypt(protectedType);
Object clearValue = protectedType.getClearValue();
if (clearValue instanceof String){
String clear = (String) clearValue;
if (clear.startsWith("<value>") && clear.endsWith("</value>")){
clear = clear.replace("<value>","").replace("</value>", "");
clearValue = (String) clear;
}
protectedType.setClearValue(clearValue);
protector.encrypt(protectedType);
}
} catch (EncryptionException ex){
//System.out.println("failed to encrypt..");
throw new IllegalArgumentException("failed to encrypt. " + ex);
}
}
}