/**
* Copyright (c) 2010-2017 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.prism.xml.ns._public.types_3;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlMixed;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import javax.xml.namespace.QName;
import com.evolveum.midpoint.prism.util.CloneUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.xml.security.exceptions.Base64DecodingException;
import org.apache.xml.security.utils.Base64;
import org.w3c.dom.Element;
import com.evolveum.midpoint.prism.crypto.ProtectedData;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.QNameUtil;
/**
* This class was originally generated. But it was heavily modified by hand.
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ProtectedDataType", propOrder = {
"content"
})
@XmlSeeAlso({
ProtectedByteArrayType.class,
ProtectedStringType.class
})
public abstract class ProtectedDataType<T> implements ProtectedData<T>, Serializable {
public static final QName COMPLEX_TYPE = new QName("http://prism.evolveum.com/xml/ns/public/types-3", "ProtectedDataType");
public final static QName F_ENCRYPTED_DATA = new QName("http://prism.evolveum.com/xml/ns/public/types-3", "encryptedData");
public final static QName F_HASHED_DATA = new QName("http://prism.evolveum.com/xml/ns/public/types-3", "hashedData");
public final static QName F_CLEAR_VALUE = new QName("http://prism.evolveum.com/xml/ns/public/types-3", "clearValue");
public static final String NS_XML_ENC = "http://www.w3.org/2001/04/xmlenc#";
public static final String NS_XML_DSIG = "http://www.w3.org/2000/09/xmldsig#";
public static final QName F_XML_ENC_ENCRYPTED_DATA = new QName(NS_XML_ENC, "EncryptedData");
public static final QName F_XML_ENC_ENCRYPTION_METHOD = new QName(NS_XML_ENC, "EncryptionMethod");
public static final String ATTRIBUTE_XML_ENC_ALGORITHM = "Algorithm";
public static final QName F_XML_ENC_ALGORITHM = new QName(NS_XML_ENC, ATTRIBUTE_XML_ENC_ALGORITHM);
public static final QName F_XML_ENC_CIPHER_DATA = new QName(NS_XML_ENC, "CipherData");
public static final QName F_XML_ENC_CIPHER_VALUE = new QName(NS_XML_ENC, "CipherValue");
public static final QName F_XML_DSIG_KEY_INFO = new QName(NS_XML_DSIG, "KeyInfo");
public static final QName F_XML_DSIG_KEY_NAME = new QName(NS_XML_DSIG, "KeyName");
@XmlTransient
private EncryptedDataType encryptedDataType;
@XmlTransient
private HashedDataType hashedDataType;
@XmlTransient
private T clearValue;
@XmlElementRef(name = "encryptedData", namespace = "http://prism.evolveum.com/xml/ns/public/types-3", type = JAXBElement.class)
@XmlMixed
@XmlAnyElement(lax = true)
protected List<Object> content;
/**
*
* TODO
* May be either encrypted or hashed or provided in the clear (e.g. for debugging).
*
* This type is marked as "mixed" because it may have alternative representation where
* just the plaintext value is presented as the only value.
*
* This is considered to be primitive built-in type for prism objects.
* Gets the value of the content property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the content property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getContent().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link Object }
* {@link String }
* {@link JAXBElement }{@code <}{@link EncryptedDataType }{@code >}
*
*
*/
public List<Object> getContent() {
if (content == null) {
content = new ContentList();
}
return this.content;
}
@Override
public EncryptedDataType getEncryptedDataType() {
return encryptedDataType;
}
@Override
public void setEncryptedData(EncryptedDataType encryptedDataType) {
this.encryptedDataType = encryptedDataType;
}
@Override
public boolean isEncrypted() {
return encryptedDataType != null;
}
@Override
public HashedDataType getHashedDataType() {
return hashedDataType;
}
@Override
public void setHashedData(HashedDataType hashedDataType) {
this.hashedDataType = hashedDataType;
}
@Override
public boolean isHashed() {
return hashedDataType != null;
}
@Override
public T getClearValue() {
return clearValue;
}
@Override
public void setClearValue(T clearValue) {
this.clearValue = clearValue;
}
@Override
public boolean canGetCleartext() {
return clearValue != null || encryptedDataType != null;
}
@Override
public void destroyCleartext() {
// Not perfect. But OK for now.
clearValue = null;
}
private JAXBElement<EncryptedDataType> toJaxbElement(EncryptedDataType encryptedDataType) {
return new JAXBElement<EncryptedDataType>(F_ENCRYPTED_DATA, EncryptedDataType.class, encryptedDataType);
}
private JAXBElement<HashedDataType> toJaxbElement(HashedDataType hashedDataType) {
return new JAXBElement<HashedDataType>(F_ENCRYPTED_DATA, HashedDataType.class, hashedDataType);
}
private void clearContent() {
encryptedDataType = null;
hashedDataType = null;
}
private boolean addContent(Object newObject) {
if (newObject instanceof String){
String s = (String) newObject;
if (StringUtils.isNotBlank(s)) {
clearValue = (T) s;
}
return true;
} else
if (newObject instanceof JAXBElement<?>) {
JAXBElement<?> jaxbElement = (JAXBElement<?>)newObject;
if (QNameUtil.match(F_ENCRYPTED_DATA, jaxbElement.getName())) {
encryptedDataType = (EncryptedDataType) jaxbElement.getValue();
return true;
} else if (QNameUtil.match(F_HASHED_DATA, jaxbElement.getName())) {
hashedDataType = (HashedDataType) jaxbElement.getValue();
return true;
} else {
throw new IllegalArgumentException("Attempt to add unknown JAXB element "+jaxbElement);
}
} else if (newObject instanceof Element) {
Element element = (Element)newObject;
QName elementName = DOMUtil.getQName(element);
if (QNameUtil.match(F_XML_ENC_ENCRYPTED_DATA, elementName)) {
encryptedDataType = convertXmlEncToEncryptedDate(element);
return true;
} else if (QNameUtil.match(F_CLEAR_VALUE, elementName)){
clearValue = (T) element.getTextContent();
return true;
} else {
throw new IllegalArgumentException("Attempt to add unknown DOM element "+elementName);
}
} else {
throw new IllegalArgumentException("Attempt to add unknown object "+newObject+" ("+newObject.getClass()+")");
}
}
private EncryptedDataType convertXmlEncToEncryptedDate(Element eEncryptedData) {
EncryptedDataType encryptedDataType = new EncryptedDataType();
Element eEncryptionMethod = DOMUtil.getChildElement(eEncryptedData, F_XML_ENC_ENCRYPTION_METHOD);
if (eEncryptionMethod != null) {
String algorithm = eEncryptionMethod.getAttribute(ATTRIBUTE_XML_ENC_ALGORITHM);
EncryptionMethodType encryptionMethodType = new EncryptionMethodType();
encryptionMethodType.setAlgorithm(algorithm);
encryptedDataType.setEncryptionMethod(encryptionMethodType);
}
Element eKeyInfo = DOMUtil.getChildElement(eEncryptedData, F_XML_DSIG_KEY_INFO);
if (eKeyInfo != null) {
KeyInfoType keyInfoType = new KeyInfoType();
encryptedDataType.setKeyInfo(keyInfoType);
Element eKeyName = DOMUtil.getChildElement(eKeyInfo, F_XML_DSIG_KEY_NAME);
if (eKeyName != null) {
keyInfoType.setKeyName(eKeyName.getTextContent());
}
}
Element eCipherData = DOMUtil.getChildElement(eEncryptedData, F_XML_ENC_CIPHER_DATA);
if (eCipherData != null) {
CipherDataType cipherDataType = new CipherDataType();
encryptedDataType.setCipherData(cipherDataType);
Element eCipherValue = DOMUtil.getChildElement(eCipherData, F_XML_ENC_CIPHER_VALUE);
if (eCipherValue != null) {
String cipherValue = eCipherValue.getTextContent();
byte[] cipherValueBytes;
try {
cipherValueBytes = Base64.decode(cipherValue);
} catch (Base64DecodingException e) {
throw new IllegalArgumentException("Bad base64 encoding in CipherValue element: "+e.getMessage(),e);
}
cipherDataType.setCipherValue(cipherValueBytes);
}
}
return encryptedDataType;
}
public boolean isEmpty() {
return encryptedDataType == null && hashedDataType == null && clearValue == null;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((clearValue == null) ? 0 : clearValue.hashCode());
result = prime * result + ((encryptedDataType == null) ? 0 : encryptedDataType.hashCode());
result = prime * result + ((hashedDataType == null) ? 0 : hashedDataType.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ProtectedDataType other = (ProtectedDataType) obj;
if (clearValue == null) {
if (other.clearValue != null) {
return false;
}
} else if (!clearValue.equals(other.clearValue)) {
return false;
}
if (encryptedDataType == null) {
if (other.encryptedDataType != null) {
return false;
}
} else if (!encryptedDataType.equals(other.encryptedDataType)) {
return false;
}
if (hashedDataType == null) {
if (other.hashedDataType != null) {
return false;
}
} else if (!hashedDataType.equals(other.hashedDataType)) {
return false;
}
return true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(getClass().getSimpleName());
sb.append("(");
if (encryptedDataType != null) {
sb.append("encrypted=");
sb.append(encryptedDataType);
}
if (hashedDataType != null) {
sb.append("hashed=");
sb.append(hashedDataType);
}
if (clearValue != null) {
sb.append("clearValue=");
sb.append(clearValue);
}
sb.append(")");
return sb.toString();
}
protected void cloneTo(ProtectedDataType<T> cloned) {
cloned.clearValue = CloneUtil.clone(clearValue);
cloned.encryptedDataType = CloneUtil.clone(encryptedDataType);
cloned.hashedDataType = CloneUtil.clone(hashedDataType);
// content is virtual, there is no point in copying it
}
class ContentList implements List<Object>, Serializable {
@Override
public int size() {
if (encryptedDataType != null || hashedDataType != null) {
return 1;
} else {
return 0;
}
}
@Override
public boolean isEmpty() {
return encryptedDataType == null && hashedDataType == null;
}
@Override
public boolean contains(Object o) {
// TODO Auto-generated method stub
return false;
}
@Override
public Iterator<Object> iterator() {
return new Iterator<Object>() {
private int index = 0;
@Override
public boolean hasNext() {
return index == 0;
}
@Override
public Object next() {
if (index == 0) {
index++;
if (encryptedDataType == null) {
return toJaxbElement(hashedDataType);
} else {
return toJaxbElement(encryptedDataType);
}
} else {
return null;
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public Object[] toArray() {
if (encryptedDataType == null && hashedDataType == null) {
return new Object[0];
} else {
Object[] a = new Object[1];
if (encryptedDataType == null) {
a[0] = toJaxbElement(hashedDataType);
} else {
a[0] = toJaxbElement(encryptedDataType);
}
return a;
}
}
@Override
public <T> T[] toArray(T[] a) {
return (T[]) toArray();
}
@Override
public boolean add(Object e) {
return addContent(e);
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection<?> c) {
for (Object e: c) {
if (!contains(e)) {
return false;
}
}
return true;
}
@Override
public boolean addAll(Collection<? extends Object> c) {
boolean changed = false;
for (Object e: c) {
if (add(e)) {
changed = true;
}
}
return changed;
}
@Override
public boolean addAll(int index, Collection<? extends Object> c) {
throw new UnsupportedOperationException("we are too lazy for this");
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
// We would normally throw an exception here. but JAXB is actually using it.
clearContent();
}
@Override
public Object get(int index) {
if (index == 0) {
// what if encryptedDataType is null and clearValue is set? [pm]
if (encryptedDataType == null) {
return toJaxbElement(hashedDataType);
} else {
return toJaxbElement(encryptedDataType);
}
} else {
return null;
}
}
@Override
public Object set(int index, Object element) {
throw new UnsupportedOperationException();
}
@Override
public void add(int index, Object element) {
throw new UnsupportedOperationException();
}
@Override
public Object remove(int index) {
throw new UnsupportedOperationException();
}
@Override
public int indexOf(Object o) {
throw new UnsupportedOperationException("we are too lazy for this");
}
@Override
public int lastIndexOf(Object o) {
throw new UnsupportedOperationException("we are too lazy for this");
}
@Override
public ListIterator<Object> listIterator() {
throw new UnsupportedOperationException("we are too lazy for this");
}
@Override
public ListIterator<Object> listIterator(int index) {
throw new UnsupportedOperationException("we are too lazy for this");
}
@Override
public List<Object> subList(int fromIndex, int toIndex) {
throw new UnsupportedOperationException("we are too lazy for this");
}
}
}