From 32d17447a258188b2d534bcb0bf65a659ba7b7d0 Mon Sep 17 00:00:00 2001 From: mcentner Date: Fri, 29 Aug 2008 12:11:34 +0000 Subject: Initial import. git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@1 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- .../egiz/bku/slcommands/impl/xsect/DataObject.java | 1006 ++++++++++++++++++++ 1 file changed, 1006 insertions(+) create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java (limited to 'bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java') diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java new file mode 100644 index 00000000..d25f2526 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java @@ -0,0 +1,1006 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slcommands.impl.xsect; + +import iaik.xml.crypto.dom.DOMCryptoContext; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.SequenceInputStream; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; +import java.nio.charset.Charset; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.crypto.MarshalException; +import javax.xml.crypto.dom.DOMStructure; +import javax.xml.crypto.dsig.CanonicalizationMethod; +import javax.xml.crypto.dsig.DigestMethod; +import javax.xml.crypto.dsig.Reference; +import javax.xml.crypto.dsig.Transform; +import javax.xml.crypto.dsig.XMLObject; +import javax.xml.crypto.dsig.spec.TransformParameterSpec; +import javax.xml.crypto.dsig.spec.XPathFilter2ParameterSpec; +import javax.xml.crypto.dsig.spec.XPathType; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import org.w3c.dom.bootstrap.DOMImplementationRegistry; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSException; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSParser; +import org.w3c.dom.ls.LSSerializer; + +import at.buergerkarte.namespaces.securitylayer._1.Base64XMLLocRefOptRefContentType; +import at.buergerkarte.namespaces.securitylayer._1.DataObjectInfoType; +import at.buergerkarte.namespaces.securitylayer._1.MetaInfoType; +import at.buergerkarte.namespaces.securitylayer._1.TransformsInfoType; +import at.gv.egiz.bku.binding.HttpUtil; +import at.gv.egiz.bku.slexceptions.SLCommandException; +import at.gv.egiz.bku.slexceptions.SLRequestException; +import at.gv.egiz.bku.slexceptions.SLRuntimeException; +import at.gv.egiz.bku.utils.urldereferencer.StreamData; +import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; +import at.gv.egiz.dom.DOMUtils; +import at.gv.egiz.slbinding.impl.XMLContentType; + +/** + * This class represents a DataObject of an XML-Signature + * created by the security layer command CreateXMLSignature. + * + * @author mcentner + */ +public class DataObject { + + /** + * Logging facility. + */ + private static Log log = LogFactory.getLog(DataObject.class); + + /** + * DOM Implementation. + */ + private static final String DOM_LS_3_0 = "LS 3.0"; + + /** + * The array of the default preferred MIME type order. + */ + private static final String[] DEFAULT_PREFFERED_MIME_TYPES = + new String[] { + "application/xhtml+xml", + "text/plain" + }; + + /** + * The DOM implementation used. + */ + private DOMImplementationLS domImplLS; + + /** + * The signature context. + */ + private SignatureContext ctx; + + /** + * The Reference for this DataObject. + */ + private XSECTReference reference; + + /** + * The XMLObject for this DataObject. + */ + private XMLObject xmlObject; + + /** + * The MIME-Type of the digest input. + */ + private String mimeType; + + /** + * An optional description of the digest input. + */ + private String description; + + /** + * Creates a new instance. + * + * @param document the document of the target signature + */ + public DataObject(SignatureContext signatureContext) { + this.ctx = signatureContext; + + DOMImplementationRegistry registry; + try { + registry = DOMImplementationRegistry.newInstance(); + } catch (Exception e) { + log.error("Failed to get DOMImplementationRegistry.", e); + throw new SLRuntimeException("Failed to get DOMImplementationRegistry."); + } + + domImplLS = (DOMImplementationLS) registry.getDOMImplementation(DOM_LS_3_0); + if (domImplLS == null) { + log.error("Failed to get DOMImplementation " + DOM_LS_3_0); + throw new SLRuntimeException("Failed to get DOMImplementation " + DOM_LS_3_0); + } + + } + + /** + * @return the reference + */ + public Reference getReference() { + return reference; + } + + /** + * @return the xmlObject + */ + public XMLObject getXmlObject() { + return xmlObject; + } + + /** + * @return the mimeType + */ + public String getMimeType() { + return mimeType; + } + + /** + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * Configures this DataObject with the information provided within the given + * sl:DataObjectInfo. + * + * @param dataObjectInfo + * the sl:DataObjectInfo + * + * @throws SLCommandException + * if configuring this DataObject with the information provided in + * the sl:DataObjectInfo fails. + * @throws SLRequestException + * if the information provided in the sl:DataObjectInfo + * does not conform to the security layer specification. + * @throws NullPointerException + * if dataObjectInfo is null + */ + public void setDataObjectInfo(DataObjectInfoType dataObjectInfo) throws SLCommandException, SLRequestException { + + Base64XMLLocRefOptRefContentType dataObject = dataObjectInfo.getDataObject(); + String structure = dataObjectInfo.getStructure(); + + // select and unmarshal an appropriate transformation path if provided + // and set the final data meta information + XSECTTransforms transforms = createTransformsAndSetFinalDataMetaInfo(dataObjectInfo.getTransformsInfo()); + + if ("enveloping".equals(structure)) { + + // configure this DataObject as an enveloped DataObject + setEnvelopedDataObject(dataObject, transforms); + + } else if ("detached".equals(structure)) { + + // configure this DataObject as an detached DataObject + setDetachedDataObject(dataObject, transforms); + + } + // other values are not allowed by the schema and are therefore ignored + + } + + /** + * Configures this DataObject as an enveloped DataObject with the information + * provided within the given sl:DataObject. + * + * @param dataObject + * the sl:DataObject + * @param transforms + * an optional Transforms element (may be + * null) + * + * @throws SLCommandException + * if configuring this DataObject with the information provided in + * the sl:DataObject fails. + * @throws SLRequestException + * if the information provided in the sl:DataObject + * does not conform to the security layer specification. + * @throws NullPointerException + * if dataObject is null + */ + private void setEnvelopedDataObject( + Base64XMLLocRefOptRefContentType dataObject, XSECTTransforms transforms) + throws SLCommandException, SLRequestException { + + String reference = dataObject.getReference(); + if (reference == null) { + // + // case A + // + // The Reference attribute is not used; the content of sl:DataObject represents the data object. + // If the data object is XML-coded (the sl:XMLContent element is used in sl:DataObject), then it + // must be incorporated in the signature structure as parsed XML. + // + + if (dataObject.getBase64Content() != null) { + + log.debug("Adding DataObject (Base64Content) without a reference URI."); + + // create XMLObject + XMLObject xmlObject = createXMLObject(new ByteArrayInputStream(dataObject.getBase64Content())); + + setXMLObjectAndReferenceBase64(xmlObject, transforms); + + } else if (dataObject.getXMLContent() != null) { + + log.debug("Adding DataObject (XMLContent) without a reference URI."); + + // create XMLObject + DocumentFragment content = parseDataObject((XMLContentType) dataObject.getXMLContent()); + XMLObject xmlObject = createXMLObject(content); + + setXMLObjectAndReferenceXML(xmlObject, transforms); + + } else if (dataObject.getLocRefContent() != null) { + + log.debug("Adding DataObject (LocRefContent) without a reference URI."); + + setEnvelopedDataObject(dataObject.getLocRefContent(), transforms); + + } else { + + // not allowed + log.info("XML structure of the command request contains an " + + "invalid combination of optional elements or attributes. " + + "DataObject of structure='enveloped' without a reference must contain content."); + throw new SLRequestException(3003); + + } + + } else { + + if (dataObject.getBase64Content() == null && + dataObject.getXMLContent() == null && + dataObject.getLocRefContent() == null) { + + // + // case B + // + // The Reference attribute contains a URI that must be resolved by the + // Citizen Card Environment to obtain the data object. + // The content of sl:DataObject remains empty + // + + log.debug("Adding DataObject from reference URI '" + reference + "'."); + + setEnvelopedDataObject(reference, transforms); + + } else { + + // not allowed + log.info("XML structure of the command request contains an " + + "invalid combination of optional elements or attributes. " + + "DataObject of structure='enveloped' with reference must not contain content."); + throw new SLRequestException(3003); + + } + + + } + + } + + /** + * Configures this DataObject as an enveloped DataObject with the content to + * be dereferenced from the given reference. + * + * @param reference + * the reference URI + * @param transforms + * an optional Transforms element (may be + * null) + * + * @throws SLCommandException + * if dereferencing the given reference fails, or if + * configuring this DataObject with the data dereferenced from the + * given reference fails. + * @throws NullPointerException + * if reference is null + */ + private void setEnvelopedDataObject(String reference, XSECTTransforms transforms) throws SLCommandException { + + if (reference == null) { + throw new NullPointerException("Argument 'reference' must not be null."); + } + + // dereference URL + URLDereferencer dereferencer = URLDereferencer.getInstance(); + + StreamData streamData; + try { + streamData = dereferencer.dereference(reference, ctx.getDereferencerContext()); + } catch (IOException e) { + log.info("Failed to dereference XMLObject from '" + reference + "'.", e); + throw new SLCommandException(4110); + } + + Node childNode; + + String contentType = streamData.getContentType(); + if (contentType.startsWith("text/xml")) { + + // If content type is text/xml parse content. + String charset = HttpUtil.getCharset(contentType, true); + + Document doc = parseDataObject(streamData.getStream(), charset); + + childNode = doc.getDocumentElement(); + + if (childNode == null) { + log.info("Failed to parse XMLObject from '" + reference + "'."); + throw new SLCommandException(4111); + } + + XMLObject xmlObject = createXMLObject(childNode); + + setXMLObjectAndReferenceXML(xmlObject, transforms); + + } else { + + // Include content Base64 encoded. + XMLObject xmlObject = createXMLObject(streamData.getStream()); + + setXMLObjectAndReferenceBase64(xmlObject, transforms); + + } + + } + + /** + * Configures this DataObject as an detached DataObject with the information + * provided in the given sl:DataObject and optionally + * transforms. + * + * @param dataObject + * the sl:DataObject + * @param transforms + * an optional Transforms object, may be null + * + * @throws SLCommandException + * if configuring this DataObject with the information provided in + * the sl:DataObject fails. + * @throws SLRequestException + * if the information provided in the sl:DataObject + * does not conform to the security layer specification. + * @throws NullPointerException + * if dataObject is null + */ + private void setDetachedDataObject( + Base64XMLLocRefOptRefContentType dataObject, XSECTTransforms transforms) + throws SLCommandException, SLRequestException { + + String referenceURI = dataObject.getReference(); + + if (referenceURI == null) { + + // not allowed + log.info("XML structure of the command request contains an " + + "invalid combination of optional elements or attributes. " + + "DataObject of structure='detached' must contain a reference."); + throw new SLRequestException(3003); + + } else { + + DigestMethod dm; + try { + dm = ctx.getAlgorithmMethodFactory().createDigestMethod(ctx); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get DigestMethod.", e); + throw new SLCommandException(4006); + } catch (InvalidAlgorithmParameterException e) { + log.error("Failed to get DigestMethod.", e); + throw new SLCommandException(4006); + } + + String idValue = ctx.getIdValueFactory().createIdValue("Reference"); + + reference = new XSECTReference(referenceURI, dm, transforms, null, idValue); + + // case D: + // + // The Reference attribute contains a URI that is used by the Citizen Card + // Environment to code the reference to the data object as part of the XML + // signature (attribute URI in the dsig:Reference) element. The content of + // sl:DataObject represents the data object. + + if (dataObject.getLocRefContent() != null) { + String locRef = dataObject.getLocRefContent(); + try { + this.reference.setDereferencer(new LocRefDereferencer(ctx.getDereferencerContext(), locRef)); + } catch (URISyntaxException e) { + log.info("Invalid URI '" + locRef + "' in DataObject.", e); + throw new SLCommandException(4003); + } catch (IllegalArgumentException e) { + log.info("LocRef URI of '" + locRef + "' not supported in DataObject. ", e); + throw new SLCommandException(4003); + } + } else if (dataObject.getBase64Content() != null) { + byte[] base64Content = dataObject.getBase64Content(); + this.reference.setDereferencer(new ByteArrayDereferencer(base64Content)); + } else if (dataObject.getXMLContent() != null) { + XMLContentType xmlContent = (XMLContentType) dataObject.getXMLContent(); + byte[] bytes = xmlContent.getRedirectedStream().toByteArray(); + this.reference.setDereferencer(new ByteArrayDereferencer(bytes)); + } else { + + // case C: + // + // The Reference attribute contains a URI that must be resolved by the + // Citizen Card Environment to obtain the data object. The Reference + // attribute contains a URI that is used by the Citizen Card Environment + // to code the reference to the data object as part of the XML signature + // (attribute URI in the dsig:Reference) element. The content of + // sl:DataObject remains empty. + + } + + } + } + + /** + * Returns the preferred sl:TransformInfo from the given list of + * transformInfos, or null if none of the given + * transformInfos is preferred over the others. + * + * @param transformsInfos + * a list of sl:TransformInfos + * + * @return the selected sl:TransformInfo or null, if + * none is preferred over the others + */ + private TransformsInfoType selectPreferredTransformsInfo(List transformsInfos) { + + Map mimeTypes = new HashMap(); + + StringBuilder debugString = null; + if (log.isDebugEnabled()) { + debugString = new StringBuilder(); + debugString.append("Got " + transformsInfos.size() + " TransformsInfo(s):"); + } + + for (TransformsInfoType transformsInfoType : transformsInfos) { + MetaInfoType finalDataMetaInfo = transformsInfoType.getFinalDataMetaInfo(); + String mimeType = finalDataMetaInfo.getMimeType(); + String description = finalDataMetaInfo.getDescription(); + mimeTypes.put(mimeType, transformsInfoType); + if (debugString != null) { + debugString.append("\n FinalDataMetaInfo: MIME-Type="); + debugString.append(mimeType); + if (description != null) { + debugString.append(" "); + debugString.append(description); + } + } + } + + if (debugString != null) { + log.debug(debugString); + } + + // look for preferred transform + for (String mimeType : DEFAULT_PREFFERED_MIME_TYPES) { + if (mimeTypes.containsKey(mimeType)) { + return mimeTypes.get(mimeType); + } + } + + // no preferred transform + return null; + + } + + /** + * Create an instance of ds:Transforms from the given + * sl:TransformsInfo. + * + * @param transformsInfo + * the sl:TransformsInfo + * + * @return a corresponding unmarshalled ds:Transforms, or + * null if the given sl:TransformsInfo does + * not contain a dsig:Transforms element + * + * @throws SLRequestException + * if the ds:Transforms in the given + * transformsInfo are not valid or cannot be parsed. + * + * @throws MarshalException + * if the ds:Transforms in the given + * transformsInfo cannot be unmarshalled. + */ + private XSECTTransforms createTransforms(TransformsInfoType transformsInfo) throws SLRequestException, MarshalException { + + ByteArrayOutputStream redirectedStream = ((at.gv.egiz.slbinding.impl.TransformsInfoType) transformsInfo).getRedirectedStream(); + byte[] transformBytes = (redirectedStream != null) ? redirectedStream.toByteArray() : null; + + if (transformBytes != null && transformBytes.length > 0) { + + // debug + if (log.isTraceEnabled()) { + StringBuilder sb = new StringBuilder(); + sb.append("Trying to parse transforms:\n"); + sb.append(new String(transformBytes, Charset.forName("UTF-8"))); + log.trace(sb); + } + + DOMImplementationLS domImplLS = DOMUtils.getDOMImplementationLS(); + LSInput input = domImplLS.createLSInput(); + input.setByteStream(new ByteArrayInputStream(transformBytes)); + + LSParser parser = domImplLS.createLSParser( + DOMImplementationLS.MODE_SYNCHRONOUS, null); + DOMConfiguration domConfig = parser.getDomConfig(); + SimpleDOMErrorHandler errorHandler = new SimpleDOMErrorHandler(); + domConfig.setParameter("error-handler", errorHandler); + domConfig.setParameter("validate", Boolean.FALSE); + + Document document; + try { + document = parser.parse(input); + } catch (DOMException e) { + log.info("Failed to parse dsig:Transforms.", e); + throw new SLRequestException(3002); + } catch (LSException e) { + log.info("Failed to parse dsig:Transforms.", e); + throw new SLRequestException(3002); + } + + // adopt ds:Transforms + Element documentElement = document.getDocumentElement(); + Node adoptedTransforms = ctx.getDocument().adoptNode(documentElement); + + DOMCryptoContext context = new DOMCryptoContext(); + + // unmarshall ds:Transforms + return new XSECTTransforms(context, adoptedTransforms); + + } else { + return null; + } + + } + + /** + * Sets the mimeType and the description value + * for this DataObject. + * + * @param metaInfoType the sl:FinalMetaDataInfo + * + * @throws NullPointerException if metaInfoType is null + */ + private void setFinalDataMetaInfo(MetaInfoType metaInfoType) { + + this.mimeType = metaInfoType.getMimeType(); + this.description = metaInfoType.getDescription(); + + } + + /** + * Selects an appropriate transformation path (if present) from the given list + * of sl:TransformInfos, sets the corresponding final data meta info and + * returns the corresponding unmarshalled ds:Transforms. + * + * @param transformsInfos the sl:TransformInfos + * + * @return the unmarshalled ds:Transforms, or null if + * no transformation path has been selected. + * + * @throws SLRequestException if the given list ds:TransformsInfo contains + * an invalid ds:Transforms element, or no suitable transformation path + * can be found. + */ + private XSECTTransforms createTransformsAndSetFinalDataMetaInfo( + List transformsInfos) throws SLRequestException { + + TransformsInfoType preferredTransformsInfo = selectPreferredTransformsInfo(transformsInfos); + // try preferred transform + if (preferredTransformsInfo != null) { + + try { + XSECTTransforms transforms = createTransforms(preferredTransformsInfo); + setFinalDataMetaInfo(preferredTransformsInfo.getFinalDataMetaInfo()); + return transforms; + } catch (MarshalException e) { + + String mimeType = preferredTransformsInfo.getFinalDataMetaInfo().getMimeType(); + log.info("Failed to unmarshal preferred transformation path (MIME-Type=" + + mimeType + ").", e); + + } + + } + + // look for another suitable transformation path + for (TransformsInfoType transformsInfoType : transformsInfos) { + + try { + XSECTTransforms transforms = createTransforms(transformsInfoType); + setFinalDataMetaInfo(transformsInfoType.getFinalDataMetaInfo()); + return transforms; + } catch (MarshalException e) { + + String mimeType = transformsInfoType.getFinalDataMetaInfo().getMimeType(); + log.info("Failed to unmarshal transformation path (MIME-Type=" + + mimeType + ").", e); + } + + } + + // no suitable transformation path found + throw new SLRequestException(3003); + + } + + /** + * Create an XMLObject with the Base64 encoding of the given + * content. + * + * @param content + * the to-be Base64 encoded content + * @return an XMLObject with the Base64 encoded content + */ + private XMLObject createXMLObject(InputStream content) { + + Text textNode; + try { + textNode = at.gv.egiz.dom.DOMUtils.createBase64Text(content, ctx.getDocument()); + } catch (IOException e) { + log.error(e); + throw new SLRuntimeException(e); + } + + DOMStructure structure = new DOMStructure(textNode); + + String idValue = ctx.getIdValueFactory().createIdValue("Object"); + + return ctx.getSignatureFactory().newXMLObject(Collections.singletonList(structure), idValue, null, null); + + } + + /** + * Create an XMLObject with the given content node. + * + * @param content the content node + * + * @return an XMLObject with the given content + */ + private XMLObject createXMLObject(Node content) { + + String idValue = ctx.getIdValueFactory().createIdValue("Object"); + + List structures = Collections.singletonList(new DOMStructure(content)); + + return ctx.getSignatureFactory().newXMLObject(structures, idValue, null, null); + + } + + /** + * Sets the given xmlObject and creates and sets a corresponding + * Reference. + *

+ * A transform to Base64-decode the xmlObject's content is inserted at the top + * of to the optional transforms if given, or to a newly created + * Transforms element if transforms is + * null. + * + * @param xmlObject + * the XMLObject + * @param transforms + * an optional Transforms element (may be + * null) + * + * @throws SLCommandException + * if creating the Reference fails + * @throws NullPointerException + * if xmlObject is null + */ + private void setXMLObjectAndReferenceBase64(XMLObject xmlObject, XSECTTransforms transforms) throws SLCommandException { + + // create reference URI + // + // NOTE: the ds:Object can be referenced directly, as the Base64 transform + // operates on the text() of the input nodelist. + // + String referenceURI = "#" + xmlObject.getId(); + + // create Base64 Transform + Transform transform; + try { + transform = ctx.getSignatureFactory().newTransform(Transform.BASE64, (TransformParameterSpec) null); + } catch (NoSuchAlgorithmException e) { + // algorithm must be present + throw new SLRuntimeException(e); + } catch (InvalidAlgorithmParameterException e) { + // algorithm does not take parameters + throw new SLRuntimeException(e); + } + + if (transforms == null) { + transforms = new XSECTTransforms(Collections.singletonList(transform)); + } else { + transforms.insertTransform(transform); + } + + DigestMethod dm; + try { + dm = ctx.getAlgorithmMethodFactory().createDigestMethod(ctx); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get DigestMethod.", e); + throw new SLCommandException(4006); + } catch (InvalidAlgorithmParameterException e) { + log.error("Failed to get DigestMethod.", e); + throw new SLCommandException(4006); + } + String id = ctx.getIdValueFactory().createIdValue("Reference"); + + this.xmlObject = xmlObject; + this.reference = new XSECTReference(referenceURI, dm, transforms, null, id); + + } + + /** + * Sets the given xmlObject and creates and sets a corresponding + * Reference. + *

+ * A transform to select the xmlObject's content is inserted at the top of to + * the optional transforms if given, or to a newly created + * Transforms element if transforms is + * null. + *

+ * + * @param xmlObject + * the XMLObject + * @param transforms + * an optional Transforms element (may be + * null) + * + * @throws SLCommandException + * if creating the Reference fails + * @throws NullPointerException + * if xmlObject is null + */ + private void setXMLObjectAndReferenceXML(XMLObject xmlObject, XSECTTransforms transforms) throws SLCommandException { + + // create reference URI + String referenceURI = "#" + xmlObject.getId(); + + // create Transform to select ds:Object's children + Transform xpathTransform; + Transform c14nTransform; + try { + + XPathType xpath = new XPathType("id(\"" + xmlObject.getId() + "\")/node()", XPathType.Filter.INTERSECT); + List xpaths = Collections.singletonList(xpath); + XPathFilter2ParameterSpec params = new XPathFilter2ParameterSpec(xpaths); + + xpathTransform = ctx.getSignatureFactory().newTransform(Transform.XPATH2, params); + + // add exclusive canonicalization to avoid signing the namespace context of the ds:Object + c14nTransform = ctx.getSignatureFactory().newTransform(CanonicalizationMethod.EXCLUSIVE, (TransformParameterSpec) null); + + } catch (NoSuchAlgorithmException e) { + // algorithm must be present + throw new SLRuntimeException(e); + } catch (InvalidAlgorithmParameterException e) { + // params must be appropriate + throw new SLRuntimeException(e); + } + + if (transforms == null) { + List newTransfroms = new ArrayList(); + newTransfroms.add(xpathTransform); + newTransfroms.add(c14nTransform); + transforms = new XSECTTransforms(newTransfroms); + } else { + transforms.insertTransform(xpathTransform); + } + + DigestMethod dm; + try { + dm = ctx.getAlgorithmMethodFactory().createDigestMethod(ctx); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get DigestMethod.", e); + throw new SLCommandException(4006); + } catch (InvalidAlgorithmParameterException e) { + log.error("Failed to get DigestMethod.", e); + throw new SLCommandException(4006); + } + String id = ctx.getIdValueFactory().createIdValue("Reference"); + + this.xmlObject = xmlObject; + this.reference = new XSECTReference(referenceURI, dm, transforms, null, id); + + } + + /** + * Parses the given xmlContent and returns a corresponding + * document fragment. + * + *

+ * The to-be parsed content is surrounded by ... elements to + * allow for mixed (e.g. Text and Element) content in XMLContent. + *

+ * + * @param xmlContent + * the XMLContent to-be parsed + * + * @return a document fragment containing the parsed nodes + * + * @throws SLCommandException + * if parsing the given xmlContent fails + * + * @throws NullPointerException + * if xmlContent is null + */ + private DocumentFragment parseDataObject(XMLContentType xmlContent) throws SLCommandException { + + ByteArrayOutputStream redirectedStream = xmlContent.getRedirectedStream(); + + // Note: We can assume a fixed character encoding of UTF-8 for the + // content of the redirect stream as the content has already been parsed + // and serialized again to the redirect stream. + + List inputStreams = new ArrayList(); + try { + // dummy start element + inputStreams.add(new ByteArrayInputStream("".getBytes("UTF-8"))); + + // content + inputStreams.add(new ByteArrayInputStream(redirectedStream.toByteArray())); + + // dummy end element + inputStreams.add(new ByteArrayInputStream("".getBytes("UTF-8"))); + } catch (UnsupportedEncodingException e) { + throw new SLRuntimeException(e); + } + + SequenceInputStream inputStream = new SequenceInputStream(Collections.enumeration(inputStreams)); + + // parse DataObject + Document doc = parseDataObject(inputStream, "UTF-8"); + + Element documentElement = doc.getDocumentElement(); + + if (documentElement == null || + !"dummy".equals(documentElement.getLocalName())) { + log.info("Failed to parse DataObject XMLContent."); + throw new SLCommandException(4111); + } + + DocumentFragment fragment = doc.createDocumentFragment(); + while (documentElement.getFirstChild() != null) { + fragment.appendChild(documentElement.getFirstChild()); + } + + // log parsed document + if (log.isTraceEnabled()) { + + StringWriter writer = new StringWriter(); + + writer.write("DataObject:\n"); + + LSOutput output = domImplLS.createLSOutput(); + output.setCharacterStream(writer); + output.setEncoding("UTF-8"); + LSSerializer serializer = domImplLS.createLSSerializer(); + serializer.getDomConfig().setParameter("xml-declaration", Boolean.FALSE); + serializer.write(fragment, output); + + log.trace(writer.toString()); + } + + return fragment; + + } + + /** + * Parses the given inputStream using the given + * encoding and returns the parsed document. + * + * @param inputStream + * the to-be parsed input + * + * @param encoding + * the encoding to be used for parsing the given + * inputStream + * + * @return the parsed document + * + * @throws SLCommandException + * if parsing the inputStream fails. + * + * @throws NullPointerException + * if inputStram is null + */ + private Document parseDataObject(InputStream inputStream, String encoding) throws SLCommandException { + + LSInput input = domImplLS.createLSInput(); + input.setByteStream(inputStream); + + if (encoding != null) { + input.setEncoding(encoding); + } + + LSParser parser = domImplLS.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null); + DOMConfiguration domConfig = parser.getDomConfig(); + SimpleDOMErrorHandler errorHandler = new SimpleDOMErrorHandler(); + domConfig.setParameter("error-handler", errorHandler); + domConfig.setParameter("validate", Boolean.FALSE); + + Document doc; + try { + doc = parser.parse(input); + } catch (DOMException e) { + log.info("Existing XML document cannot be parsed.", e); + throw new SLCommandException(4111); + } catch (LSException e) { + log.info("Existing XML document cannot be parsed. ", e); + throw new SLCommandException(4111); + } + + if (errorHandler.hasErrors()) { + // log errors + if (log.isInfoEnabled()) { + List errorMessages = errorHandler.getErrorMessages(); + StringBuffer sb = new StringBuffer(); + for (String errorMessage : errorMessages) { + sb.append(" "); + sb.append(errorMessage); + } + log.info("Existing XML document cannot be parsed. " + sb.toString()); + } + throw new SLCommandException(4111); + } + + return doc; + + } + + +} -- cgit v1.2.3 From 66cfb865fbfa7af514e803003f928d77f1156e46 Mon Sep 17 00:00:00 2001 From: mcentner Date: Thu, 11 Sep 2008 12:16:35 +0000 Subject: Added to be signed data validation. git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@32 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- BKUViewer/.classpath | 10 + BKUViewer/.project | 23 + BKUViewer/.settings/org.eclipse.jdt.core.prefs | 5 + BKUViewer/.settings/org.maven.ide.eclipse.prefs | 8 + BKUViewer/pom.xml | 44 ++ .../at/gv/egiz/bku/slxhtml/SLXHTMLValidator.java | 251 ++++++++ .../egiz/bku/slxhtml/css/CSSValidatorSLXHTML.java | 95 +++ .../bku/slxhtml/css/CssBackgroundColorSLXHTML.java | 57 ++ .../egiz/bku/slxhtml/css/CssBackgroundSLXHTML.java | 93 +++ .../slxhtml/css/CssBorderBottomColorSLXHTML.java | 57 ++ .../bku/slxhtml/css/CssBorderColorSLXHTML.java | 81 +++ .../bku/slxhtml/css/CssBorderLeftColorSLXHTML.java | 57 ++ .../slxhtml/css/CssBorderRightColorSLXHTML.java | 57 ++ .../gv/egiz/bku/slxhtml/css/CssBorderSLXHTML.java | 85 +++ .../bku/slxhtml/css/CssBorderTopColorSLXHTML.java | 57 ++ .../gv/egiz/bku/slxhtml/css/CssColorSLXHTML.java | 99 ++++ .../at/gv/egiz/bku/slxhtml/css/CssFontSLXHTML.java | 59 ++ .../bku/slxhtml/css/CssLetterSpacingSLXHTML.java | 54 ++ .../bku/slxhtml/css/CssMarginBottomSLXHTML.java | 60 ++ .../egiz/bku/slxhtml/css/CssMarginLeftSLXHTML.java | 61 ++ .../bku/slxhtml/css/CssMarginRightSLXHTML.java | 60 ++ .../gv/egiz/bku/slxhtml/css/CssMarginSLXHTML.java | 101 ++++ .../egiz/bku/slxhtml/css/CssMarginTopSLXHTML.java | 61 ++ .../bku/slxhtml/css/CssPaddingBottomSLXHTML.java | 60 ++ .../bku/slxhtml/css/CssPaddingLeftSLXHTML.java | 60 ++ .../bku/slxhtml/css/CssPaddingRightSLXHTML.java | 60 ++ .../gv/egiz/bku/slxhtml/css/CssPaddingSLXHTML.java | 102 ++++ .../egiz/bku/slxhtml/css/CssPaddingTopSLXHTML.java | 61 ++ .../bku/slxhtml/css/CssTextDecorationSLXHTML.java | 51 ++ .../bku/slxhtml/css/CssWordSpacingSLXHTML.java | 54 ++ .../slxhtml/css/SLXHTMLInvalidParamException.java | 71 +++ .../at/gv/egiz/bku/slxhtml/css/SLXHTMLStyle.java | 22 + .../egiz/bku/slxhtml/css/TableLayoutSLXHTML.java | 45 ++ .../java/at/gv/egiz/bku/text/TextValidator.java | 32 + .../services/at.gv.egiz.bku.viewer.Validator | 2 + .../at/gv/egiz/bku/slxhtml/slxhtml-model-1.xsd | 469 +++++++++++++++ .../at/gv/egiz/bku/slxhtml/slxhtml-modules-1.xsd | 248 ++++++++ .../resources/at/gv/egiz/bku/slxhtml/slxhtml.xsd | 70 +++ .../at/gv/egiz/bku/slxhtml/xhtml-attribs-1.xsd | 72 +++ .../at/gv/egiz/bku/slxhtml/xhtml-blkphras-1.xsd | 161 ++++++ .../at/gv/egiz/bku/slxhtml/xhtml-blkpres-1.xsd | 37 ++ .../at/gv/egiz/bku/slxhtml/xhtml-blkstruct-1.xsd | 49 ++ .../at/gv/egiz/bku/slxhtml/xhtml-datatypes-1.xsd | 175 ++++++ .../at/gv/egiz/bku/slxhtml/xhtml-framework-1.xsd | 66 +++ .../at/gv/egiz/bku/slxhtml/xhtml-image-1.xsd | 45 ++ .../at/gv/egiz/bku/slxhtml/xhtml-inlphras-1.xsd | 163 ++++++ .../at/gv/egiz/bku/slxhtml/xhtml-inlpres-1.xsd | 39 ++ .../at/gv/egiz/bku/slxhtml/xhtml-inlstruct-1.xsd | 50 ++ .../at/gv/egiz/bku/slxhtml/xhtml-list-1.xsd | 99 ++++ .../at/gv/egiz/bku/slxhtml/xhtml-pres-1.xsd | 51 ++ .../at/gv/egiz/bku/slxhtml/xhtml-struct-1.xsd | 116 ++++ .../at/gv/egiz/bku/slxhtml/xhtml-style-1.xsd | 53 ++ .../at/gv/egiz/bku/slxhtml/xhtml-table-1.xsd | 272 +++++++++ .../at/gv/egiz/bku/slxhtml/xhtml-text-1.xsd | 67 +++ .../main/resources/at/gv/egiz/bku/slxhtml/xml.xsd | 145 +++++ .../org/w3c/css/properties/Config.properties | 32 + .../css/properties/ProfilesProperties.properties | 30 + .../css/properties/SLXHTMLProperties.properties | 641 +++++++++++++++++++++ .../java/at/gv/egiz/bku/slxhtml/ValidatorTest.java | 66 +++ .../gv/egiz/bku/slxhtml/css/CssValidatorTest.java | 75 +++ .../resources/at/gv/egiz/bku/slxhtml/test.xhtml | 10 + .../src/test/resources/commons-logging.properties | 1 + BKUViewer/src/test/resources/log4j.properties | 19 + bkucommon/pom.xml | 9 +- .../binding/multipart/InputStreamPartSource.java | 5 - .../egiz/bku/binding/multipart/SLResultPart.java | 5 - .../impl/CreateXMLSignatureCommandImpl.java | 13 +- .../egiz/bku/slcommands/impl/xsect/DataObject.java | 119 +++- .../bku/slcommands/impl/xsect/STALSignature.java | 11 +- .../egiz/bku/slcommands/impl/xsect/Signature.java | 10 +- .../egiz/bku/slexceptions/SLViewerException.java | 7 +- .../at/gv/egiz/bku/viewer/ValidationException.java | 38 ++ .../main/java/at/gv/egiz/bku/viewer/Validator.java | 25 + .../at/gv/egiz/bku/viewer/ValidatorFactory.java | 165 ++++++ .../bku/slcommands/impl/xsect/SignatureTest.java | 21 +- pom.xml | 33 +- 76 files changed, 5885 insertions(+), 52 deletions(-) create mode 100644 BKUViewer/.classpath create mode 100644 BKUViewer/.project create mode 100644 BKUViewer/.settings/org.eclipse.jdt.core.prefs create mode 100644 BKUViewer/.settings/org.maven.ide.eclipse.prefs create mode 100644 BKUViewer/pom.xml create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/SLXHTMLValidator.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CSSValidatorSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBackgroundColorSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBackgroundSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderBottomColorSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderColorSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderLeftColorSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderRightColorSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderTopColorSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssColorSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssFontSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssLetterSpacingSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginBottomSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginLeftSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginRightSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginTopSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingBottomSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingLeftSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingRightSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingTopSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssTextDecorationSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssWordSpacingSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/SLXHTMLInvalidParamException.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/SLXHTMLStyle.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/TableLayoutSLXHTML.java create mode 100644 BKUViewer/src/main/java/at/gv/egiz/bku/text/TextValidator.java create mode 100644 BKUViewer/src/main/resources/META-INF/services/at.gv.egiz.bku.viewer.Validator create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/slxhtml-model-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/slxhtml-modules-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/slxhtml.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-attribs-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-blkphras-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-blkpres-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-blkstruct-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-datatypes-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-framework-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-image-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-inlphras-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-inlpres-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-inlstruct-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-list-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-pres-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-struct-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-style-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-table-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-text-1.xsd create mode 100644 BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xml.xsd create mode 100644 BKUViewer/src/main/resources/org/w3c/css/properties/Config.properties create mode 100644 BKUViewer/src/main/resources/org/w3c/css/properties/ProfilesProperties.properties create mode 100644 BKUViewer/src/main/resources/org/w3c/css/properties/SLXHTMLProperties.properties create mode 100644 BKUViewer/src/test/java/at/gv/egiz/bku/slxhtml/ValidatorTest.java create mode 100644 BKUViewer/src/test/java/at/gv/egiz/bku/slxhtml/css/CssValidatorTest.java create mode 100644 BKUViewer/src/test/resources/at/gv/egiz/bku/slxhtml/test.xhtml create mode 100644 BKUViewer/src/test/resources/commons-logging.properties create mode 100644 BKUViewer/src/test/resources/log4j.properties create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/viewer/ValidationException.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/viewer/Validator.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/viewer/ValidatorFactory.java (limited to 'bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java') diff --git a/BKUViewer/.classpath b/BKUViewer/.classpath new file mode 100644 index 00000000..1041acfa --- /dev/null +++ b/BKUViewer/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/BKUViewer/.project b/BKUViewer/.project new file mode 100644 index 00000000..c18f3f10 --- /dev/null +++ b/BKUViewer/.project @@ -0,0 +1,23 @@ + + + BKUViewer + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/BKUViewer/.settings/org.eclipse.jdt.core.prefs b/BKUViewer/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..59690d7b --- /dev/null +++ b/BKUViewer/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +#Tue Sep 09 16:54:39 CEST 2008 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/BKUViewer/.settings/org.maven.ide.eclipse.prefs b/BKUViewer/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 00000000..feb34e97 --- /dev/null +++ b/BKUViewer/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,8 @@ +#Tue Sep 09 16:54:38 CEST 2008 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +version=1 diff --git a/BKUViewer/pom.xml b/BKUViewer/pom.xml new file mode 100644 index 00000000..d7dbe0aa --- /dev/null +++ b/BKUViewer/pom.xml @@ -0,0 +1,44 @@ + + + bku + at.gv.egiz + 1.0-SNAPSHOT + + 4.0.0 + at.gv.egiz + BKUViewer + BKU viewer components + 1.0-SNAPSHOT + + + + at.gv.egiz + bkucommon + 1.0-SNAPSHOT + + + commons-logging + commons-logging + + + xerces + xercesImpl + + + org.w3c + css-validator + 2.1-mocca + + + org.w3c + jigsaw + + + tagsoup + tagsoup + + + + + \ No newline at end of file diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/SLXHTMLValidator.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/SLXHTMLValidator.java new file mode 100644 index 00000000..7ce5fdbe --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/SLXHTMLValidator.java @@ -0,0 +1,251 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; +import java.util.Locale; + +import javax.xml.XMLConstants; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.ValidatorHandler; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import at.gv.egiz.bku.slxhtml.css.CSSValidatorSLXHTML; +import at.gv.egiz.bku.viewer.ValidationException; + +public class SLXHTMLValidator implements at.gv.egiz.bku.viewer.Validator { + + /** + * The schema file for the SLXHTML schema. + */ + private static final String SLXHTML_SCHEMA_FILE = "at/gv/egiz/bku/slxhtml/slxhtml.xsd"; + + /** + * Logging facility. + */ + private static Log log = LogFactory.getLog(SLXHTMLValidator.class); + + private static Schema slSchema; + + /** + * Initialize the security layer schema. + */ + private synchronized static void ensureSchema() { + if (slSchema == null) { + try { + SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + ClassLoader cl = SLXHTMLValidator.class.getClassLoader(); + URL schemaURL = cl.getResource(SLXHTML_SCHEMA_FILE); + log.debug("Trying to create SLXHTML schema from URL '" + schemaURL + "'."); + long t0 = System.currentTimeMillis(); + slSchema = schemaFactory.newSchema(schemaURL); + long t1 = System.currentTimeMillis(); + log.debug("SLXHTML schema successfully created in " + (t1 - t0) + "ms."); + } catch (SAXException e) { + log.error("Failed to load security layer XHTML schema.", e); + throw new RuntimeException("Failed to load security layer XHTML schema.", e); + } + + } + } + + public SLXHTMLValidator() { + ensureSchema(); + } + + public void validate(InputStream is, String charset) + throws ValidationException { + if (charset == null) { + validate(is, (Charset) null); + } else { + try { + validate(is, Charset.forName(charset)); + } catch (IllegalCharsetNameException e) { + throw new ValidationException(e); + } catch (UnsupportedCharsetException e) { + throw new ValidationException(e); + } + } + } + + public void validate(InputStream is, Charset charset) throws ValidationException { + + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setNamespaceAware(true); + spf.setSchema(slSchema); + spf.setValidating(true); + spf.setXIncludeAware(false); + + SAXParser parser; + try { + parser = spf.newSAXParser(); + } catch (ParserConfigurationException e) { + log.error("Failed to create SLXHTML parser.", e); + throw new RuntimeException("Failed to create SLXHTML parser.", e); + } catch (SAXException e) { + log.error("Failed to create SLXHTML parser.", e); + throw new RuntimeException("Failed to create SLXHTML parser.", e); + } + + InputSource source; + if (charset != null) { + source = new InputSource(new InputStreamReader(is, charset)); + } else { + source = new InputSource(is); + } + + + ValidatorHandler validatorHandler = slSchema.newValidatorHandler(); + + DefaultHandler defaultHandler = new ValidationHandler(validatorHandler); + try { + parser.parse(source, defaultHandler); + } catch (SAXException e) { + if (e.getException() instanceof ValidationException) { + throw (ValidationException) e.getException(); + } else { + throw new ValidationException(e); + } + } catch (IOException e) { + throw new ValidationException(e); + } + + } + + private void validateCss(InputStream is) throws ValidationException { + CSSValidatorSLXHTML cssValidator = new CSSValidatorSLXHTML(); + // TODO: use the right locale + cssValidator.validate(is, Locale.getDefault(), "SLXHTML", 0); + } + + private class ValidationHandler extends DefaultHandler implements ContentHandler { + + private ValidatorHandler validatorHandler; + + private boolean insideStyle = false; + + private StringBuffer style = new StringBuffer(); + + private ValidationHandler(ValidatorHandler contentHandler) { + this.validatorHandler = contentHandler; + } + + @Override + public void endDocument() throws SAXException { + validatorHandler.endDocument(); + } + + @Override + public void endPrefixMapping(String prefix) throws SAXException { + validatorHandler.endPrefixMapping(prefix); + } + + @Override + public void ignorableWhitespace(char[] ch, int start, int length) + throws SAXException { + validatorHandler.ignorableWhitespace(ch, start, length); + } + + @Override + public void processingInstruction(String target, String data) + throws SAXException { + validatorHandler.processingInstruction(target, data); + } + + @Override + public void setDocumentLocator(Locator locator) { + validatorHandler.setDocumentLocator(locator); + } + + @Override + public void skippedEntity(String name) throws SAXException { + validatorHandler.skippedEntity(name); + } + + @Override + public void startDocument() throws SAXException { + validatorHandler.startDocument(); + } + + @Override + public void startPrefixMapping(String prefix, String uri) + throws SAXException { + validatorHandler.startPrefixMapping(prefix, uri); + } + + @Override + public void startElement(String uri, String localName, String name, + Attributes attributes) throws SAXException { + validatorHandler.startElement(uri, localName, name, attributes); + + System.out.println(uri + ":" + localName); + + if ("http://www.w3.org/1999/xhtml".equals(uri) && + "style".equals(localName)) { + insideStyle = true; + } + } + + @Override + public void characters(char[] ch, int start, int length) + throws SAXException { + validatorHandler.characters(ch, start, length); + + if (insideStyle) { + style.append(ch, start, length); + } + + } + + @Override + public void endElement(String uri, String localName, String name) + throws SAXException { + validatorHandler.endElement(uri, localName, name); + + if (insideStyle) { + insideStyle = false; + try { + validateCss(new ByteArrayInputStream(style.toString().getBytes(Charset.forName("UTF-8")))); + } catch (ValidationException e) { + throw new SAXException(e); + } + } + } + + } + + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CSSValidatorSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CSSValidatorSLXHTML.java new file mode 100644 index 00000000..7abe4741 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CSSValidatorSLXHTML.java @@ -0,0 +1,95 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Locale; + +import org.w3c.css.css.CssParser; +import org.w3c.css.css.StyleSheet; +import org.w3c.css.css.StyleSheetParser; +import org.w3c.css.parser.CssError; +import org.w3c.css.parser.Errors; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.Util; +import org.w3c.css.util.Warning; +import org.w3c.css.util.Warnings; + +import at.gv.egiz.bku.viewer.ValidationException; + +public class CSSValidatorSLXHTML { + + public void validate(InputStream input, Locale locale, String title, int lineno) throws ValidationException { + + // disable imports + Util.importSecurity = true; + + CssParser cssParser = new StyleSheetParser(); + + ApplContext ac = new ApplContext(locale.getLanguage()); + ac.setCssVersion("slxhtml"); + ac.setMedium("all"); + + URL url; + try { + url = new URL("http://test.xyz"); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + + cssParser.parseStyleElement(ac, input, title, "all", url, lineno); + + StyleSheet styleSheet = cssParser.getStyleSheet(); + + // find conflicts + styleSheet.findConflicts(ac); + + boolean valid = true; + StringBuilder sb = new StringBuilder().append("CSS:"); + + // look for errors + Errors errors = styleSheet.getErrors(); + if (errors.getErrorCount() != 0) { + valid = false; + CssError[] cssErrors = errors.getErrors(); + for (CssError cssError : cssErrors) { + Exception exception = cssError.getException(); + sb.append(" "); + sb.append(exception.getMessage()); + } + } + + // look for warnings + Warnings warnings = styleSheet.getWarnings(); + if (warnings.getWarningCount() != 0) { + valid = false; + Warning[] cssWarnings = warnings.getWarnings(); + for (Warning warning : cssWarnings) { + sb.append(" "); + sb.append(warning.getWarningMessage()); + } + } + + if (!valid) { + throw new ValidationException(sb.toString()); + } + + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBackgroundColorSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBackgroundColorSLXHTML.java new file mode 100644 index 00000000..53191d17 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBackgroundColorSLXHTML.java @@ -0,0 +1,57 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssBackgroundColorCSS2; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssValue; + +public class CssBackgroundColorSLXHTML extends CssBackgroundColorCSS2 { + + public CssBackgroundColorSLXHTML() { + } + + public CssBackgroundColorSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // A Citizen Card Environment must support all the options for specifying a + // colour listed in [CSS 2], section 4.3.6 for a CSS property, if such an + // option is available for this property according to [CSS 2]. + + // The exceptions are the system colours (cf. [CSS 2], section 18.2); these + // must not be used in an instance document so as to prevent dependencies on + // the system environment. Otherwise the instance document must be rejected + // by the Citizen Card Environment. + + CssValue color = getColor(); + if (!isSoftlyInherited() && color != null) { + if (CssColorSLXHTML.isDisallowedColor(color)) { + throw new SLXHTMLInvalidParamException("color", color, getPropertyName(), ac); + } + } + + } + + public CssBackgroundColorSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + super(ac, expression); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBackgroundSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBackgroundSLXHTML.java new file mode 100644 index 00000000..724c8c6a --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBackgroundSLXHTML.java @@ -0,0 +1,93 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssBackgroundCSS2; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssValue; + +/** + * @author mcentner + * + */ +public class CssBackgroundSLXHTML extends CssBackgroundCSS2 { + + public CssBackgroundSLXHTML() { + } + + public CssBackgroundSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // A Citizen Card Environment must support all the options for specifying a + // colour listed in [CSS 2], section 4.3.6 for a CSS property, if such an + // option is available for this property according to [CSS 2]. + + // The exceptions are the system colours (cf. [CSS 2], section 18.2); these + // must not be used in an instance document so as to prevent dependencies on + // the system environment. Otherwise the instance document must be rejected + // by the Citizen Card Environment. + + CssValue color = getColor(); + if (!isSoftlyInherited() && color != null) { + if (CssColorSLXHTML.isDisallowedColor(color)) { + throw new SLXHTMLInvalidParamException("color", color, getPropertyName(), ac); + } + } + + // The properties for selecting and controlling an image as background + // (background-image, background-repeat, background-position, + // background-attachment; cf. [CSS 2], section 14.2.1) must not be contained + // in an instance document to prevent content from overlapping. Otherwise + // the instance document must be rejected by the Citizen Card Environment. + // + // The property for the shorthand version of the background properties + // (background) should be supported by a Citizen Card Environment. The + // recommended values result from the explanations for the background-color + // property above (cf. [CSS 2], section 14.2.1). If the property contains + // values for selecting and controlling an image as background, the instance + // document must be rejected by the Citizen Card Environment. + + if (getImage() != null) { + throw new SLXHTMLInvalidParamException("background", "background-image", ac); + } + + if (getRepeat() != null) { + throw new SLXHTMLInvalidParamException("background", "background-repeat", ac); + } + + if (getPosition() != null) { + throw new SLXHTMLInvalidParamException("background", "background-position", ac); + } + + if (getAttachment() != null) { + throw new SLXHTMLInvalidParamException("background", "background-attachment", ac); + } + + } + + public CssBackgroundSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderBottomColorSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderBottomColorSLXHTML.java new file mode 100644 index 00000000..4f5798b0 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderBottomColorSLXHTML.java @@ -0,0 +1,57 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssBorderBottomColorCSS2; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssValue; + +public class CssBorderBottomColorSLXHTML extends CssBorderBottomColorCSS2 { + + public CssBorderBottomColorSLXHTML() { + } + + public CssBorderBottomColorSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // A Citizen Card Environment must support all the options for specifying a + // colour listed in [CSS 2], section 4.3.6 for a CSS property, if such an + // option is available for this property according to [CSS 2]. + + // The exceptions are the system colours (cf. [CSS 2], section 18.2); these + // must not be used in an instance document so as to prevent dependencies on + // the system environment. Otherwise the instance document must be rejected + // by the Citizen Card Environment. + + CssValue color = getColor(); + if (!isSoftlyInherited() && color != null) { + if (CssColorSLXHTML.isDisallowedColor(color)) { + throw new SLXHTMLInvalidParamException("color", color, getPropertyName(), ac); + } + } + + } + + public CssBorderBottomColorSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderColorSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderColorSLXHTML.java new file mode 100644 index 00000000..3f5a7319 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderColorSLXHTML.java @@ -0,0 +1,81 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssBorderBottomColorCSS2; +import org.w3c.css.properties.css1.CssBorderColorCSS2; +import org.w3c.css.properties.css1.CssBorderLeftColorCSS2; +import org.w3c.css.properties.css1.CssBorderRightColorCSS2; +import org.w3c.css.properties.css1.CssBorderTopColorCSS2; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; + +public class CssBorderColorSLXHTML extends CssBorderColorCSS2 { + + public CssBorderColorSLXHTML() { + } + + public CssBorderColorSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // A Citizen Card Environment must support all the options for specifying a + // colour listed in [CSS 2], section 4.3.6 for a CSS property, if such an + // option is available for this property according to [CSS 2]. + + // The exceptions are the system colours (cf. [CSS 2], section 18.2); these + // must not be used in an instance document so as to prevent dependencies on + // the system environment. Otherwise the instance document must be rejected + // by the Citizen Card Environment. + + CssBorderTopColorCSS2 top = getTop(); + if (!isSoftlyInherited() && top != null) { + if (CssColorSLXHTML.isDisallowedColor(top.getColor())) { + throw new SLXHTMLInvalidParamException("color", top.getColor(), getPropertyName(), ac); + } + } + + CssBorderLeftColorCSS2 left = getLeft(); + if (!isSoftlyInherited() && left != null) { + if (CssColorSLXHTML.isDisallowedColor(left.getColor())) { + throw new SLXHTMLInvalidParamException("color", left.getColor(), getPropertyName(), ac); + } + } + + CssBorderRightColorCSS2 right = getRight(); + if (!isSoftlyInherited() && right != null) { + if (CssColorSLXHTML.isDisallowedColor(right.getColor())) { + throw new SLXHTMLInvalidParamException("color", right.getColor(), getPropertyName(), ac); + } + } + + CssBorderBottomColorCSS2 bottom = getBottom(); + if (!isSoftlyInherited() && bottom != null) { + if (CssColorSLXHTML.isDisallowedColor(bottom.getColor())) { + throw new SLXHTMLInvalidParamException("color", bottom.getColor(), getPropertyName(), ac); + } + } + + } + + public CssBorderColorSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderLeftColorSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderLeftColorSLXHTML.java new file mode 100644 index 00000000..e2378e99 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderLeftColorSLXHTML.java @@ -0,0 +1,57 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssBorderLeftColorCSS2; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssValue; + +public class CssBorderLeftColorSLXHTML extends CssBorderLeftColorCSS2 { + + public CssBorderLeftColorSLXHTML() { + } + + public CssBorderLeftColorSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // A Citizen Card Environment must support all the options for specifying a + // colour listed in [CSS 2], section 4.3.6 for a CSS property, if such an + // option is available for this property according to [CSS 2]. + + // The exceptions are the system colours (cf. [CSS 2], section 18.2); these + // must not be used in an instance document so as to prevent dependencies on + // the system environment. Otherwise the instance document must be rejected + // by the Citizen Card Environment. + + CssValue color = getColor(); + if (!isSoftlyInherited() && color != null) { + if (CssColorSLXHTML.isDisallowedColor(color)) { + throw new SLXHTMLInvalidParamException("color", color, getPropertyName(), ac); + } + } + + } + + public CssBorderLeftColorSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderRightColorSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderRightColorSLXHTML.java new file mode 100644 index 00000000..99d6bae5 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderRightColorSLXHTML.java @@ -0,0 +1,57 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssBorderRightColorCSS2; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssValue; + +public class CssBorderRightColorSLXHTML extends CssBorderRightColorCSS2 { + + public CssBorderRightColorSLXHTML() { + } + + public CssBorderRightColorSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // A Citizen Card Environment must support all the options for specifying a + // colour listed in [CSS 2], section 4.3.6 for a CSS property, if such an + // option is available for this property according to [CSS 2]. + + // The exceptions are the system colours (cf. [CSS 2], section 18.2); these + // must not be used in an instance document so as to prevent dependencies on + // the system environment. Otherwise the instance document must be rejected + // by the Citizen Card Environment. + + CssValue color = getColor(); + if (!isSoftlyInherited() && color != null) { + if (CssColorSLXHTML.isDisallowedColor(color)) { + throw new SLXHTMLInvalidParamException("color", color, getPropertyName(), ac); + } + } + + } + + public CssBorderRightColorSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderSLXHTML.java new file mode 100644 index 00000000..ac32670e --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderSLXHTML.java @@ -0,0 +1,85 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssBorderCSS2; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssValue; + +public class CssBorderSLXHTML extends CssBorderCSS2 { + + public CssBorderSLXHTML() { + } + + public CssBorderSLXHTML(ApplContext ac, CssExpression value, boolean check) + throws InvalidParamException { + super(ac, value, check); + + // A Citizen Card Environment must support all the options for specifying a + // colour listed in [CSS 2], section 4.3.6 for a CSS property, if such an + // option is available for this property according to [CSS 2]. + + // The exceptions are the system colours (cf. [CSS 2], section 18.2); these + // must not be used in an instance document so as to prevent dependencies on + // the system environment. Otherwise the instance document must be rejected + // by the Citizen Card Environment. + + if (getTop() != null) { + CssValue top = getTop().getColor(); + if (!isSoftlyInherited() && top != null) { + if (CssColorSLXHTML.isDisallowedColor(top)) { + throw new SLXHTMLInvalidParamException("color", top, getPropertyName(), ac); + } + } + } + + if (getLeft() != null) { + CssValue left = getLeft().getColor(); + if (!isSoftlyInherited() && left != null) { + if (CssColorSLXHTML.isDisallowedColor(left)) { + throw new SLXHTMLInvalidParamException("color", left, getPropertyName(), ac); + } + } + } + + if (getRight() != null) { + CssValue right = getRight().getColor(); + if (!isSoftlyInherited() && right != null) { + if (CssColorSLXHTML.isDisallowedColor(right)) { + throw new SLXHTMLInvalidParamException("color", right, getPropertyName(), ac); + } + } + } + + if (getBottom() != null) { + CssValue bottom = getBottom().getColor(); + if (!isSoftlyInherited() && bottom != null) { + if (CssColorSLXHTML.isDisallowedColor(bottom)) { + throw new SLXHTMLInvalidParamException("color", bottom, getPropertyName(), ac); + } + } + } + } + + public CssBorderSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderTopColorSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderTopColorSLXHTML.java new file mode 100644 index 00000000..42926479 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssBorderTopColorSLXHTML.java @@ -0,0 +1,57 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssBorderTopColorCSS2; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssValue; + +public class CssBorderTopColorSLXHTML extends CssBorderTopColorCSS2 { + + public CssBorderTopColorSLXHTML() { + } + + public CssBorderTopColorSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // A Citizen Card Environment must support all the options for specifying a + // colour listed in [CSS 2], section 4.3.6 for a CSS property, if such an + // option is available for this property according to [CSS 2]. + + // The exceptions are the system colours (cf. [CSS 2], section 18.2); these + // must not be used in an instance document so as to prevent dependencies on + // the system environment. Otherwise the instance document must be rejected + // by the Citizen Card Environment. + + CssValue color = getColor(); + if (!isSoftlyInherited() && color != null) { + if (CssColorSLXHTML.isDisallowedColor(color)) { + throw new SLXHTMLInvalidParamException("color", color, getPropertyName(), ac); + } + } + + } + + public CssBorderTopColorSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssColorSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssColorSLXHTML.java new file mode 100644 index 00000000..a640eb3a --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssColorSLXHTML.java @@ -0,0 +1,99 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import java.util.HashSet; +import java.util.Set; + +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssValue; + +public class CssColorSLXHTML extends org.w3c.css.properties.css1.CssColorCSS2 { + + private static Set SLXHTML_DISSALLOWED_COLORS = new HashSet(); + + static { + + SLXHTML_DISSALLOWED_COLORS.add("activeborder"); + SLXHTML_DISSALLOWED_COLORS.add("activecaption"); + SLXHTML_DISSALLOWED_COLORS.add("appworkspace"); + SLXHTML_DISSALLOWED_COLORS.add("background"); + SLXHTML_DISSALLOWED_COLORS.add("buttonface"); + SLXHTML_DISSALLOWED_COLORS.add("buttonhighlight"); + SLXHTML_DISSALLOWED_COLORS.add("buttonshadow"); + SLXHTML_DISSALLOWED_COLORS.add("buttontext"); + SLXHTML_DISSALLOWED_COLORS.add("captiontext"); + SLXHTML_DISSALLOWED_COLORS.add("graytext"); + SLXHTML_DISSALLOWED_COLORS.add("highlight"); + SLXHTML_DISSALLOWED_COLORS.add("highlighttext"); + SLXHTML_DISSALLOWED_COLORS.add("inactiveborder"); + SLXHTML_DISSALLOWED_COLORS.add("inactivecaption"); + SLXHTML_DISSALLOWED_COLORS.add("inactivecaptiontext"); + SLXHTML_DISSALLOWED_COLORS.add("infobackground"); + SLXHTML_DISSALLOWED_COLORS.add("infotext"); + SLXHTML_DISSALLOWED_COLORS.add("menu"); + SLXHTML_DISSALLOWED_COLORS.add("menutext"); + SLXHTML_DISSALLOWED_COLORS.add("scrollbar"); + SLXHTML_DISSALLOWED_COLORS.add("threeddarkshadow"); + SLXHTML_DISSALLOWED_COLORS.add("threedface"); + SLXHTML_DISSALLOWED_COLORS.add("threedhighlight"); + SLXHTML_DISSALLOWED_COLORS.add("threedlightshadow"); + SLXHTML_DISSALLOWED_COLORS.add("threedshadow"); + SLXHTML_DISSALLOWED_COLORS.add("window"); + SLXHTML_DISSALLOWED_COLORS.add("windowframe"); + SLXHTML_DISSALLOWED_COLORS.add("windowtext"); + + } + + public static boolean isDisallowedColor(CssValue cssValue) { + return SLXHTML_DISSALLOWED_COLORS.contains(cssValue.toString().toLowerCase()); + } + + public CssColorSLXHTML() { + } + + public CssColorSLXHTML(ApplContext ac, CssExpression expression, boolean check) + throws InvalidParamException { + + super(ac, expression, check); + + // A Citizen Card Environment must support all the options for specifying a + // colour listed in [CSS 2], section 4.3.6 for a CSS property, if such an + // option is available for this property according to [CSS 2]. + + // The exceptions are the system colours (cf. [CSS 2], section 18.2); these + // must not be used in an instance document so as to prevent dependencies on + // the system environment. Otherwise the instance document must be rejected + // by the Citizen Card Environment. + + CssValue color = getColor(); + if (!isSoftlyInherited() && color != null) { + if (CssColorSLXHTML.isDisallowedColor(color)) { + throw new SLXHTMLInvalidParamException("color", color, getPropertyName(), ac); + } + } + + } + + public CssColorSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssFontSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssFontSLXHTML.java new file mode 100644 index 00000000..8e5298ec --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssFontSLXHTML.java @@ -0,0 +1,59 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssFontCSS2; +import org.w3c.css.properties.css1.CssFontConstantCSS2; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssIdent; +import org.w3c.css.values.CssValue; + +public class CssFontSLXHTML extends CssFontCSS2 { + + public CssFontSLXHTML() { + } + + public CssFontSLXHTML(ApplContext ac, CssExpression expression, boolean check) + throws InvalidParamException { + super(ac, checkExpression(expression, ac), check); + } + + public CssFontSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + + protected static CssExpression checkExpression(CssExpression expression, + ApplContext ac) throws InvalidParamException { + + CssValue value = expression.getValue(); + + if (value instanceof CssIdent) { + for (String font : CssFontConstantCSS2.FONT) { + if (font.equalsIgnoreCase(value.toString())) { + throw new SLXHTMLInvalidParamException("font", value.toString(), ac); + } + } + } + + return expression; + + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssLetterSpacingSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssLetterSpacingSLXHTML.java new file mode 100644 index 00000000..326a731f --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssLetterSpacingSLXHTML.java @@ -0,0 +1,54 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssLetterSpacing; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssLength; +import org.w3c.css.values.CssNumber; + +public class CssLetterSpacingSLXHTML extends CssLetterSpacing { + + public CssLetterSpacingSLXHTML() { + } + + public CssLetterSpacingSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + Object value = get(); + if (value instanceof CssLength) { + Object length = ((CssLength) value).get(); + if (length instanceof Float && ((Float) length).floatValue() < 0) { + throw new SLXHTMLInvalidParamException("spacing", length, getPropertyName(), ac); + } + } else if (value instanceof CssNumber) { + if (((CssNumber) value).getValue() < 0) { + throw new SLXHTMLInvalidParamException("spacing", value, getPropertyName(), ac); + } + } + + } + + public CssLetterSpacingSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginBottomSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginBottomSLXHTML.java new file mode 100644 index 00000000..cac97d06 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginBottomSLXHTML.java @@ -0,0 +1,60 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssMarginBottom; +import org.w3c.css.properties.css1.CssMarginSide; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; + +public class CssMarginBottomSLXHTML extends CssMarginBottom { + + public CssMarginBottomSLXHTML() { + } + + public CssMarginBottomSLXHTML(CssMarginSide another) { + super(another); + } + + public CssMarginBottomSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + + public CssMarginBottomSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // The margin-top, margin-bottom, margin-left and margin-right properties + // must be supported by a Citizen Card Environment. Values specified as + // percentages (cf. section 3.5.1.2) should be supported. + + // The margin property may be supported by a Citizen Card Environment. + + // An instance document must not contain a negative value in the properties + // mentioned above. Otherwise it must be rejected by the Citizen Card + // Environment. + + if (CssMarginSLXHTML.isDisallowedMargin(getValue())) { + throw new SLXHTMLInvalidParamException("margin", getValue(), + getPropertyName(), ac); + } + + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginLeftSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginLeftSLXHTML.java new file mode 100644 index 00000000..c456af43 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginLeftSLXHTML.java @@ -0,0 +1,61 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssMarginLeft; +import org.w3c.css.properties.css1.CssMarginSide; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; + +public class CssMarginLeftSLXHTML extends CssMarginLeft { + + public CssMarginLeftSLXHTML() { + } + + public CssMarginLeftSLXHTML(CssMarginSide another) { + super(another); + } + + public CssMarginLeftSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + + public CssMarginLeftSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // TODO Auto-generated constructor stub + // The margin-top, margin-bottom, margin-left and margin-right properties + // must be supported by a Citizen Card Environment. Values specified as + // percentages (cf. section 3.5.1.2) should be supported. + + // The margin property may be supported by a Citizen Card Environment. + + // An instance document must not contain a negative value in the properties + // mentioned above. Otherwise it must be rejected by the Citizen Card + // Environment. + + if (CssMarginSLXHTML.isDisallowedMargin(getValue())) { + throw new SLXHTMLInvalidParamException("margin", getValue(), + getPropertyName(), ac); + } + + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginRightSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginRightSLXHTML.java new file mode 100644 index 00000000..7f16830d --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginRightSLXHTML.java @@ -0,0 +1,60 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssMarginRight; +import org.w3c.css.properties.css1.CssMarginSide; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; + +public class CssMarginRightSLXHTML extends CssMarginRight { + + public CssMarginRightSLXHTML() { + } + + public CssMarginRightSLXHTML(CssMarginSide another) { + super(another); + } + + public CssMarginRightSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + + public CssMarginRightSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // The margin-top, margin-bottom, margin-left and margin-right properties + // must be supported by a Citizen Card Environment. Values specified as + // percentages (cf. section 3.5.1.2) should be supported. + + // The margin property may be supported by a Citizen Card Environment. + + // An instance document must not contain a negative value in the properties + // mentioned above. Otherwise it must be rejected by the Citizen Card + // Environment. + + if (CssMarginSLXHTML.isDisallowedMargin(getValue())) { + throw new SLXHTMLInvalidParamException("margin", getValue(), + getPropertyName(), ac); + } + + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginSLXHTML.java new file mode 100644 index 00000000..f478b96a --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginSLXHTML.java @@ -0,0 +1,101 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssMargin; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssLength; +import org.w3c.css.values.CssNumber; +import org.w3c.css.values.CssPercentage; +import org.w3c.css.values.CssValue; + +public class CssMarginSLXHTML extends CssMargin { + + public CssMarginSLXHTML() { + } + + public CssMarginSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + if (getTop() != null) { + if (isDisallowedMargin(getTop().getValue())) { + throw new SLXHTMLInvalidParamException("margin", getTop().getValue(), + getPropertyName(), ac); + } + } + + if (getRight() != null) { + if (isDisallowedMargin(getRight().getValue())) { + throw new SLXHTMLInvalidParamException("margin", getRight().getValue(), + getPropertyName(), ac); + } + } + + if (getLeft() != null) { + if (isDisallowedMargin(getLeft().getValue())) { + throw new SLXHTMLInvalidParamException("margin", getLeft().getValue(), + getPropertyName(), ac); + } + } + + if (getBottom() != null) { + if (isDisallowedMargin(getBottom().getValue())) { + throw new SLXHTMLInvalidParamException("margin", getBottom().getValue(), + getPropertyName(), ac); + } + } + + } + + public CssMarginSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + + public static boolean isDisallowedMargin(CssValue margin) { + + // The margin-top, margin-bottom, margin-left and margin-right properties + // must be supported by a Citizen Card Environment. Values specified as + // percentages (cf. section 3.5.1.2) should be supported. + + // The margin property may be supported by a Citizen Card Environment. + + // An instance document must not contain a negative value in the properties + // mentioned above. Otherwise it must be rejected by the Citizen Card + // Environment. + + if (margin instanceof CssLength) { + Object value = ((CssLength) margin).get(); + if (value instanceof Float) { + return ((Float) value).floatValue() < 0; + } + } else if (margin instanceof CssPercentage) { + Object value = ((CssPercentage) margin).get(); + if (value instanceof Float) { + return ((Float) value).floatValue() < 0; + } + } else if (margin instanceof CssNumber) { + return ((CssNumber) margin).getValue() < 0; + } + + return false; + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginTopSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginTopSLXHTML.java new file mode 100644 index 00000000..06b30c4f --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssMarginTopSLXHTML.java @@ -0,0 +1,61 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssMarginSide; +import org.w3c.css.properties.css1.CssMarginTop; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; + +public class CssMarginTopSLXHTML extends CssMarginTop { + + public CssMarginTopSLXHTML() { + } + + public CssMarginTopSLXHTML(CssMarginSide another) { + super(another); + } + + public CssMarginTopSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + + } + + public CssMarginTopSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // The margin-top, margin-bottom, margin-left and margin-right properties + // must be supported by a Citizen Card Environment. Values specified as + // percentages (cf. section 3.5.1.2) should be supported. + + // The margin property may be supported by a Citizen Card Environment. + + // An instance document must not contain a negative value in the properties + // mentioned above. Otherwise it must be rejected by the Citizen Card + // Environment. + + if (CssMarginSLXHTML.isDisallowedMargin(getValue())) { + throw new SLXHTMLInvalidParamException("margin", getValue(), + getPropertyName(), ac); + } + + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingBottomSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingBottomSLXHTML.java new file mode 100644 index 00000000..4bcb0065 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingBottomSLXHTML.java @@ -0,0 +1,60 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssPaddingBottom; +import org.w3c.css.properties.css1.CssPaddingSide; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; + +public class CssPaddingBottomSLXHTML extends CssPaddingBottom { + + public CssPaddingBottomSLXHTML() { + } + + public CssPaddingBottomSLXHTML(CssPaddingSide another) { + super(another); + } + + public CssPaddingBottomSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // The padding-top, padding-bottom, padding-left and padding-right + // properties must be supported by a Citizen Card Environment. Values + // specified as percentages (cf. section 3.5.1.2) should be supported. + + // The padding property may be supported by a Citizen Card Environment. + + // An instance document must not contain a negative value in the properties + // mentioned above. Otherwise it must be rejected by the Citizen Card + // Environment. + + if (CssPaddingSLXHTML.isDisallowedValue(getValue())) { + throw new SLXHTMLInvalidParamException("padding", getValue(), + getPropertyName(), ac); + } + + } + + public CssPaddingBottomSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingLeftSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingLeftSLXHTML.java new file mode 100644 index 00000000..350a5c15 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingLeftSLXHTML.java @@ -0,0 +1,60 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssPaddingLeft; +import org.w3c.css.properties.css1.CssPaddingSide; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; + +public class CssPaddingLeftSLXHTML extends CssPaddingLeft { + + public CssPaddingLeftSLXHTML() { + } + + public CssPaddingLeftSLXHTML(CssPaddingSide another) { + super(another); + } + + public CssPaddingLeftSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // The padding-top, padding-bottom, padding-left and padding-right + // properties must be supported by a Citizen Card Environment. Values + // specified as percentages (cf. section 3.5.1.2) should be supported. + + // The padding property may be supported by a Citizen Card Environment. + + // An instance document must not contain a negative value in the properties + // mentioned above. Otherwise it must be rejected by the Citizen Card + // Environment. + + if (CssPaddingSLXHTML.isDisallowedValue(getValue())) { + throw new SLXHTMLInvalidParamException("padding", getValue(), + getPropertyName(), ac); + } + + } + + public CssPaddingLeftSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingRightSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingRightSLXHTML.java new file mode 100644 index 00000000..d2d62748 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingRightSLXHTML.java @@ -0,0 +1,60 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssPaddingRight; +import org.w3c.css.properties.css1.CssPaddingSide; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; + +public class CssPaddingRightSLXHTML extends CssPaddingRight { + + public CssPaddingRightSLXHTML() { + } + + public CssPaddingRightSLXHTML(CssPaddingSide another) { + super(another); + } + + public CssPaddingRightSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // The padding-top, padding-bottom, padding-left and padding-right + // properties must be supported by a Citizen Card Environment. Values + // specified as percentages (cf. section 3.5.1.2) should be supported. + + // The padding property may be supported by a Citizen Card Environment. + + // An instance document must not contain a negative value in the properties + // mentioned above. Otherwise it must be rejected by the Citizen Card + // Environment. + + if (CssPaddingSLXHTML.isDisallowedValue(getValue())) { + throw new SLXHTMLInvalidParamException("padding", getValue(), + getPropertyName(), ac); + } + + } + + public CssPaddingRightSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingSLXHTML.java new file mode 100644 index 00000000..57d7cf77 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingSLXHTML.java @@ -0,0 +1,102 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssPadding; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssLength; +import org.w3c.css.values.CssNumber; +import org.w3c.css.values.CssPercentage; +import org.w3c.css.values.CssValue; + +public class CssPaddingSLXHTML extends CssPadding { + + public CssPaddingSLXHTML() { + } + + public CssPaddingSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + if (getTop() != null) { + if (isDisallowedValue(getTop().getValue())) { + throw new SLXHTMLInvalidParamException("padding", getTop().getValue(), + getPropertyName(), ac); + } + } + + if (getRight() != null) { + if (isDisallowedValue(getRight().getValue())) { + throw new SLXHTMLInvalidParamException("padding", getRight().getValue(), + getPropertyName(), ac); + } + } + + if (getLeft() != null) { + if (isDisallowedValue(getLeft().getValue())) { + throw new SLXHTMLInvalidParamException("padding", getLeft().getValue(), + getPropertyName(), ac); + } + } + + if (getBottom() != null) { + if (isDisallowedValue(getBottom().getValue())) { + throw new SLXHTMLInvalidParamException("padding", getBottom().getValue(), + getPropertyName(), ac); + } + } + + } + + public CssPaddingSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + + public static boolean isDisallowedValue(CssValue padding) { + + // The padding-top, padding-bottom, padding-left and padding-right + // properties must be supported by a Citizen Card Environment. Values + // specified as percentages (cf. section 3.5.1.2) should be supported. + + // The padding property may be supported by a Citizen Card Environment. + + // An instance document must not contain a negative value in the properties + // mentioned above. Otherwise it must be rejected by the Citizen Card + // Environment. + + if (padding instanceof CssLength) { + Object value = ((CssLength) padding).get(); + if (value instanceof Float) { + return ((Float) value).floatValue() < 0; + } + } else if (padding instanceof CssPercentage) { + Object value = ((CssPercentage) padding).get(); + if (value instanceof Float) { + return ((Float) value).floatValue() < 0; + } + } else if (padding instanceof CssNumber) { + return ((CssNumber) padding).getValue() < 0; + } + + return false; + + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingTopSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingTopSLXHTML.java new file mode 100644 index 00000000..bc113bfe --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssPaddingTopSLXHTML.java @@ -0,0 +1,61 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssPaddingSide; +import org.w3c.css.properties.css1.CssPaddingTop; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; + +public class CssPaddingTopSLXHTML extends CssPaddingTop { + + public CssPaddingTopSLXHTML() { + } + + public CssPaddingTopSLXHTML(CssPaddingSide another) { + super(another); + } + + public CssPaddingTopSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + // The padding-top, padding-bottom, padding-left and padding-right + // properties must be supported by a Citizen Card Environment. Values + // specified as percentages (cf. section 3.5.1.2) should be supported. + + // The padding property may be supported by a Citizen Card Environment. + + // An instance document must not contain a negative value in the properties + // mentioned above. Otherwise it must be rejected by the Citizen Card + // Environment. + + if (CssPaddingSLXHTML.isDisallowedValue(getValue())) { + throw new SLXHTMLInvalidParamException("padding", getValue(), + getPropertyName(), ac); + } + + } + + public CssPaddingTopSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + super(ac, expression); + // TODO Auto-generated constructor stub + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssTextDecorationSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssTextDecorationSLXHTML.java new file mode 100644 index 00000000..16b9780a --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssTextDecorationSLXHTML.java @@ -0,0 +1,51 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssTextDecoration; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssValue; + +public class CssTextDecorationSLXHTML extends CssTextDecoration { + + public CssTextDecorationSLXHTML() { + } + + public CssTextDecorationSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + if (get() instanceof CssValue) { + if ("blink".equalsIgnoreCase(((CssValue) get()).toString())) { + throw new SLXHTMLInvalidParamException("text-decoration", "blink", ac); + } + } else if (get() instanceof String) { + if ("blink".equalsIgnoreCase((String) get())) { + throw new SLXHTMLInvalidParamException("text-decoration", "blink", ac); + } + } + + } + + public CssTextDecorationSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssWordSpacingSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssWordSpacingSLXHTML.java new file mode 100644 index 00000000..a497f4e3 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/CssWordSpacingSLXHTML.java @@ -0,0 +1,54 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css1.CssWordSpacing; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssLength; +import org.w3c.css.values.CssNumber; + +public class CssWordSpacingSLXHTML extends CssWordSpacing { + + public CssWordSpacingSLXHTML() { + } + + public CssWordSpacingSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + Object value = get(); + if (value instanceof CssLength) { + Object length = ((CssLength) value).get(); + if (length instanceof Float && ((Float) length).floatValue() < 0) { + throw new SLXHTMLInvalidParamException("spacing", length, getPropertyName(), ac); + } + } else if (value instanceof CssNumber) { + if (((CssNumber) value).getValue() < 0) { + throw new SLXHTMLInvalidParamException("spacing", value, getPropertyName(), ac); + } + } + + } + + public CssWordSpacingSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/SLXHTMLInvalidParamException.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/SLXHTMLInvalidParamException.java new file mode 100644 index 00000000..edac03f4 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/SLXHTMLInvalidParamException.java @@ -0,0 +1,71 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import java.text.MessageFormat; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.w3c.css.util.ApplContext; + +public class SLXHTMLInvalidParamException extends + org.w3c.css.util.InvalidParamException { + + private static final long serialVersionUID = 1L; + + protected String message; + + public SLXHTMLInvalidParamException() { + } + + public SLXHTMLInvalidParamException(String error, ApplContext ac) { + setMessage(error, null, ac); + } + + public SLXHTMLInvalidParamException(String error, Object message, ApplContext ac) { + setMessage(error, new Object[] {message}, ac); + } + + public SLXHTMLInvalidParamException(String error, Object message1, Object message2, + ApplContext ac) { + setMessage(error, new Object[] {message1, message2}, ac); + } + + @Override + public String getMessage() { + return getLocalizedMessage(); + } + + @Override + public String getLocalizedMessage() { + return message; + } + + protected void setMessage(String error, Object[] arguments, ApplContext ac) { + Locale locale = new Locale(ac.getContentLanguage()); + ResourceBundle bundle = ResourceBundle.getBundle("at/gv/egiz/bku/slxhtml/css/Messages", locale); + String pattern; + try { + pattern = bundle.getString(error); + } catch (MissingResourceException e) { + pattern = "Can't find error message for : " + error; + } + message = MessageFormat.format(pattern, arguments); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/SLXHTMLStyle.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/SLXHTMLStyle.java new file mode 100644 index 00000000..99448ec4 --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/SLXHTMLStyle.java @@ -0,0 +1,22 @@ +// +// $Id: Css2Style.java,v 1.2 2005-09-08 12:24:01 ylafon Exp $ +// From Philippe Le Hegaret (Philippe.Le_Hegaret@sophia.inria.fr) +// +// (c) COPYRIGHT MIT and INRIA, 1997. +// Please first read the full copyright statement in file COPYRIGHT.html +package at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.aural.ACssStyle; +import org.w3c.css.parser.CssPrinterStyle; + +/** + * @version $Revision: 1.2 $ + */ +public class SLXHTMLStyle extends ACssStyle { + + public void print(CssPrinterStyle printer) { + super.print(printer); + } + + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/TableLayoutSLXHTML.java b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/TableLayoutSLXHTML.java new file mode 100644 index 00000000..50f30cce --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/slxhtml/css/TableLayoutSLXHTML.java @@ -0,0 +1,45 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import org.w3c.css.properties.css2.table.TableLayout; +import org.w3c.css.util.ApplContext; +import org.w3c.css.util.InvalidParamException; +import org.w3c.css.values.CssExpression; +import org.w3c.css.values.CssIdent; + +public class TableLayoutSLXHTML extends TableLayout { + + public TableLayoutSLXHTML() { + } + + public TableLayoutSLXHTML(ApplContext ac, CssExpression expression, + boolean check) throws InvalidParamException { + super(ac, expression, check); + + if (new CssIdent("fixed").equals(get())) { + throw new SLXHTMLInvalidParamException("table-layout", "fixed", getPropertyName(), ac); + } + + } + + public TableLayoutSLXHTML(ApplContext ac, CssExpression expression) + throws InvalidParamException { + this(ac, expression, false); + } + +} diff --git a/BKUViewer/src/main/java/at/gv/egiz/bku/text/TextValidator.java b/BKUViewer/src/main/java/at/gv/egiz/bku/text/TextValidator.java new file mode 100644 index 00000000..5108140d --- /dev/null +++ b/BKUViewer/src/main/java/at/gv/egiz/bku/text/TextValidator.java @@ -0,0 +1,32 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.text; + +import java.io.InputStream; + +import at.gv.egiz.bku.viewer.ValidationException; +import at.gv.egiz.bku.viewer.Validator; + +public class TextValidator implements Validator { + + @Override + public void validate(InputStream is, String charset) + throws ValidationException { + // TODO: implement character validation + } + +} diff --git a/BKUViewer/src/main/resources/META-INF/services/at.gv.egiz.bku.viewer.Validator b/BKUViewer/src/main/resources/META-INF/services/at.gv.egiz.bku.viewer.Validator new file mode 100644 index 00000000..0004949b --- /dev/null +++ b/BKUViewer/src/main/resources/META-INF/services/at.gv.egiz.bku.viewer.Validator @@ -0,0 +1,2 @@ +application/xhtml+xml at.gv.egiz.bku.slxhtml.SLXHTMLValidator +text/plain at.gv.egiz.bku.text.TextValidator \ No newline at end of file diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/slxhtml-model-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/slxhtml-model-1.xsd new file mode 100644 index 00000000..89e91faa --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/slxhtml-model-1.xsd @@ -0,0 +1,469 @@ + + + + + + This is the XML Schema module of common content models for SLXHTML. + SLXHTML is a profile of XHTML (see W3C copyright notice below). + + @author: Gregor Karlinger gregor.karlinger@cio.gv.at + $Id: slxhtml-model-1.xsd,v 1.4 2004/05/12 11:35:31 karlinger Exp $ + + + + + + XHTML Document Model + This module describes the groupings of elements/attributes + that make up common content models for XHTML elements. + XHTML has following basic content models: + xhtml.Inline.mix; character-level elements + xhtml.Block.mix; block-like elements, e.g., paragraphs and lists + xhtml.Flow.mix; any block or inline elements + xhtml.HeadOpts.mix; Head Elements + xhtml.InlinePre.mix; Special class for pre content model + xhtml.InlineNoAnchor.mix; Content model for Anchor + + Any groups declared in this module may be used to create + element content models, but the above are considered 'global' + (insofar as that term applies here). XHTML has the + following Attribute Groups + xhtml.Core.extra.attrib + xhtml.I18n.extra.attrib + xhtml.Common.extra + + The above attribute Groups are considered Global + + + + + + + SLXHTML 1.2: attributeGroup "dir.attrib" removed. + + + + + + + + SLXHTML 1.2: attributeGroup "style.attrib" removed. + + + + + + + + + + Extended Global Core Attributes + + + + + Extended Global I18n attributes + + + + + Extended Global Common Attributes + + + + + + + SLXHTML 1.2: elements "script", "meta", "link", "object" removed. + + + + + + + + + + + SLXHTML 1.2: Only a single instance of element "style" is + allowed apart from the obligatory "title" element. + + + + + + + + + + + + SLXHTML 1.2: elements "ins", "del" removed. + + + + + + + + + SLXHTML 1.2: elements "script", "noscript" removed. + + + + + + + + + + + + + + + + + + + + + + + + + + SLXHTML 1.2: elements "dfn", "samp", "kbd", "var", "q" , "abbr" and + "acronym" removed. + + + + + + + + + + + + + SLXHTML 1.2: elements "tt", "i", "b", "big", "small", "sub", "sup" removed. + + + + + + + + SLXHTML 1.2: element "bdo" removed. + + + + + + + + SLXHTML 1.2: element "a" removed. + + + + + + + + SLXHTML 1.2: elements "map", "object" removed. + + + + + + + + + + SLXHTML 1.2: elements "input", "select", "textara", "lable", "button" removed. + + + + + + + + + + + SLXHTML 1.2: element "ruby" removed. + + + + + + + + + + + + + + + + + + + + + + SLXHTML 1.2: elements "tt", "i", "b", "script", "map" removed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SLXHTML 1.2: element "form" removed. + + + + + + + + + SLXHTML 1.2: element "fieldset" removed. + + + + + + + + + + + + + + + + SLXHTML 1.2: element "address" removed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/slxhtml-modules-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/slxhtml-modules-1.xsd new file mode 100644 index 00000000..016833be --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/slxhtml-modules-1.xsd @@ -0,0 +1,248 @@ + + + + + + + This XML Schema declares changes to the content models + of modules included in SLXHTML 1.2 + + + + + + + Module Content Model Redefinitions + + This schema describes the changes (Redefinitions) to the + content model of individual modules as they are instantiated as part of + SLXHTML 1.2 Document + + + + + + + + + + + + + Redefinition by SLXHTML 1.2: Removed xml:lang attrib. + + + + + + + + + Redefinition by SLXHTML 1.2: Removed title attrib. + + + + + + + + + + + + + + + + + + Redefinition by SLXHTML 1.2: Removed cite attrib. + + + + + + + + + + + + + + + + + + + + + Redefinition by SLXHTML 1.2: Change value of the version attrib. + + + + + + + + + Redefinition by SLXHTML 1.2: Removed profile attrib. + + + + + + + + + + + + + + + + + Redefinition by SLXHTML 1.2: Removed attributes "longdesc", "height", "width". + + + + + + + + + + + + + + + + + + + Redefinition by SLXHTML 1.2: + Removed attribute group "title" + Removed attribute "xml:space" + Fixed value of attribute "type" + Fixed value of attribute "media" + + + + + + + + + + + + + + + + + + + Redefinition by SLXHTML 1.2: + Removed attribute groups "scope.attrib", "CellHAlign.attrib", "CellVAlign.attrib" + Removed attributes "abbr", "axis", "headers" + + + + + + + + + + + Redefinition by SLXHTML 1.2: + Removed attribute groups "scope.attrib", "CellHAlign.attrib", "CellVAlign.attrib" + Removed attributes "abbr", "axis", "headers" + + + + + + + + + + + Redefinition by SLXHTML 1.2: + Removed attribute groups "CellHAlign.attrib", "CellVAlign.attrib" + + + + + + + + + Redefinition by SLXHTML 1.2: + Removed attribute groups "CellHAlign.attrib", "CellVAlign.attrib" + Removed attributes "span", "width" + + + + + + + + + Redefinition by SLXHTML 1.2: + Removed attribute groups "CellHAlign.attrib", "CellVAlign.attrib" + Removed attributes "span", "width" + + + + + + + + + Redefinition by SLXHTML 1.2: + Removed attribute groups "CellHAlign.attrib", "CellVAlign.attrib" + + + + + + + + + Redefinition by SLXHTML 1.2: + Removed attribute groups "CellHAlign.attrib", "CellVAlign.attrib" + + + + + + + + + Redefinition by SLXHTML 1.2: + Removed attribute groups "CellHAlign.attrib", "CellVAlign.attrib" + + + + + + + + + Redefinition by SLXHTML 1.2: + Removed attribute groups "frame.attrib", "rules.attrib" + Removed attributes "summary", "width", "border", "cellspacing", "cellpadding" + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/slxhtml.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/slxhtml.xsd new file mode 100644 index 00000000..555edb52 --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/slxhtml.xsd @@ -0,0 +1,70 @@ + + + + + This is the XML Schema driver for SLXHTML 1.2. + SLXHTML is a profile of XHTML (see W3C copyright notice below). + + @author: Gregor Karlinger gregor.karlinger@cio.gv.at + $Id: slxhtml.xsd,v 1.3 2004/05/12 11:35:31 karlinger Exp $ + + + + + This is the Schema Driver file for SLXHTML 1.2 + Document Type + + This schema includes + + modules for SLXHTML 1.2 Document Type. + + + schema that defines all the named model for + the SLXHTML 1.2 Document Type + + + schema that redefines the content model of + individual elements defined in the Module + implementations. + + SLXHTML 1.2 Document Type includes the following Modules + + XHTML Core modules + + text + + lists + + structure + + Other XHTML modules + + Style + + Image + + Tables + + + + + + + + This import brings in the XML namespace attributes + The XML attributes are used by various modules + + + + + + + + This schema redefines the content model defined by + the individual modules for SLXHTML 1.2 Document Type + + + + + + + + Document Model module for the SLXHTML 1.2 Document Type. + This schema file defines all named models used by XHTML + Modularization Framework for SLXHTML 1.2 Document Type + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-attribs-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-attribs-1.xsd new file mode 100644 index 00000000..df5ce483 --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-attribs-1.xsd @@ -0,0 +1,72 @@ + + + + + + + This is the XML Schema common attributes module for XHTML + $Id: xhtml-attribs-1.xsd,v 1.6 2005/09/26 23:37:47 ahby Exp $ + + + + + + + + This import brings in the XML namespace attributes + The module itself does not provide the schemaLocation + and expects the driver schema to provide the + actual SchemaLocation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-blkphras-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-blkphras-1.xsd new file mode 100644 index 00000000..da15e4c1 --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-blkphras-1.xsd @@ -0,0 +1,161 @@ + + + + + + + + + This is the XML Schema Block Phrasal support module for XHTML + $Id: xhtml-blkphras-1.xsd,v 1.6 2006/09/11 10:27:50 ahby Exp $ + + + + + + Block Phrasal + This module declares the elements and their attributes used to + support block-level phrasal markup. + This is the XML Schema block phrasal elements module for XHTML + + * address, blockquote, pre, h1, h2, h3, h4, h5, h6 + + + + + + + This import brings in the XML namespace attributes + The module itself does not provide the schemaLocation + and expects the driver schema to provide the + actual SchemaLocation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-blkpres-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-blkpres-1.xsd new file mode 100644 index 00000000..cf42303a --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-blkpres-1.xsd @@ -0,0 +1,37 @@ + + + + + + This is the XML SchemaBlock presentation element module for XHTML + $Id: xhtml-blkpres-1.xsd,v 1.2 2005/09/26 22:54:53 ahby Exp $ + + + + + Block Presentational Elements + + * hr + + This module declares the elements and their attributes used to + support block-level presentational markup. + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-blkstruct-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-blkstruct-1.xsd new file mode 100644 index 00000000..1e658580 --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-blkstruct-1.xsd @@ -0,0 +1,49 @@ + + + + + + Block Structural + + * div, p + + This module declares the elements and their attributes used to + support block-level structural markup. + + This is the XML Schema Block Structural module for XHTML + $Id: xhtml-blkstruct-1.xsd,v 1.3 2005/09/26 22:54:53 ahby Exp $ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-datatypes-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-datatypes-1.xsd new file mode 100644 index 00000000..5943cf35 --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-datatypes-1.xsd @@ -0,0 +1,175 @@ + + + + + XHTML Datatypes + This is the XML Schema datatypes module for XHTML + + Defines containers for the XHTML datatypes, many of + these imported from other specifications and standards. + + $Id: xhtml-datatypes-1.xsd,v 1.9 2008/06/04 20:58:09 ahby Exp $ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-framework-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-framework-1.xsd new file mode 100644 index 00000000..05b906d4 --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-framework-1.xsd @@ -0,0 +1,66 @@ + + + + + This is the XML Schema Modular Framework support module for XHTML + $Id: xhtml-framework-1.xsd,v 1.5 2005/09/26 23:37:47 ahby Exp $ + + + + + + XHTML Modular Framework + This required module instantiates the necessary modules + needed to support the XHTML modularization framework. + + The Schema modules instantiated are: + + notations + + datatypes + + common attributes + + character entities + + + + + + + + This module defines XHTML Attribute DataTypes + + + + + + + + This module defines Common attributes for XHTML + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-image-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-image-1.xsd new file mode 100644 index 00000000..cd16bc9b --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-image-1.xsd @@ -0,0 +1,45 @@ + + + + + + + Images + This is the XML Schema Images module for XHTML + + * img + + This module provides markup to support basic image embedding. + + To avoid problems with text-only UAs as well as to make + image content understandable and navigable to users of + non-visual UAs, you need to provide a description with + the 'alt' attribute, and avoid server-side image maps. + + + $Id: xhtml-image-1.xsd,v 1.2 2005/09/26 22:54:53 ahby Exp $ + + + + + + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-inlphras-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-inlphras-1.xsd new file mode 100644 index 00000000..919c59de --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-inlphras-1.xsd @@ -0,0 +1,163 @@ + + + + + + + This is the XML Schema Inline Phrasal support module for XHTML + $Id: xhtml-inlphras-1.xsd,v 1.4 2005/09/26 22:54:53 ahby Exp $ + + + + + + Inline Phrasal. + This module declares the elements and their attributes used to + support inline-level phrasal markup. + This is the XML Schema Inline Phrasal module for XHTML + + * abbr, acronym, cite, code, dfn, em, kbd, q, samp, strong, var + + $Id: xhtml-inlphras-1.xsd,v 1.4 2005/09/26 22:54:53 ahby Exp $ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-inlpres-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-inlpres-1.xsd new file mode 100644 index 00000000..a053447c --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-inlpres-1.xsd @@ -0,0 +1,39 @@ + + + + + + This is the XML Schema Inline Presentation element module for XHTML + $Id: xhtml-inlpres-1.xsd,v 1.2 2005/09/26 22:54:53 ahby Exp $ + + + + + + Inline Presentational Elements + + * b, big, i, small, sub, sup, tt + + This module declares the elements and their attributes used to + support inline-level presentational markup. + + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-inlstruct-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-inlstruct-1.xsd new file mode 100644 index 00000000..635eb5f1 --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-inlstruct-1.xsd @@ -0,0 +1,50 @@ + + + + + + This is the XML Schema Inline Structural support module for XHTML + $Id: xhtml-inlstruct-1.xsd,v 1.4 2005/09/26 22:54:53 ahby Exp $ + + + + + + Inline Structural. + This module declares the elements and their attributes + used to support inline-level structural markup. + This is the XML Schema Inline Structural element module for XHTML + + * br, span + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-list-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-list-1.xsd new file mode 100644 index 00000000..cc22ba88 --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-list-1.xsd @@ -0,0 +1,99 @@ + + + + + + List Module + This is the XML Schema Lists module for XHTML + List Module Elements + + * dl, dt, dd, ol, ul, li + + This module declares the list-oriented element types + and their attributes. + $Id: xhtml-list-1.xsd,v 1.2 2005/09/26 22:54:53 ahby Exp $ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-pres-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-pres-1.xsd new file mode 100644 index 00000000..bc36fc48 --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-pres-1.xsd @@ -0,0 +1,51 @@ + + + + + + This is the XML Schema Presentation module for XHTML + This is a REQUIRED module. + $Id: xhtml-pres-1.xsd,v 1.2 2005/09/26 22:54:53 ahby Exp $ + + + + + + Presentational Elements + + This module defines elements and their attributes for + simple presentation-related markup. + + Elements defined here: + + * hr + * b, big, i, small, sub, sup, tt + + + + + + + Block Presentational module + Elements defined here: + + * hr + + + + + + + Inline Presentational module + Elements defined here: + + * b, big, i, small, sub, sup, tt + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-struct-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-struct-1.xsd new file mode 100644 index 00000000..60cbcbf5 --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-struct-1.xsd @@ -0,0 +1,116 @@ + + + + + + This is the XML Schema Document Structure module for XHTML + Document Structure + + * title, head, body, html + + The Structure Module defines the major structural elements and + their attributes. + + $Id: xhtml-struct-1.xsd,v 1.8 2006/09/11 10:27:50 ahby Exp $ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-style-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-style-1.xsd new file mode 100644 index 00000000..1b3e7d3b --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-style-1.xsd @@ -0,0 +1,53 @@ + + + + + + + This is the XML Schema Stylesheets module for XHTML + $Id: xhtml-style-1.xsd,v 1.5 2006/09/11 10:14:57 ahby Exp $ + + + + + + Stylesheets + + * style + + This module declares the style element type and its attributes, + used to embed stylesheet information in the document head element. + + + + + + + This import brings in the XML namespace attributes + The module itself does not provide the schemaLocation + and expects the driver schema to provide the + actual SchemaLocation. + + + + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-table-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-table-1.xsd new file mode 100644 index 00000000..ec76db3c --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-table-1.xsd @@ -0,0 +1,272 @@ + + + + + + + This is the XML Schema Tables module for XHTML + $Id: xhtml-table-1.xsd,v 1.3 2005/09/26 22:54:53 ahby Exp $ + + + + + + Tables + + * table, caption, thead, tfoot, tbody, colgroup, col, tr, th, td + + This module declares element types and attributes used to provide + table markup similar to HTML 4.0, including features that enable + better accessibility for non-visual user agents. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-text-1.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-text-1.xsd new file mode 100644 index 00000000..432bdad7 --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xhtml-text-1.xsd @@ -0,0 +1,67 @@ + + + + + + Textual Content + This is the XML Schema Text module for XHTML + + The Text module includes declarations for all core + text container elements and their attributes. + + + block phrasal + + block structural + + inline phrasal + + inline structural + + $Id: xhtml-text-1.xsd,v 1.2 2005/09/26 22:54:53 ahby Exp $ + + + + + + + + Block Phrasal module + Elements defined here: + + * address, blockquote, pre, h1, h2, h3, h4, h5, h6 + + + + + + + Block Structural module + Elements defined here: + + * div, p + + + + + + + Inline Phrasal module + Elements defined here: + + * abbr, acronym, cite, code, dfn, em, kbd, q, samp, strong, var + + + + + + + Inline Structural module + Elements defined here: + + * br,span + + + + diff --git a/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xml.xsd b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xml.xsd new file mode 100644 index 00000000..eeb9db56 --- /dev/null +++ b/BKUViewer/src/main/resources/at/gv/egiz/bku/slxhtml/xml.xsd @@ -0,0 +1,145 @@ + + + + + + See http://www.w3.org/XML/1998/namespace.html and + http://www.w3.org/TR/REC-xml for information about this namespace. + + This schema document describes the XML namespace, in a form + suitable for import by other schema documents. + + Note that local names in this namespace are intended to be defined + only by the World Wide Web Consortium or its subgroups. The + following names are currently defined in this namespace and should + not be used with conflicting semantics by any Working Group, + specification, or document instance: + + base (as an attribute name): denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification. + + id (as an attribute name): denotes an attribute whose value + should be interpreted as if declared to be of type ID. + This name is reserved by virtue of its definition in the + xml:id specification. + + lang (as an attribute name): denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification. + + space (as an attribute name): denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification. + + Father (in any context at all): denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: + + In appreciation for his vision, leadership and dedication + the W3C XML Plenary on this 10th day of February, 2000 + reserves for Jon Bosak in perpetuity the XML name + xml:Father + + + + + This schema defines attributes and an attribute group + suitable for use by + schemas wishing to allow xml:base, xml:lang, xml:space or xml:id + attributes on elements they define. + + To enable this, such a schema must import this schema + for the XML namespace, e.g. as follows: + <schema . . .> + . . . + <import namespace="http://www.w3.org/XML/1998/namespace" + schemaLocation="http://www.w3.org/2001/xml.xsd"/> + + Subsequently, qualified reference to any of the attributes + or the group defined below will have the desired effect, e.g. + + <type . . .> + . . . + <attributeGroup ref="xml:specialAttrs"/> + + will define a type which will schema-validate an instance + element with any of those attributes + + + + In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + http://www.w3.org/2007/08/xml.xsd. + At the date of issue it can also be found at + http://www.w3.org/2001/xml.xsd. + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML Schema + itself, or with the XML namespace itself. In other words, if the XML + Schema or XML namespaces change, the version of this document at + http://www.w3.org/2001/xml.xsd will change + accordingly; the version at + http://www.w3.org/2007/08/xml.xsd will not change. + + + + + + Attempting to install the relevant ISO 2- and 3-letter + codes as the enumerated possible values is probably never + going to be a realistic possibility. See + RFC 3066 at http://www.ietf.org/rfc/rfc3066.txt and the IANA registry + at http://www.iana.org/assignments/lang-tag-apps.htm for + further information. + + The union allows for the 'un-declaration' of xml:lang with + the empty string. + + + + + + + + + + + + + + + + + + + + + + + + See http://www.w3.org/TR/xmlbase/ for + information about this attribute. + + + + + + See http://www.w3.org/TR/xml-id/ for + information about this attribute. + + + + + + + + + + + diff --git a/BKUViewer/src/main/resources/org/w3c/css/properties/Config.properties b/BKUViewer/src/main/resources/org/w3c/css/properties/Config.properties new file mode 100644 index 00000000..0ece8cda --- /dev/null +++ b/BKUViewer/src/main/resources/org/w3c/css/properties/Config.properties @@ -0,0 +1,32 @@ +# configuration file for org.w3c.css.parser.CssFouffa +# Properties should be in the style directory + +# Is the parser should run in CSS2 ? +extended-parser: true + +# the CssStyle to use +#style for CSS1 +css1: org.w3c.css.properties.css1.Css1Style +#style for CSS2 (and mobile profile and TV profile) +css2: org.w3c.css.properties.css2.font.Css2Style +#style for CSS2.1 +css21: org.w3c.css.properties.css21.Css21Style +#style for CSS3 +css3: org.w3c.css.properties.css3.Css3Style +#SVG styles +svg : org.w3c.css.properties.svg.SVGStyle +svgbasic : org.w3c.css.properties.svg.SVGBasicStyle +svgtiny : org.w3c.css.properties.svg.SVGTinyStyle +#ATSC style +atsc-tv: org.w3c.css.properties.atsc.ATSCStyle +#SLXHMTL +slxhtml: at.gv.egiz.bku.slxhtml.css.SLXHTMLStyle + +#media +media: Media.properties + +# file containing the properties files for each profile +profilesProperties: ProfilesProperties.properties + +#default profile +defaultProfile: css21 diff --git a/BKUViewer/src/main/resources/org/w3c/css/properties/ProfilesProperties.properties b/BKUViewer/src/main/resources/org/w3c/css/properties/ProfilesProperties.properties new file mode 100644 index 00000000..8c2aded8 --- /dev/null +++ b/BKUViewer/src/main/resources/org/w3c/css/properties/ProfilesProperties.properties @@ -0,0 +1,30 @@ +# The list of properties to use + +# properties for CSS1 +css1 : CSS1Properties.properties + +# properties for CSS2 +css2 : CSS2Properties.properties + +# properties for CSS2.1 +css21 : CSS21Properties.properties + +# properties for CSS3 +css3 : CSS3Properties.properties + +# properties for mobile profile +mobile : MobileProperties.properties + +# properties for ATSC TV profile +atsc-tv : ATSCProperties.properties + +# properties for TV profile +tv : TVProperties.properties + +# properties for SVG profiles +svg : SVGProperties.properties +svgbasic : SVGBasicProperties.properties +svgtiny : SVGTinyProperties.properties + +# properties for SLXHTML profile +slxhtml : SLXHTMLProperties.properties diff --git a/BKUViewer/src/main/resources/org/w3c/css/properties/SLXHTMLProperties.properties b/BKUViewer/src/main/resources/org/w3c/css/properties/SLXHTMLProperties.properties new file mode 100644 index 00000000..dec68c11 --- /dev/null +++ b/BKUViewer/src/main/resources/org/w3c/css/properties/SLXHTMLProperties.properties @@ -0,0 +1,641 @@ +# All properties for all media + +# CSS2 Properties + +# Margin spacing +# +# The margin-top, margin-bottom, margin-left and margin-right properties +# must be supported by a Citizen Card Environment. Values specified as percentages +# (cf. section 3.5.1.2) should be supported. +# +# The margin property may be supported by a Citizen Card Environment. +# +# An instance document must not contain a negative value in the properties mentioned +# above. Otherwise it must be rejected by the Citizen Card Environment. + +margin-top: at.gv.egiz.bku.slxhtml.css.CssMarginTopSLXHTML +margin-bottom: at.gv.egiz.bku.slxhtml.css.CssMarginBottomSLXHTML +margin-left: at.gv.egiz.bku.slxhtml.css.CssMarginLeftSLXHTML +margin-right: at.gv.egiz.bku.slxhtml.css.CssMarginRightSLXHTML +margin: at.gv.egiz.bku.slxhtml.css.CssMarginSLXHTML + +# Padding spacing +# +# The padding-top, padding-bottom, padding-left and padding-right properties must be +# supported by a Citizen Card Environment. Values specified as percentages (cf. section +# 3.5.1.2) should be supported. +# +# The padding property may be supported by a Citizen Card Environment. +# +# An instance document must not contain a negative value in the properties +# mentioned above. Otherwise it must be rejected by the Citizen Card Environment. + +padding-top: at.gv.egiz.bku.slxhtml.css.CssPaddingTopSLXHTML +padding-bottom: at.gv.egiz.bku.slxhtml.css.CssPaddingBottomSLXHTML +padding-left: at.gv.egiz.bku.slxhtml.css.CssPaddingLeftSLXHTML +padding-right: at.gv.egiz.bku.slxhtml.css.CssPaddingRightSLXHTML +padding: at.gv.egiz.bku.slxhtml.css.CssPaddingSLXHTML + +# +# Borders +# + +# Border width +# +# The border-top-width, border-bottom-width, border-left-width, border-right-width +# and border-width properties should be supported by a Citizen Card Environment. If +# the properties are supported, the predefined values thin, medium and thick should +# also be supported (cf. [CSS 2], section 8.5.1). + +border-top-width: org.w3c.css.properties.css1.CssBorderTopWidthCSS2 +border-right-width: org.w3c.css.properties.css1.CssBorderRightWidthCSS2 +border-left-width: org.w3c.css.properties.css1.CssBorderLeftWidthCSS2 +border-bottom-width: org.w3c.css.properties.css1.CssBorderBottomWidthCSS2 + +# Border colour +# +# The border-top-color, border-bottom-color, border-left-color, border-right-color +# and border-color properties should be supported by a Citizen Card Environment. The +# predefined value transparent for the border-color property may be supported (cf. +# [CSS 2], section 8.5.2). + +border-top-color: at.gv.egiz.bku.slxhtml.css.CssBorderTopColorSLXHTML +border-right-color: at.gv.egiz.bku.slxhtml.css.CssBorderRightColorSLXHTML +border-left-color: at.gv.egiz.bku.slxhtml.css.CssBorderLeftColorSLXHTML +border-bottom-color: at.gv.egiz.bku.slxhtml.css.CssBorderBottomColorSLXHTML + +# Border style +# +# The border-top-style, border-bottom-style, border-left-style, border-right-style and +# border-style properties should be supported by a Citizen Card Environment. If the properties +# are supported, the predefined values none, dashed, dotted, solid and double should also +# be supported; all other values may be supported (cf. [CSS 2], section 8.5.3). + +border-top-style: org.w3c.css.properties.css1.CssBorderTopStyleCSS2 +border-right-style: org.w3c.css.properties.css1.CssBorderRightStyleCSS2 +border-left-style: org.w3c.css.properties.css1.CssBorderLeftStyleCSS2 +border-bottom-style: org.w3c.css.properties.css1.CssBorderBottomStyleCSS2 + +# Shorthand +# +# The properties for the shorthand version of the border properties (border-top, +# border-bottom, border-left, border-right and border (cf. [CSS 2], section 8.5.4) +# should be supported by a Citizen Card Environment. The recommended values result +# from the three previous sections. + +border-width: org.w3c.css.properties.css1.CssBorderWidthCSS2 +border-color: at.gv.egiz.bku.slxhtml.css.CssBorderColorSLXHTML +border-style: org.w3c.css.properties.css1.CssBorderStyleCSS2 +border-top: org.w3c.css.properties.css1.CssBorderTopCSS2 +border-right: org.w3c.css.properties.css1.CssBorderRightCSS2 +border-left: org.w3c.css.properties.css1.CssBorderLeftCSS2 +border-bottom: org.w3c.css.properties.css1.CssBorderBottomCSS2 +border: at.gv.egiz.bku.slxhtml.css.CssBorderSLXHTML + +# +# Positioning of boxes +# + +# Box type +# +# The property for controlling the box type (display) may be supported by a Citizen +# Card Environment (cf. [CSS 2], section 9.2). + +display: org.w3c.css.properties.css1.CssDisplayCSS2 + +# Positioning scheme +# +# The property for defining the positioning scheme for a box (position, cf. [CSS 2], +# section 9.3) must not be contained in an instance document to prevent content +# from overlapping. Otherwise the instance document must be rejected by the Citizen +# Card Environment. + +#! position: org.w3c.css.properties.css1.CssPosition + +# Box spacing +# +# The property for defining the positioning scheme for a box (top, bottom, left, right; +# cf. [CSS 2], section 9.3) must not be contained in an instance document to prevent +# content from overlapping. Otherwise the instance document must be rejected by the +# Citizen Card Environment. + +#! top: org.w3c.css.properties.css1.CssTop +#! right: org.w3c.css.properties.css1.CssRight +#! left: org.w3c.css.properties.css1.CssLeft +#! bottom: org.w3c.css.properties.css1.CssBottom + +# Flow around boxes +# +# The properties for defining the flow around boxes (float, clear) may be supported by +# a Citizen Card Environment (cf. [CSS 2], section 9.5). + +float: org.w3c.css.properties.css1.CssFloat +clear: org.w3c.css.properties.css1.CssClear + +# Positioning of boxes on the z-axis +# +# The property for defining the positioning of boxes on the z-axis (z-index, cf. [CSS 2], +# section 9.9) must not be contained in an instance document to prevent content from +# overlapping. Otherwise the instance document must be rejected by the Citizen Card Environment. + +#! z-index: org.w3c.css.properties.css1.CssZIndex + +# Text direction +# +# The properties for controlling the text direction (direction, unicode-bidi) may be +# supported by a Citizen Card Environment (cf. [CSS 2], section 9.10). + +direction: org.w3c.css.properties.css1.CssDirection +unicode-bidi: org.w3c.css.properties.css1.CssUnicodeBidi + +# +# Displaying boxes +# + +# Width and height +# +# The properties for specifying the width and height of a box (width, height, cf. [CSS 2], +# sections 10.2 and 10.5) must not be supported by a Citizen Card Environment to prevent +# content from overlapping. Otherwise the instance document must be rejected by the +# Citizen Card Environment. +# +# The properties for specifying the minimum width and height of a box (min-width, min-height) +# may be supported by a Citizen Card Environment (cf. [CSS 2], sections 10.4 and 10.7). +# +# The properties for specifying the maximum width and height of a box (max-width, max-height, +# cf. [CSS 2], sections 10.4 and 10.7) must not be supported by a Citizen Card Environment +# to prevent content from overlapping. Otherwise the instance document must be rejected by +# the Citizen Card Environment. + +#! width: org.w3c.css.properties.css1.CssWidth +min-width: org.w3c.css.properties.css1.CssMinWidth +#! max-width: org.w3c.css.properties.css1.CssMaxWidth +min-height: org.w3c.css.properties.css1.CssMinHeight +#! max-height: org.w3c.css.properties.css1.CssMaxHeight +#! height: org.w3c.css.properties.css1.CssHeight + +# Line height +# +# The properties for specifying the line height (line-height, vertical-align) should be +# supported by a Citizen Card (cf. [CSS 2], section 10.8). The only exception is the +# vertical-align property: In this case a Citizen Card Environment must be able to interpret +# the values sub and super. + +line-height: org.w3c.css.properties.css1.CssLineHeightCSS2 +vertical-align: org.w3c.css.properties.css1.CssVerticalAlign + +# +# Visible area in boxes +# + +# The property for specifying the visibility of a box (visibility) may be supported by a +# Citizen Card Environment (cf. [CSS 2], section 11). +# +# The properties for controlling the visible area of a box (overflow, clip; cf. [CSS 2], +# section 11) must not be contained in an instance document to prevent hidden content. Otherwise +# the instance document must be rejected by the Citizen Card Environment. + +#! overflow: org.w3c.css.properties.css1.CssOverflow +#! clip: org.w3c.css.properties.css1.CssClip +visibility: org.w3c.css.properties.css1.CssVisibility + +# +# Generated content, numbering, lists +# + +# Generated content +# +# The property for generating content (content) may be supported by a Citizen Card Environment +# (cf. [CSS 2], section 12.2). + +content: org.w3c.css.properties.css1.CssContentCSS2 + +# Displaying quotation marks +# +# The property for displaying quotation marks (quotes) may be supported by a Citizen Card +# Environment (cf. [CSS 2], section 12.3). + +quotes: org.w3c.css.properties.css1.CssQuotes + +# Numbering +# +# The properties for automatic numbering (counter-reset, counter-increment) may be supported +# by a Citizen Card Environment (cf. [CSS 2], section 12.5). + +counter-reset: org.w3c.css.properties.css1.CssCounterReset +counter-increment: org.w3c.css.properties.css1.CssCounterIncrement + +# +# Markers and lists +# + +# Marker spacing +# +# The property for defining the space between a marker and the associated box +# (marker-offset) may be supported by a Citizen Card Environment (cf. [CSS 2], +# section 12.6.1). + +marker-offset: org.w3c.css.properties.css1.CssMarkerOffset + +# List symbols +# +# For the property for selecting the list symbol (list-style-type) a Citizen +# Card Environment must support the values none, disc, circle, square, decimal, +# decimal-leading-zero, lower-roman, upper-roman, lower-alpha, lower-latin, +# upper-alpha and upper-latin. The other values may be supported (cf. [CSS 2], +# section 12.6.2). + +list-style-type: org.w3c.css.properties.css1.CssListStyleTypeCSS2 + +# Position of the list symbol +# +# The property for positioning the list symbol in relation to the associated box +# (list-style-position) should be supported by a Citizen Card Environment (cf. [CSS 2], +# section 12.6.2). + +list-style-position: org.w3c.css.properties.css1.CssListStylePositionCSS2 + +# Image as a list symbol +# +# The property for selecting an image as a list symbol (list-style-image) may be supported +# by a Citizen Card Environment (cf. [CSS 2], section 12.6.2). If the Citizen Card Environment +# supports this property, then it must proceed in respect of the integration of the image +# in the signature as described in section 2.1.7. + +# optional, not supported: +#! list-style-image: org.w3c.css.properties.css1.CssListStyleImageCSS2 + +# Shorthand +# +# The property for the shorthand version of the list properties (list-style) should be supported +# by a Citizen Card Environment. The recommended values result from the explanations for the +# list-style-type, list-style-position and list-style-image properties above (cf. [CSS 2], +# section 12.6.2). + +list-style: org.w3c.css.properties.css1.CssListStyleCSS2 + +# Page-based media +# +# The properties for page-based media may be supported by a Citizen Card Environment (size, marks, +# page-break-before, page-break-inside, page-break-after, page, orphans and widows (cf. [CSS 2], +# section 13). + +page-break-before: org.w3c.css.properties.paged.PageBreakBefore +page-break-after: org.w3c.css.properties.paged.PageBreakAfter +page-break-inside: org.w3c.css.properties.paged.PageBreakInside +page: org.w3c.css.properties.paged.Page +orphans: org.w3c.css.properties.paged.Orphans +widows: org.w3c.css.properties.paged.Widows + +@page.size: org.w3c.css.properties.paged.Size +@page.marks: org.w3c.css.properties.paged.Marks +@page.page-break-before: org.w3c.css.properties.paged.PageBreakBefore +@page.page-break-after: org.w3c.css.properties.paged.PageBreakAfter +@page.page-break-inside: org.w3c.css.properties.paged.PageBreakInside +@page.page: org.w3c.css.properties.paged.Page +@page.orphans: org.w3c.css.properties.paged.Orphans +@page.widows: org.w3c.css.properties.paged.Widows + + +# +# Colours and background +# + +# A Citizen Card Environment must support all the options for specifying a colour listed in [CSS 2], +# section 4.3.6 for a CSS property, if such an option is available for this property according to [CSS 2]. +# +# The exceptions are the system colours (cf. [CSS 2], section 18.2); these must not be used in an +# instance document so as to prevent dependencies on the system environment. Otherwise the instance +# document must be rejected by the Citizen Card Environment. + +# Colour + +# The property for defining the foreground colour of the content of an element (color) must be +# supported by a Citizen Card Environment (cf. [CSS 2], section 14.1). + +color: at.gv.egiz.bku.slxhtml.css.CssColorSLXHTML + +# Background +# +# The property for defining the background colour of the content of an element (background-color) +# must be supported by a Citizen Card Environment (cf. [CSS 2], section 14.2.1). +# +# The properties for selecting and controlling an image as background (background-image, background-repeat, +# background-position, background-attachment; cf. [CSS 2], section 14.2.1) must not be contained in an +# instance document to prevent content from overlapping. Otherwise the instance document must be +# rejected by the Citizen Card Environment. + +# The property for the shorthand version of the background properties (background) should be supported +# by a Citizen Card Environment. The recommended values result from the explanations for the background-color +# property above (cf. [CSS 2], section 14.2.1). If the property contains values for selecting and controlling +# an image as background, the instance document must be rejected by the Citizen Card Environment. + +background-color: at.gv.egiz.bku.slxhtml.css.CssBackgroundColorSLXHTML +#! background-image: org.w3c.css.properties.css1.CssBackgroundImageCSS2 +#! background-repeat: org.w3c.css.properties.css1.CssBackgroundRepeatCSS2 +#! background-attachment: org.w3c.css.properties.css1.CssBackgroundAttachmentCSS2 +#! background-position: org.w3c.css.properties.css1.CssBackgroundPositionCSS2 +background: at.gv.egiz.bku.slxhtml.css.CssBackgroundSLXHTML + +# +# Fonts +# +# +# For the property for selecting a font family (font-family), a Citizen Card Environment must +# support the predefined values serif, sans-serif and monospaced for the general font families. +# All other values may be supported by a Citizen Card Environment (cf. [CSS 2], section 15.2.2). +# +# If a preferred font family is specified in the instance document that cannot be displayed by the +# Citizen Card Environment, then the Citizen Card Environment may still display the instance +# document if another displayable font family has been specified as an alternative. For example, +# if the specification in the instance document is font-family: "Times New Roman", serif, then the +# Citizen Card Environment may display the instance document in the secure viewer even if it does +# not know the Times New Roman font family (as it must always support serif). + +font-family: org.w3c.css.properties.css1.CssFontFamilyCSS2 + +# Font style +# +# The properties for defining the font style (font-style) and font weight (font-weight) +# must be supported by a Citizen Card Environment. The values normal and italic must be supported, +# while the value oblique should be supported. +# +# The property for defining the font variant (font-variant) should be supported by a Citizen Card +# Environment, while the property for defining the font stretch (font-stretch) may be supported +# by a Citizen Card Environment (cf. [CSS 2], section 15.2.3). + +font-style: org.w3c.css.properties.css1.CssFontStyleCSS2 +font-weight: org.w3c.css.properties.css1.CssFontWeightCSS2 +font-variant: org.w3c.css.properties.css1.CssFontVariantCSS2 +font-stretch: org.w3c.css.properties.css1.CssFontStretchCSS2 + +# Font size +# +# The property for specifying the font size (font-size) must be supported by a Citizen +# Card Environment. The property for specifying the stretch ratio (font-size-adjust) may +# be supported by a Citizen Card Environment (cf. [CSS 2], section 15.2.4). + +font-size: org.w3c.css.properties.css1.CssFontSizeCSS2 +font-size-adjust: org.w3c.css.properties.css1.CssFontSizeAdjustCSS2 + +# Shorthand +# +# The property for the shorthand version of the font properties (font) should be supported by +# a Citizen Card Environment (cf. [CSS 2], section 15.2.5). The recommended values result from +# the explanations above for the font-style, font-variant, font-weight, font-size and font-family +# properties and the explanations for the line-height property in section 3.5.4.2. +# +# The additional, predefined values relating to the system fonts used (caption, icon, etc.) must +# not be contained in an instance document so as to prevent dependencies on the system environment. +# Otherwise the instance document must be rejected by the Citizen Card Environment. + +font: at.gv.egiz.bku.slxhtml.css.CssFontSLXHTML + +# +# Displaying text +# + +# Non-displayable characters +# +# If the text of an instance document contains a character that cannot be displayed by the +# Citizen Card Environment, then the instance document must be rejected by the Citizen Card +# Environment. The character must not be represented by a placeholder. + +# FIXME: How to implement?! + +# Indent +# +# The property for indenting the first line of a text block (text-indent) should be supported +# by a Citizen Card Environment (cf. [CSS 2], section 16.1). + +text-indent: org.w3c.css.properties.css1.CssTextIndent + +# Alignment +# +# For the property for aligning the content of a text block (text-align) a Citizen Card Environment +# must support the values left, right and center. The value justified should be supported, +# while the specification of a string value may be supported (cf. [CSS 2], section 16.2). + +text-align: org.w3c.css.properties.css1.CssTextAlign + +# Text decoration +# +# For the property for decorating a text (text-decoration; cf. [CSS 2], section 16.3.1) a +# Citizen Card Environment must support the values none, underline and line-through. +# +# The value blink must not be contained in an instance document. Otherwise the instance +# document must be rejected by the Citizen Card Environment. +# +# The other values may be supported by a Citizen Card Environment. + +text-decoration: at.gv.egiz.bku.slxhtml.css.CssTextDecorationSLXHTML + +# Shadows +# +# The property for specifying a text shadow (text-shadow) may be supported by a Citizen Card +# Environment (cf. [CSS 2], section 16.3.2). + +text-shadow: org.w3c.css.properties.css1.CssTextShadow + +# Word and letter spacing +# +# The word-spacing and letter-spacing should be supported by a Citizen Card Environment +# (cf. [CSS 2], section 16.4). +# +# An instance document must not contain negative values in order to prevent content from +# overlapping. Otherwise the instance document must be rejected by the Citizen Card Environment. + +word-spacing: at.gv.egiz.bku.slxhtml.css.CssWordSpacingSLXHTML +letter-spacing: at.gv.egiz.bku.slxhtml.css.CssLetterSpacingSLXHTML + +# Capitalisation +# +# The property for specifying the capitalisation of the text of an element (text-transform) +# may be supported by a Citizen Card Environment (cf. [CSS 2], section 16.5). + +text-transform: org.w3c.css.properties.css1.CssTextTransform + +# White space +# +# The property for the handling of white space within the text of an element (white-space) should +# be supported by a Citizen Card Environment (cf. [CSS 2], section 16.6). + +white-space: org.w3c.css.properties.css1.CssWhiteSpace + +# +# Tables +# + +# Position of caption +# +# A Citizen Card Environment should support the top and bottom properties for the property for +# specifying the position when labelling a table (caption-side); the properties left and right +# may be supported (cf. [CSS 2], section 17.4.1). + +caption-side: org.w3c.css.properties.css2.table.CaptionSide + +# Layout algorithm +# +# The property for defining the layout algorithm for a table (table-layout) may be supported by +# a Citizen Card Environment (cf. [CSS 2], section 17.5.2). +# +# However, the fixed value must not be supported because the layout algorithm selected with it can +# cause content to overlap. +# +# In general, the viewer component of the Citizen Card Environment must use a layout algorithm for a +# table that does not generate an overflow, in other words with which the content of every table +# element can be rendered so that it does not extend beyond the confines of the table element. +# There is an example of such an algorithm in [CSS 2], section 17.5.2, subsection Automatic table layout. + +table-layout: at.gv.egiz.bku.slxhtml.css.TableLayoutSLXHTML +row-span: org.w3c.css.properties.css2.table.RowSpan +column-span: org.w3c.css.properties.css2.table.ColumnSpan + +# Borders +# +# The properties for displaying borders in tables (border-collapse, border-spacing, empty-cells) may +# be supported by a Citizen Card Environment (cf. [CSS 2], section 17.6). + +border-collapse: org.w3c.css.properties.css2.table.BorderCollapse +border-spacing: org.w3c.css.properties.css2.table.BorderSpacing +empty-cells: org.w3c.css.properties.css2.table.EmptyCells + +# Voice output +# +# The property for controlling the voice output of the column headers in a table (speak-header) may +# be supported by a Citizen Card Environment (cf. [CSS 2], section 17.7.1). + +speak-header: org.w3c.css.properties.css2.table.SpeakHeader + +# +# User interface +# + +# Cursor format +# +# The property for controlling the cursor format (cursor; cf. [CSS 2], section 18.1) must not be +# contained in an instance document. Otherwise the instance document must be rejected by the Citizen +# Card Environment. + +#! cursor: org.w3c.css.properties.css2.user.CursorCSS2 + +# Contours +# +# The properties for defining element contours (outline-width, outline-style, outline-color and +# outline; cf. [CSS 2], section 18.4) must not be contained in an instance document. Otherwise the +# instance document must be rejected by the Citizen Card Environment. + +#! outline: org.w3c.css.properties.css2.user.Outline +#! outline-width: org.w3c.css.properties.css2.user.OutlineWidth +#! outline-style: org.w3c.css.properties.css2.user.OutlineStyle +#! outline-color: org.w3c.css.properties.css2.user.OutlineColor + +# +# Aural Properties +# +# The properties for the voice output of a document (cf. [CSS 2], section 19) may be supported +# by a Citizen Card Environment. + +volume: org.w3c.css.properties.aural.ACssVolume +pause-before: org.w3c.css.properties.aural.ACssPauseBefore +pause-after: org.w3c.css.properties.aural.ACssPauseAfter +pause: org.w3c.css.properties.aural.ACssPause +cue-before: org.w3c.css.properties.aural.ACssCueBefore +cue-after: org.w3c.css.properties.aural.ACssCueAfter +cue: org.w3c.css.properties.aural.ACssCue +play-during: org.w3c.css.properties.aural.ACssPlayDuring +voice-family: org.w3c.css.properties.aural.ACssVoiceFamily +elevation: org.w3c.css.properties.aural.ACssElevation +speech-rate: org.w3c.css.properties.aural.ACssSpeechRate +pitch: org.w3c.css.properties.aural.ACssPitch +pitch-range: org.w3c.css.properties.aural.ACssPitchRange +stress: org.w3c.css.properties.aural.ACssStress +richness: org.w3c.css.properties.aural.ACssRichness +speak-punctuation: org.w3c.css.properties.aural.ACssSpeakPunctuation +speak-date: org.w3c.css.properties.aural.ACssSpeakDate +speak-numeral: org.w3c.css.properties.aural.ACssSpeakNumeral +speak-time: org.w3c.css.properties.aural.ACssSpeakTime +speak: org.w3c.css.properties.aural.ACssSpeak +azimuth: org.w3c.css.properties.aural.ACssAzimuth + +# +# @page +# +# The @page rule for defining the page properties for page-based output media may be +# supported by a Citizen Card Environment (cf. [CSS 2], section 13, and section 3.5.7 +# of this document). +# + +@page.margin-top: org.w3c.css.properties.css1.CssMarginTop +@page.margin-bottom: org.w3c.css.properties.css1.CssMarginBottom +@page.margin-left: org.w3c.css.properties.css1.CssMarginLeft +@page.margin-right: org.w3c.css.properties.css1.CssMarginRight +@page.margin: org.w3c.css.properties.css1.CssMargin +@page.padding-top: org.w3c.css.properties.css1.CssPaddingTop +@page.padding-bottom: org.w3c.css.properties.css1.CssPaddingBottom +@page.padding-left: org.w3c.css.properties.css1.CssPaddingLeft +@page.padding-right: org.w3c.css.properties.css1.CssPaddingRight +@page.padding: org.w3c.css.properties.css1.CssPadding +@page.border-top-width: org.w3c.css.properties.css1.CssBorderTopWidthCSS2 +@page.border-right-width: org.w3c.css.properties.css1.CssBorderRightWidthCSS2 +@page.border-left-width: org.w3c.css.properties.css1.CssBorderLeftWidthCSS2 +@page.border-bottom-width: org.w3c.css.properties.css1.CssBorderBottomWidthCSS2 +@page.border-top-color: org.w3c.css.properties.css1.CssBorderTopColorCSS2 +@page.border-right-color: org.w3c.css.properties.css1.CssBorderRightColorCSS2 +@page.border-left-color: org.w3c.css.properties.css1.CssBorderLeftColorCSS2 +@page.border-bottom-color: org.w3c.css.properties.css1.CssBorderBottomColorCSS2 +@page.border-top-style: org.w3c.css.properties.css1.CssBorderTopStyleCSS2 +@page.border-right-style: org.w3c.css.properties.css1.CssBorderRightStyleCSS2 +@page.border-left-style: org.w3c.css.properties.css1.CssBorderLeftStyleCSS2 +@page.border-bottom-style: org.w3c.css.properties.css1.CssBorderBottomStyleCSS2 +@page.border-width: org.w3c.css.properties.css1.CssBorderWidthCSS2 +@page.border-color: org.w3c.css.properties.css1.CssBorderColorCSS2 +@page.border-style: org.w3c.css.properties.css1.CssBorderStyleCSS2 +@page.border-top: org.w3c.css.properties.css1.CssBorderTopCSS2 +@page.border-right: org.w3c.css.properties.css1.CssBorderRightCSS2 +@page.border-left: org.w3c.css.properties.css1.CssBorderLeftCSS2 +@page.border-bottom: org.w3c.css.properties.css1.CssBorderBottomCSS2 +@page.border: org.w3c.css.properties.css1.CssBorderCSS2 +@page.display: org.w3c.css.properties.css1.CssDisplayCSS2 +@page.position: org.w3c.css.properties.css1.CssPosition +@page.z-index: org.w3c.css.properties.css1.CssZIndex +@page.direction: org.w3c.css.properties.css1.CssDirection +@page.unicode-bidi: org.w3c.css.properties.css1.CssUnicodeBidi +@page.top: org.w3c.css.properties.css1.CssTop +@page.right: org.w3c.css.properties.css1.CssRight +@page.left: org.w3c.css.properties.css1.CssLeft +@page.bottom: org.w3c.css.properties.css1.CssBottom +@page.float: org.w3c.css.properties.css1.CssFloat +@page.clear: org.w3c.css.properties.css1.CssClear + +# +# @font-face +# +# The @font-face rule for describing or referencing additional font families (cf. [CSS 2], +# section 15.3) must not be used in an instance document. The viewer component of the Citizen +# Card Environment must reject an instance document containing a @font-face rule. + +#! @font-face.font-style: org.w3c.css.properties.css2.font.FontStyle +#! @font-face.font-variant: org.w3c.css.properties.css2.font.FontVariant +#! @font-face.font-weight: org.w3c.css.properties.css2.font.FontWeight +#! @font-face.font-size: org.w3c.css.properties.css2.font.FontSize +#! @font-face.font-family: org.w3c.css.properties.css2.font.FontFamily +#! @font-face.font-stretch: org.w3c.css.properties.css2.font.FontStretch +#! @font-face.unicode-range: org.w3c.css.properties.css2.font.UnicodeRange +#! @font-face.units-per-em: org.w3c.css.properties.css2.font.UnitsPerEm +#! @font-face.src: org.w3c.css.properties.css2.font.Src +#! @font-face.panose-1: org.w3c.css.properties.css2.font.Panose1 +#! @font-face.stemv: org.w3c.css.properties.css2.font.Stemv +#! @font-face.stemh: org.w3c.css.properties.css2.font.Stemh +#! @font-face.slope: org.w3c.css.properties.css2.font.Slope +#! @font-face.cap-height: org.w3c.css.properties.css2.font.CapHeight +#! @font-face.x-hegiht: org.w3c.css.properties.css2.font.XHeight +#! @font-face.widths: org.w3c.css.properties.css2.font.Widths +#! @font-face.ascent: org.w3c.css.properties.css2.font.Ascent +#! @font-face.descent: org.w3c.css.properties.css2.font.Descent +#! @font-face.bbox: org.w3c.css.properties.css2.font.Bbox +#! @font-face.baseline: org.w3c.css.properties.css2.font.Baseline +#! @font-face.centerline: org.w3c.css.properties.css2.font.Centerline +#! @font-face.definition-src: org.w3c.css.properties.css2.font.DefinitionSrc +#! @font-face.mathline: org.w3c.css.properties.css2.font.Mathline +#! @font-face.topline: org.w3c.css.properties.css2.font.Topline diff --git a/BKUViewer/src/test/java/at/gv/egiz/bku/slxhtml/ValidatorTest.java b/BKUViewer/src/test/java/at/gv/egiz/bku/slxhtml/ValidatorTest.java new file mode 100644 index 00000000..38c64262 --- /dev/null +++ b/BKUViewer/src/test/java/at/gv/egiz/bku/slxhtml/ValidatorTest.java @@ -0,0 +1,66 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml; + +import static org.junit.Assert.*; + +import java.io.InputStream; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Test; + +import at.gv.egiz.bku.viewer.ValidationException; +import at.gv.egiz.bku.viewer.Validator; +import at.gv.egiz.bku.viewer.ValidatorFactory; + + +public class ValidatorTest { + + private static Log log = LogFactory.getLog(ValidatorTest.class); + + @Test + public void testGetInstance() { + + Validator validator = ValidatorFactory.newValidator("application/xhtml+xml"); + + assertNotNull(validator); + + } + + @Test + public void testValidate() throws ValidationException { + + String slxhtmlFile = "at/gv/egiz/bku/slxhtml/test.xhtml"; + + Validator validator = ValidatorFactory.newValidator("application/xhtml+xml"); + + ClassLoader cl = ValidatorTest.class.getClassLoader(); + InputStream slxhtml = cl.getResourceAsStream(slxhtmlFile); + long t0 = System.currentTimeMillis(); + try { + validator.validate(slxhtml, null); + } catch (ValidationException e) { + e.printStackTrace(); + throw e; + } + long t1 = System.currentTimeMillis(); + log.info("Validated SLXHTML file '" + slxhtmlFile + "' in " + (t1 - t0) + "ms."); + + } + +} diff --git a/BKUViewer/src/test/java/at/gv/egiz/bku/slxhtml/css/CssValidatorTest.java b/BKUViewer/src/test/java/at/gv/egiz/bku/slxhtml/css/CssValidatorTest.java new file mode 100644 index 00000000..2b4740f9 --- /dev/null +++ b/BKUViewer/src/test/java/at/gv/egiz/bku/slxhtml/css/CssValidatorTest.java @@ -0,0 +1,75 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slxhtml.css; + +import static org.junit.Assert.*; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.Locale; +import java.util.Properties; +import java.util.Set; + +import org.junit.Test; + +import at.gv.egiz.bku.viewer.ValidationException; + +public class CssValidatorTest { + + @Test + public void testProperties() throws IOException { + + ClassLoader cs = CssValidatorTest.class.getClassLoader(); + InputStream is = cs.getResourceAsStream("org/w3c/css/properties/SLXHTMLProperties.properties"); + + assertNotNull(is); + + Properties cssProperties = new Properties(); + cssProperties.load(is); + + Set names = cssProperties.stringPropertyNames(); + for (String name : names) { + String className = cssProperties.getProperty(name); + try { + Class.forName(className); + } catch (ClassNotFoundException e) { + fail("Implementation class '" + className + "' for property '" + name + "' not found."); + } + + } + + } + + @Test(expected=ValidationException.class) + public void testValidator() throws UnsupportedEncodingException, ValidationException { + + String css = "@charset \"ABCDEFG\";\n" + + " @import url(http://test.abc/test); * { color: black }"; + ByteArrayInputStream input = new ByteArrayInputStream(css.getBytes("UTF-8")); + + CSSValidatorSLXHTML validator = new CSSValidatorSLXHTML(); + + Locale locale = new Locale("de"); + + validator.validate(input, locale, "Test", 10); + + } + + +} diff --git a/BKUViewer/src/test/resources/at/gv/egiz/bku/slxhtml/test.xhtml b/BKUViewer/src/test/resources/at/gv/egiz/bku/slxhtml/test.xhtml new file mode 100644 index 00000000..cbd29551 --- /dev/null +++ b/BKUViewer/src/test/resources/at/gv/egiz/bku/slxhtml/test.xhtml @@ -0,0 +1,10 @@ + + + + Ein einfaches SLXHTML-Dokument + @font-face { color: red }; p { color: red; } + + + Ich bin ein einfacher Text in rot. + + diff --git a/BKUViewer/src/test/resources/commons-logging.properties b/BKUViewer/src/test/resources/commons-logging.properties new file mode 100644 index 00000000..29292562 --- /dev/null +++ b/BKUViewer/src/test/resources/commons-logging.properties @@ -0,0 +1 @@ +org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger diff --git a/BKUViewer/src/test/resources/log4j.properties b/BKUViewer/src/test/resources/log4j.properties new file mode 100644 index 00000000..053eac17 --- /dev/null +++ b/BKUViewer/src/test/resources/log4j.properties @@ -0,0 +1,19 @@ +# loglever DEBUG, appender STDOUT +log4j.rootLogger=TRACE, STDOUT +#log4j.logger.at.gv.egiz.slbinding.RedirectEventFilter=DEBUG, STDOUT + +# STDOUT appender +log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender +log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout +#log4j.appender.STDOUT.layout.ConversionPattern=%5p | %d{dd HH:mm:ss,SSS} | %20c | %10t | %m%n +#log4j.appender.STDOUT.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n +log4j.appender.STDOUT.layout.ConversionPattern=%-5p |%d | %t | %c %x- %m%n + +### FILE appender +#log4j.appender.file=org.apache.log4j.RollingFileAppender +#log4j.appender.file.maxFileSize=100KB +#log4j.appender.file.maxBackupIndex=9 +#log4j.appender.file.File=egovbus_ca.log +#log4j.appender.file.threshold=info +#log4j.appender.file.layout=org.apache.log4j.PatternLayout +#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n \ No newline at end of file diff --git a/bkucommon/pom.xml b/bkucommon/pom.xml index 2ccf0766..2db0cc84 100644 --- a/bkucommon/pom.xml +++ b/bkucommon/pom.xml @@ -1,7 +1,5 @@ - + bku at.gv.egiz @@ -42,10 +40,13 @@ commons-httpclient compile + + xerces + xercesImpl + xalan xalan - 2.7.0 iaik diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/InputStreamPartSource.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/InputStreamPartSource.java index 253f8ff5..1a22f787 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/InputStreamPartSource.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/InputStreamPartSource.java @@ -14,11 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - package at.gv.egiz.bku.binding.multipart; import java.io.IOException; diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/SLResultPart.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/SLResultPart.java index 566b77b3..5585f02e 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/SLResultPart.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/SLResultPart.java @@ -14,11 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - package at.gv.egiz.bku.binding.multipart; import at.gv.egiz.bku.slcommands.SLResult; diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureCommandImpl.java index 136fa6f3..628326cf 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureCommandImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureCommandImpl.java @@ -44,7 +44,9 @@ import at.gv.egiz.bku.slcommands.impl.xsect.IdValueFactory; import at.gv.egiz.bku.slcommands.impl.xsect.IdValueFactoryImpl; import at.gv.egiz.bku.slcommands.impl.xsect.Signature; import at.gv.egiz.bku.slexceptions.SLCommandException; +import at.gv.egiz.bku.slexceptions.SLException; import at.gv.egiz.bku.slexceptions.SLRequestException; +import at.gv.egiz.bku.slexceptions.SLViewerException; import at.gv.egiz.dom.DOMUtils; import at.gv.egiz.stal.InfoboxReadRequest; import at.gv.egiz.stal.InfoboxReadResponse; @@ -166,9 +168,10 @@ public class CreateXMLSignatureCommandImpl extends SLCommandImpltrue if validation should be enabled, or + * false otherwise. + */ + public static void enableHashDataInputValidation(boolean validate) { + DataObject.validate = validate; + } + + /** + * @return true if hash data input validation is enabled, + * or false otherwise. + */ + public static boolean isHashDataInputValidationEnabled() { + return validate; + } + + /** + * Valid MIME types. + */ + private static String[] validMimeTypes = DEFAULT_PREFFERED_MIME_TYPES; + + /** + * Sets the list of valid hash data input media types. + *

The array is also used for transformation path selection. + * The transformation path with a final type, that appears in the + * given array in the earliest position is used selected.

+ * + * @param mediaTypes an array of MIME media types. + */ + public static void setValidHashDataInputMediaTypes(String[] mediaTypes) { + validMimeTypes = mediaTypes; + } + /** * The DOM implementation used. */ @@ -184,7 +230,70 @@ public class DataObject { public String getDescription() { return description; } - + + public void validateHashDataInput() throws SLViewerException { + + if (validate) { + + if (reference == null) { + log.error("Medthod validateHashDataInput() called before reference has been created."); + throw new SLViewerException(5000); + } + + InputStream digestInputStream = reference.getDigestInputStream(); + if (digestInputStream == null) { + log.error("Method validateHashDataInput() called before reference has been generated " + + "or reference caching is not enabled."); + throw new SLViewerException(5000); + } + + if (mimeType == null) { + log.info("FinalDataMetaInfo does not specify MIME type of to be signed data."); + // TODO: add detailed message + throw new SLViewerException(5000); + } + + // get MIME media type + String mediaType = mimeType.split(";")[0].trim(); + // and optional charset + String charset = HttpUtil.getCharset(mimeType, false); + + if (Arrays.asList(validMimeTypes).contains(mediaType)) { + + Validator validator; + try { + validator = ValidatorFactory.newValidator(mediaType); + } catch (IllegalArgumentException e) { + log.error("No validator found for mime type '" + mediaType + "'."); + throw new SLViewerException(5000); + } + + try { + validator.validate(digestInputStream, charset); + } catch (ValidationException e) { + if ("text/plain".equals(mediaType)) { + log.info("Data to be displayed contains unsupported characters.", e); + // TODO: add detailed message + throw new SLViewerException(5003); + } else if ("application/xhtml+xml".equals(mediaType)) { + // TODO: add detailed message + log.info("Standard display format: HTML does not conform to specification.", e); + throw new SLViewerException(5004); + } else { + // TODO: add detailed message + log.info("Data to be displayed is invalid.", e); + throw new SLViewerException(5000); + } + } + + } else { + log.info("MIME media type '" + mediaType + "' is not a valid digest input."); + throw new SLViewerException(5001); + } + } + + } + /** * Configures this DataObject with the information provided within the given * sl:DataObjectInfo. diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALSignature.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALSignature.java index eba1d96d..2d89c8ae 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALSignature.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALSignature.java @@ -17,6 +17,8 @@ package at.gv.egiz.bku.slcommands.impl.xsect; import at.gv.egiz.bku.slcommands.impl.HashDataInputImpl; +import at.gv.egiz.bku.slexceptions.SLViewerException; + import java.io.ByteArrayOutputStream; import java.security.InvalidKeyException; import java.security.InvalidParameterException; @@ -123,9 +125,14 @@ public class STALSignature extends SignatureSpi { // log.debug("got " + dataObjects.size() + " DataObjects, passing HashDataInputs to STAL SignRequest"); List hashDataInputs = new ArrayList(); - for (DataObject dataObject : dataObjects) { - hashDataInputs.add(new HashDataInputImpl(dataObject)); + for (DataObject dataObject : dataObjects) { + try { + dataObject.validateHashDataInput(); + } catch (SLViewerException e) { + throw new STALSignatureException(e); } + hashDataInputs.add(new HashDataInputImpl(dataObject)); + } SignRequest signRequest = new SignRequest(); signRequest.setKeyIdentifier(keyboxIdentifier); diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java index 191f8371..2330ed3f 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java @@ -81,6 +81,7 @@ import at.buergerkarte.namespaces.securitylayer._1.SignatureInfoCreationType; import at.gv.egiz.bku.binding.HttpUtil; import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.bku.slexceptions.SLRequestException; +import at.gv.egiz.bku.slexceptions.SLViewerException; import at.gv.egiz.bku.utils.HexDump; import at.gv.egiz.bku.utils.urldereferencer.StreamData; import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; @@ -387,10 +388,11 @@ public class Signature { * if signing the XMLSignature fails * @throws SLCommandException * if building the XMLSignature fails + * @throws SLViewerException * @throws NullPointerException * if signContext is null */ - public void sign(DOMSignContext signContext) throws MarshalException, XMLSignatureException, SLCommandException { + public void sign(DOMSignContext signContext) throws MarshalException, XMLSignatureException, SLCommandException, SLViewerException { if (xmlSignature == null) { buildXMLSignature(); @@ -415,6 +417,9 @@ public class Signature { Throwable cause = e.getCause(); while (cause != null) { if (cause instanceof STALSignatureException) { + if (((STALSignatureException) cause).getCause() instanceof SLViewerException) { + throw (SLViewerException) ((STALSignatureException) cause).getCause(); + } int errorCode = ((STALSignatureException) cause).getErrorCode(); SLCommandException commandException = new SLCommandException(errorCode); log.info("Failed to sign signature.", commandException); @@ -482,11 +487,12 @@ public class Signature { * if signing this Signature fails * @throws SLCommandException * if building this Signature fails + * @throws SLViewerException * @throws NullPointerException * if stal or keyboxIdentifier is * null */ - public void sign(STAL stal, String keyboxIdentifier) throws MarshalException, XMLSignatureException, SLCommandException { + public void sign(STAL stal, String keyboxIdentifier) throws MarshalException, XMLSignatureException, SLCommandException, SLViewerException { if (stal == null) { throw new NullPointerException("Argument 'stal' must not be null."); diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLViewerException.java b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLViewerException.java index 1d128a00..853328d5 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLViewerException.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLViewerException.java @@ -17,9 +17,12 @@ package at.gv.egiz.bku.slexceptions; public class SLViewerException extends SLException { - + + public SLViewerException(int errorCode) { + super(errorCode); + } + public SLViewerException(int errorCode, String msg, Object[] args) { super(errorCode, msg, args); - // TODO Auto-generated constructor stub } } \ No newline at end of file diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/viewer/ValidationException.java b/bkucommon/src/main/java/at/gv/egiz/bku/viewer/ValidationException.java new file mode 100644 index 00000000..fb332a09 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/viewer/ValidationException.java @@ -0,0 +1,38 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.viewer; + +public class ValidationException extends Exception { + + private static final long serialVersionUID = 1L; + + public ValidationException() { + } + + public ValidationException(String message) { + super(message); + } + + public ValidationException(Throwable cause) { + super(cause); + } + + public ValidationException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/viewer/Validator.java b/bkucommon/src/main/java/at/gv/egiz/bku/viewer/Validator.java new file mode 100644 index 00000000..08b21080 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/viewer/Validator.java @@ -0,0 +1,25 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.viewer; + +import java.io.InputStream; + +public interface Validator { + + public void validate(InputStream is, String charset) throws ValidationException; + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/viewer/ValidatorFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/viewer/ValidatorFactory.java new file mode 100644 index 00000000..e16a261e --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/viewer/ValidatorFactory.java @@ -0,0 +1,165 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.viewer; + +import java.io.IOException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public class ValidatorFactory { + + /** + * Logging facility. + */ + protected static Log log = LogFactory.getLog(ValidatorFactory.class); + + private static final Class VALIDATOR_CLASS = Validator.class; + + private static final String SERVICE_ID = "META-INF/services/" + VALIDATOR_CLASS.getName(); + + /** + * Creates a new Validator for the given mimeType. + * + * @param mimeType + * + * @return + * + * @throws IllegalArgumentException + * if no Validator for the mimeType could be found + */ + public static Validator newValidator(String mimeType) throws IllegalArgumentException { + + ClassLoader classLoader = ValidatorFactory.class.getClassLoader(); + ValidatorFactory factory = new ValidatorFactory(classLoader); + + Validator validator = factory.createValidator(mimeType); + + if (validator == null) { + throw new IllegalArgumentException("Validator for '" + mimeType + + "' could not be found."); + } + + return validator; + + } + + private ClassLoader classLoader; + + /** + * Private constructor. + * + * @param classLoader must not be null + */ + private ValidatorFactory(ClassLoader classLoader) { + + if (classLoader == null) { + throw new NullPointerException("Argument 'classLoader' must no be null."); + } + + this.classLoader = classLoader; + + } + + private Validator createValidator(String mimeType) { + + Iterator serviceIterator = createServiceIterator(); + while (serviceIterator.hasNext()) { + URL url = serviceIterator.next(); + + Properties properties = new Properties(); + try { + properties.load(url.openStream()); + } catch (IOException e) { + log.error("Failed to load service properties " + url.toExternalForm()); + continue; + } + String className = properties.getProperty(mimeType); + if (className != null) { + try { + return createValidatorInstance(className); + } catch (Exception e) { + continue; + } + } + + } + + return null; + + } + + private Validator createValidatorInstance(String className) + throws ClassNotFoundException, InstantiationException, + IllegalAccessException { + + try { + Class implClass = classLoader.loadClass(className); + return (Validator) implClass.newInstance(); + } catch (ClassNotFoundException e) { + log.error("Validator class '" + className + "' not found.", e); + throw e; + } catch (InstantiationException e) { + log.error("Faild to initialize validator class '" + className + "'.", e); + throw e; + } catch (IllegalAccessException e) { + log.error("Faild to initialize validator class '" + className + "'.", e); + throw e; + } catch (ClassCastException e) { + log.error("Class '" + className + "' is not a validator implementation.", e); + throw e; + } + + } + + private Iterator createServiceIterator() { + + try { + final Enumeration resources = classLoader.getResources(SERVICE_ID); + return new Iterator () { + + @Override + public boolean hasNext() { + return resources.hasMoreElements(); + } + + @Override + public URL next() { + return resources.nextElement(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + }; + } catch (IOException e) { + log.error("Failed to enumerate resources " + SERVICE_ID); + List list = Collections.emptyList(); + return list.iterator(); + } + + } + +} diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java index a650d67f..9e34d9ae 100644 --- a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java @@ -68,6 +68,7 @@ import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory; import at.buergerkarte.namespaces.securitylayer._1.SignatureInfoCreationType; import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.bku.slexceptions.SLRequestException; +import at.gv.egiz.bku.slexceptions.SLViewerException; import at.gv.egiz.bku.utils.urldereferencer.StreamData; import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerContext; @@ -361,7 +362,7 @@ public class SignatureTest { } - private void signAndMarshalSignature(Signature signature) throws MarshalException, XMLSignatureException, SLCommandException { + private void signAndMarshalSignature(Signature signature) throws MarshalException, XMLSignatureException, SLCommandException, SLViewerException { Node parent = signature.getParent(); Node nextSibling = signature.getNextSibling(); @@ -387,7 +388,7 @@ public class SignatureTest { @SuppressWarnings("unchecked") @Test - public void testDataObject_Base64Content_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException { + public void testDataObject_Base64Content_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Base64Content_1.xml"); @@ -427,7 +428,7 @@ public class SignatureTest { @SuppressWarnings("unchecked") @Test - public void testDataObject_XMLContent_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException { + public void testDataObject_XMLContent_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_XMLContent_1.xml"); @@ -467,7 +468,7 @@ public class SignatureTest { @SuppressWarnings("unchecked") @Test - public void testDataObject_XMLContent_2() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException { + public void testDataObject_XMLContent_2() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_XMLContent_2.xml"); @@ -508,7 +509,7 @@ public class SignatureTest { @SuppressWarnings("unchecked") @Test - public void testDataObject_LocRefContent_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException { + public void testDataObject_LocRefContent_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_LocRefContent_1.xml"); @@ -546,7 +547,7 @@ public class SignatureTest { @SuppressWarnings("unchecked") @Test - public void testDataObject_LocRefContent_2() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException { + public void testDataObject_LocRefContent_2() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_LocRefContent_2.xml"); @@ -584,7 +585,7 @@ public class SignatureTest { @SuppressWarnings("unchecked") @Test - public void testDataObject_Reference_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException { + public void testDataObject_Reference_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Reference_1.xml"); @@ -622,7 +623,7 @@ public class SignatureTest { @SuppressWarnings("unchecked") @Test - public void testDataObject_Detached_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException { + public void testDataObject_Detached_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Detached_1.xml"); @@ -653,7 +654,7 @@ public class SignatureTest { @SuppressWarnings("unchecked") @Test - public void testDataObject_Detached_Base64Content() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException { + public void testDataObject_Detached_Base64Content() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Detached_Base64Content.xml"); @@ -704,7 +705,7 @@ public class SignatureTest { @SuppressWarnings("unchecked") @Test - public void testTransformsInfo_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException { + public void testTransformsInfo_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { CreateXMLSignatureRequestType requestType = unmarshalCreateXMLSignatureRequest("TransformsInfo_1.xml"); diff --git a/pom.xml b/pom.xml index 352257f0..3438e596 100644 --- a/pom.xml +++ b/pom.xml @@ -7,17 +7,18 @@ 1.0-SNAPSHOT BKU http://bku.egiz.gv.at - - utils - bkucommon - STAL - BKUOnline - smcc - BKULocal - BKUApplet - smccSTAL - STALService - BKUCommonGUI + + utils + bkucommon + STAL + BKUOnline + smcc + BKULocal + BKUApplet + smccSTAL + STALService + BKUCommonGUI + BKUViewer @@ -161,6 +162,16 @@ 4.4 test
+ + xerces + xercesImpl + 2.9.1 + + + xalan + xalan + 2.7.0 + iaik iaik_jce_full_signed -- cgit v1.2.3 From 6576428966f1e3d688269a407b072fb01f9f7647 Mon Sep 17 00:00:00 2001 From: clemenso Date: Thu, 26 Feb 2009 19:39:00 +0000 Subject: 1.1 candidate (activation) git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@309 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- .../gv/egiz/bku/online/applet/AppletBKUWorker.java | 9 +- .../java/at/gv/egiz/bku/gui/PINManagementGUI.java | 519 ++++- .../at/gv/egiz/bku/gui/PINManagementGUIFacade.java | 47 +- .../java/at/gv/egiz/bku/gui/PINSpecRenderer.java | 39 + .../java/at/gv/egiz/bku/gui/PINStatusProvider.java | 32 - .../java/at/gv/egiz/bku/gui/PINStatusRenderer.java | 63 + .../at/gv/egiz/bku/gui/PINStatusTableModel.java | 60 + .../bku/online/applet/PINManagementApplet.java | 3 +- .../bku/online/applet/PINManagementBKUWorker.java | 82 +- .../smccstal/ext/PINManagementRequestHandler.java | 331 ++++ .../bku/smccstal/ext/PINMgmtRequestHandler.java | 93 - .../gv/egiz/bku/gui/ActivationMessages.properties | 28 +- .../egiz/bku/gui/ActivationMessages_en.properties | 30 +- .../test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java | 4 +- BKUAppletExt/src/test/resources/appletTest.html | 2 +- .../main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java | 8 +- .../main/java/at/gv/egiz/bku/gui/PinDocument.java | 28 +- .../at/gv/egiz/bku/gui/Messages.properties | 4 +- .../test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java | 2 +- .../at/gv/egiz/stal/ext/ActivatePINRequest.java | 28 - .../java/at/gv/egiz/stal/ext/ChangePINRequest.java | 28 - .../at/gv/egiz/stal/ext/PINManagementRequest.java | 31 + .../at/gv/egiz/stal/ext/PINManagementResponse.java | 28 + .../at/gv/egiz/stal/ext/UnblockPINRequest.java | 28 - .../egiz/bku/slcommands/impl/xsect/DataObject.java | 2078 ++++++++++---------- .../egiz/bku/slcommands/impl/xsect/Signature.java | 5 +- .../bku/slcommands/impl/xsect/SignatureTest.java | 1505 +++++++------- .../egiz/bku/slcommands/impl/TransformsInfo_2.xml | 397 ++++ smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java | 25 +- .../at/gv/egiz/smcc/AbstractSignatureCard.java | 10 + smcc/src/main/java/at/gv/egiz/smcc/PINSpec.java | 30 +- .../src/main/java/at/gv/egiz/smcc/STARCOSCard.java | 25 +- smcc/src/main/java/at/gv/egiz/smcc/SWCard.java | 14 +- .../main/java/at/gv/egiz/smcc/SignatureCard.java | 5 +- .../at/gv/egiz/bku/smccstal/AbstractBKUWorker.java | 3 + .../java/at/gv/egiz/smcc/AbstractSMCCSTALTest.java | 9 +- .../java/at/gv/egiz/marshal/NamespacePrefix.java | 34 + .../gv/egiz/marshal/NamespacePrefixMapperImpl.java | 16 +- .../at/gv/egiz/slbinding/RedirectEventFilter.java | 389 ++-- .../gv/egiz/slbinding/impl/TransformsInfoType.java | 1 + .../at/gv/egiz/slbinding/impl/XMLContentType.java | 2 +- .../org/w3/_2000/_09/xmldsig_/ObjectFactory.java | 1 + .../org/w3/_2000/_09/xmldsig_/TransformsType.java | 2 +- .../java/at/gv/egiz/slbinding/RedirectTest.java | 29 +- .../CreateXMLSignatureRequest02.xml_redirect.txt | 5 +- 45 files changed, 3813 insertions(+), 2299 deletions(-) create mode 100644 BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINSpecRenderer.java delete mode 100644 BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusProvider.java create mode 100644 BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusRenderer.java create mode 100644 BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusTableModel.java create mode 100644 BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PINManagementRequestHandler.java delete mode 100644 BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PINMgmtRequestHandler.java delete mode 100644 STALExt/src/main/java/at/gv/egiz/stal/ext/ActivatePINRequest.java delete mode 100644 STALExt/src/main/java/at/gv/egiz/stal/ext/ChangePINRequest.java create mode 100644 STALExt/src/main/java/at/gv/egiz/stal/ext/PINManagementRequest.java create mode 100644 STALExt/src/main/java/at/gv/egiz/stal/ext/PINManagementResponse.java delete mode 100644 STALExt/src/main/java/at/gv/egiz/stal/ext/UnblockPINRequest.java create mode 100644 bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/impl/TransformsInfo_2.xml create mode 100644 utils/src/main/java/at/gv/egiz/marshal/NamespacePrefix.java (limited to 'bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java') diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java index 5a57ef18..8c1bd2bd 100644 --- a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java +++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java @@ -195,11 +195,16 @@ public class AppletBKUWorker extends AbstractBKUWorker implements Runnable { } } + /** + * + * @param err_code + * @param ex if not null, the message will be appended as parameter to the error message + */ protected void showErrorDialog(String err_code, Exception ex) { actionCommandList.clear(); actionCommandList.add("ok"); - gui.showErrorDialog(err_code, - new Object[]{ex.getMessage()}, this, "ok"); + Object[] params = (ex != null) ? new Object[] { ex.getMessage() } : null; + gui.showErrorDialog(err_code, params, this, "ok"); try { waitForAction(); } catch (InterruptedException e) { diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUI.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUI.java index 8acf051e..8eef8aea 100644 --- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUI.java +++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUI.java @@ -17,15 +17,28 @@ package at.gv.egiz.bku.gui; +import at.gv.egiz.smcc.PINSpec; import java.awt.Container; +import java.awt.Cursor; +import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; import java.net.URL; +import java.text.MessageFormat; import java.util.Locale; +import java.util.Map; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JLabel; +import javax.swing.JPasswordField; +import javax.swing.JScrollPane; +import javax.swing.JTable; import javax.swing.LayoutStyle; +import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; /** * TODO pull out ResourceBundle to common superclass for activationGUI and pinMgmtGUI @@ -33,9 +46,10 @@ import javax.swing.SwingUtilities; */ public class PINManagementGUI extends ActivationGUI implements PINManagementGUIFacade { - public static final String BUTTON_ACTIVATE = "button.activate"; - public static final String BUTTON_UNBLOCK = "button.unblock"; - public static final String BUTTON_CHANGE = "button.change"; + /** remember the pinfield to return to worker */ + protected JPasswordField oldPinField; + /** remember the pinSpec to return to worker */ + protected PINSpec pinSpec; public PINManagementGUI(Container contentPane, Locale locale, @@ -46,12 +60,31 @@ public class PINManagementGUI extends ActivationGUI implements PINManagementGUIF } @Override - public void showPINManagementDialog(final PINStatusProvider pinStatusProvider, - final ActionListener activateListener, final String activateCmd, - final ActionListener changeListener, final String changeCmd, - final ActionListener unblockListener, final String unblockCmd, - final ActionListener cancelListener, final String cancelCmd) { -// try { + public char[] getOldPin() { + if (oldPinField != null) { + char[] pin = oldPinField.getPassword(); + oldPinField = null; + return pin; + } + return null; + } + + @Override + public PINSpec getSelectedPIN() { + return pinSpec; + } + + @Override + public void showPINManagementDialog(final Map pins, + final ActionListener activateListener, + final String activateCmd, + final String changeCmd, + final String unblockCmd, + final ActionListener cancelListener, + final String cancelCmd) { + + log.debug("scheduling PIN managment dialog"); + SwingUtilities.invokeLater(new Runnable() { @Override @@ -68,13 +101,76 @@ public class PINManagementGUI extends ActivationGUI implements PINManagementGUIF if (renderHeaderPanel) { titleLabel.setText(cardmgmtMessages.getString(TITLE_PINMGMT)); - mgmtLabel.setText(cardmgmtMessages.getString(MESSAGE_PINMGMT)); + String infoPattern = cardmgmtMessages.getString(MESSAGE_PINMGMT); + mgmtLabel.setText(MessageFormat.format(infoPattern, pins.size())); } else { mgmtLabel.setText(cardmgmtMessages.getString(TITLE_PINMGMT)); } + final PINStatusTableModel tableModel = new PINStatusTableModel(pins); + final JTable pinStatusTable = new JTable(tableModel); + pinStatusTable.setDefaultRenderer(PINSpec.class, new PINSpecRenderer()); + pinStatusTable.setDefaultRenderer(STATUS.class, new PINStatusRenderer(cardmgmtMessages)); + pinStatusTable.setTableHeader(null); - + pinStatusTable.addMouseMotionListener(new MouseMotionAdapter() { + + @Override + public void mouseMoved(MouseEvent e) { + if (pinStatusTable.columnAtPoint(e.getPoint()) == 0) { + pinStatusTable.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } else { + pinStatusTable.setCursor(Cursor.getDefaultCursor()); + } + } + }); + + final JButton activateButton = new JButton(); + activateButton.setFont(activateButton.getFont().deriveFont(activateButton.getFont().getStyle() & ~java.awt.Font.BOLD)); + activateButton.addActionListener(activateListener); + + pinStatusTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + pinStatusTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + + @Override + public void valueChanged(final ListSelectionEvent e) { + //invoke later to allow thread to paint selection background + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + ListSelectionModel lsm = (ListSelectionModel) e.getSource(); + int selectionIdx = lsm.getMinSelectionIndex(); + if (selectionIdx >= 0) { + pinSpec = (PINSpec) tableModel.getValueAt(selectionIdx, 0); + STATUS status = (STATUS) tableModel.getValueAt(selectionIdx, 1); + + if (status == STATUS.NOT_ACTIV) { + activateButton.setText(cardmgmtMessages.getString(BUTTON_ACTIVATE)); + activateButton.setEnabled(true); + activateButton.setActionCommand(activateCmd); + } else if (status == STATUS.BLOCKED) { + activateButton.setText(cardmgmtMessages.getString(BUTTON_UNBLOCK)); + activateButton.setEnabled(true); + activateButton.setActionCommand(unblockCmd); + } else if (status == STATUS.ACTIV) { + activateButton.setText(cardmgmtMessages.getString(BUTTON_CHANGE)); + activateButton.setEnabled(true); + activateButton.setActionCommand(changeCmd); + } else { + activateButton.setText(cardmgmtMessages.getString(BUTTON_ACTIVATE)); + activateButton.setEnabled(false); + } + } + } + }); + } + }); + + //select first entry + pinStatusTable.getSelectionModel().setSelectionInterval(0, 0); + + JScrollPane pinStatusScrollPane = new JScrollPane(pinStatusTable); GroupLayout mainPanelLayout = new GroupLayout(mainPanel); mainPanel.setLayout(mainPanelLayout); @@ -91,30 +187,16 @@ public class PINManagementGUI extends ActivationGUI implements PINManagementGUIF .addComponent(helpLabel); } - mainPanelLayout.setHorizontalGroup(messageHorizontal); - mainPanelLayout.setVerticalGroup(messageVertical); + mainPanelLayout.setHorizontalGroup( + mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(messageHorizontal) + .addComponent(pinStatusScrollPane, 0, 0, Short.MAX_VALUE)); - - JButton activateButton = new JButton(); - activateButton.setFont(activateButton.getFont().deriveFont(activateButton.getFont().getStyle() & ~java.awt.Font.BOLD)); - activateButton.setText(cardmgmtMessages.getString(BUTTON_ACTIVATE)); - activateButton.setEnabled(true);//false); - activateButton.setActionCommand(activateCmd); - activateButton.addActionListener(activateListener); - - JButton changeButton = new JButton(); - changeButton.setFont(activateButton.getFont().deriveFont(activateButton.getFont().getStyle() & ~java.awt.Font.BOLD)); - changeButton.setText(cardmgmtMessages.getString(BUTTON_CHANGE)); - changeButton.setEnabled(false); - changeButton.setActionCommand(changeCmd); - changeButton.addActionListener(changeListener); - - JButton unblockButton = new JButton(); - unblockButton.setFont(activateButton.getFont().deriveFont(activateButton.getFont().getStyle() & ~java.awt.Font.BOLD)); - unblockButton.setText(cardmgmtMessages.getString(BUTTON_UNBLOCK)); - unblockButton.setEnabled(false); - unblockButton.setActionCommand(unblockCmd); - unblockButton.addActionListener(unblockListener); + mainPanelLayout.setVerticalGroup( + mainPanelLayout.createSequentialGroup() + .addGroup(messageVertical) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pinStatusScrollPane, 0, 0, pinStatusTable.getPreferredSize().height+3)); JButton cancelButton = new JButton(); cancelButton.setFont(cancelButton.getFont().deriveFont(cancelButton.getFont().getStyle() & ~java.awt.Font.BOLD)); @@ -129,30 +211,377 @@ public class PINManagementGUI extends ActivationGUI implements PINManagementGUIF .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(activateButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) - .addComponent(changeButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE) - .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) - .addComponent(unblockButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE) - .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) .addComponent(cancelButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE); GroupLayout.Group buttonVertical = buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(activateButton) - .addComponent(changeButton) - .addComponent(unblockButton) .addComponent(cancelButton); buttonPanelLayout.setHorizontalGroup(buttonHorizontal); buttonPanelLayout.setVerticalGroup(buttonVertical); contentPanel.validate(); - } }); + } + + @Override + public void showActivatePINDialog(final PINSpec pin, + final ActionListener okListener, final String okCommand, + final ActionListener cancelListener, final String cancelCommand) { + log.debug("scheduling activate pin dialog"); + showPINDialog(false, pin, okListener, okCommand, cancelListener, cancelCommand); + } + + + private void showPINDialog(final boolean changePin, final PINSpec pinSpec, + final ActionListener okListener, final String okCommand, + final ActionListener cancelListener, final String cancelCommand) { + + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + + String HELP_TOPIC, TITLE, MESSAGE_MGMT; + if (changePin) { + log.debug("show change pin dialog"); + HELP_TOPIC = HELP_PINMGMT; + TITLE = TITLE_CHANGE_PIN; + MESSAGE_MGMT = MESSAGE_CHANGE_PIN; + } else { + log.debug("show activate pin dialog"); + HELP_TOPIC = HELP_PINMGMT; + TITLE = TITLE_ACTIVATE_PIN; + MESSAGE_MGMT = MESSAGE_ACTIVATE_PIN; + oldPinField = null; + } + + mainPanel.removeAll(); + buttonPanel.removeAll(); + + helpListener.setHelpTopic(HELP_TOPIC); + + JLabel mgmtLabel = new JLabel(); + mgmtLabel.setFont(mgmtLabel.getFont().deriveFont(mgmtLabel.getFont().getStyle() & ~java.awt.Font.BOLD)); + + if (renderHeaderPanel) { + titleLabel.setText(cardmgmtMessages.getString(TITLE)); + String mgmtPattern = cardmgmtMessages.getString(MESSAGE_MGMT); + if (shortText) { + mgmtLabel.setText(MessageFormat.format(mgmtPattern, "PIN")); + } else { + mgmtLabel.setText(MessageFormat.format(mgmtPattern, pinSpec.getLocalizedName())); + } + } else { + mgmtLabel.setText(cardmgmtMessages.getString(TITLE)); + } + + JButton okButton = new JButton(); + okButton.setFont(okButton.getFont().deriveFont(okButton.getFont().getStyle() & ~java.awt.Font.BOLD)); + okButton.setText(messages.getString(BUTTON_OK)); + okButton.setEnabled(false); + okButton.setActionCommand(okCommand); + okButton.addActionListener(okListener); + + JLabel pinLabel = new JLabel(); + pinLabel.setFont(pinLabel.getFont().deriveFont(pinLabel.getFont().getStyle() & ~java.awt.Font.BOLD)); + String pinLabelPattern = (changePin) ? cardmgmtMessages.getString(LABEL_NEW_PIN) : messages.getString(LABEL_PIN); + pinLabel.setText(MessageFormat.format(pinLabelPattern, new Object[]{pinSpec.getLocalizedName()})); + + final JPasswordField repeatPinField = new JPasswordField(); + pinField = new JPasswordField(); + pinField.setText(""); + pinField.setDocument(new PINDocument(pinSpec, null)); + pinField.setActionCommand(okCommand); + pinField.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (pinField.getPassword().length >= pinSpec.getMinLength()) { + repeatPinField.requestFocusInWindow(); + } + } + }); + JLabel repeatPinLabel = new JLabel(); + repeatPinLabel.setFont(pinLabel.getFont()); + String repeatPinLabelPattern = cardmgmtMessages.getString(LABEL_REPEAT_PIN); + repeatPinLabel.setText(MessageFormat.format(repeatPinLabelPattern, new Object[]{pinSpec.getLocalizedName()})); + + repeatPinField.setText(""); + repeatPinField.setDocument(new PINDocument(pinSpec, okButton, pinField.getDocument())); + repeatPinField.setActionCommand(okCommand); + repeatPinField.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (pinField.getPassword().length >= pinSpec.getMinLength()) { + okListener.actionPerformed(e); + } + } + }); + + JLabel oldPinLabel = null; + if (changePin) { + oldPinLabel = new JLabel(); + oldPinLabel.setFont(oldPinLabel.getFont().deriveFont(oldPinLabel.getFont().getStyle() & ~java.awt.Font.BOLD)); + String oldPinLabelPattern = cardmgmtMessages.getString(LABEL_OLD_PIN); + oldPinLabel.setText(MessageFormat.format(oldPinLabelPattern, new Object[]{pinSpec.getLocalizedName()})); + + oldPinField = new JPasswordField(); + oldPinField.setText(""); + oldPinField.setDocument(new PINDocument(pinSpec, null)); + oldPinField.setActionCommand(okCommand); + oldPinField.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (oldPinField.getPassword().length >= pinSpec.getMinLength()) { + pinField.requestFocusInWindow(); + } + } + }); + } + + JLabel pinsizeLabel = new JLabel(); + pinsizeLabel.setFont(pinsizeLabel.getFont().deriveFont(pinsizeLabel.getFont().getStyle() & ~java.awt.Font.BOLD, pinsizeLabel.getFont().getSize()-2)); + String pinsizePattern = messages.getString(LABEL_PINSIZE); + String pinSize = String.valueOf(pinSpec.getMinLength()); + if (pinSpec.getMinLength() != pinSpec.getMaxLength()) { + pinSize += "-" + pinSpec.getMaxLength(); + } + pinsizeLabel.setText(MessageFormat.format(pinsizePattern, new Object[]{pinSize})); + + GroupLayout mainPanelLayout = new GroupLayout(mainPanel); + mainPanel.setLayout(mainPanelLayout); + + GroupLayout.SequentialGroup infoHorizontal = mainPanelLayout.createSequentialGroup() + .addComponent(mgmtLabel); + GroupLayout.ParallelGroup infoVertical = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(mgmtLabel); + + if (!renderHeaderPanel) { + infoHorizontal + .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE) + .addComponent(helpLabel); + infoVertical + .addComponent(helpLabel); + } -// } catch (Exception ex) { -// log.error(ex.getMessage(), ex); -// showErrorDialog(ERR_UNKNOWN_WITH_PARAM, new Object[] {ex.getMessage()}); -// } + GroupLayout.ParallelGroup pinHorizontal = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING); + GroupLayout.SequentialGroup pinVertical = mainPanelLayout.createSequentialGroup(); + + if (pinLabelPos == PinLabelPosition.ABOVE) { + if (changePin) { + pinHorizontal + .addComponent(oldPinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(oldPinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE); + pinVertical + .addComponent(oldPinLabel) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(oldPinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED); + } + pinHorizontal + .addComponent(pinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(repeatPinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(repeatPinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(mainPanelLayout.createSequentialGroup() + .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE) + .addComponent(pinsizeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)); + pinVertical + .addComponent(pinLabel) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(repeatPinLabel) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(repeatPinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pinsizeLabel); + } else { + if (changePin) { + pinHorizontal + .addGroup(mainPanelLayout.createSequentialGroup() + .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(oldPinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(pinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(repeatPinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(oldPinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(repeatPinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))); + + pinVertical + .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(oldPinLabel) + .addComponent(oldPinField)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED); + } else { + pinHorizontal + .addGroup(mainPanelLayout.createSequentialGroup() + .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(pinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(repeatPinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(repeatPinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))); + + } + pinHorizontal + .addGroup(mainPanelLayout.createSequentialGroup() + .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE) + .addComponent(pinsizeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)); + pinVertical + .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(pinLabel) + .addComponent(pinField)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(repeatPinLabel) + .addComponent(repeatPinField)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pinsizeLabel); + } + + mainPanelLayout.setHorizontalGroup( + mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(infoHorizontal) + .addGroup(pinHorizontal)); + + mainPanelLayout.setVerticalGroup( + mainPanelLayout.createSequentialGroup() + .addGroup(infoVertical) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pinVertical)); + + GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel); + buttonPanel.setLayout(buttonPanelLayout); + + GroupLayout.SequentialGroup buttonHorizontal = buttonPanelLayout.createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(okButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE); + GroupLayout.Group buttonVertical; + + JButton cancelButton = new JButton(); + cancelButton.setFont(cancelButton.getFont().deriveFont(cancelButton.getFont().getStyle() & ~java.awt.Font.BOLD)); + cancelButton.setText(messages.getString(BUTTON_CANCEL)); + cancelButton.setActionCommand(cancelCommand); + cancelButton.addActionListener(cancelListener); + + buttonHorizontal + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE); + buttonVertical = buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(okButton) + .addComponent(cancelButton); + + buttonPanelLayout.setHorizontalGroup(buttonHorizontal); + buttonPanelLayout.setVerticalGroup(buttonVertical); + + if (oldPinField != null) { + oldPinField.requestFocusInWindow(); + } else { + pinField.requestFocusInWindow(); + } + contentPanel.validate(); + + } + }); + } + + @Override + public void showChangePINDialog(final PINSpec pin, + final ActionListener okListener, final String okCommand, + final ActionListener cancelListener, final String cancelCommand) { + + log.debug("scheduling change pin dialog"); + showPINDialog(true, pin, okListener, okCommand, cancelListener, cancelCommand); + } + + @Override + public void showUnblockPINDialog(final PINSpec pin, + final ActionListener okListener, final String okCommand, + final ActionListener cancelListener, final String cancelCommand) { + + log.debug("scheduling unblock PIN dialog"); + + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + + log.debug("show unblock PIN dialog"); + + log.error("unblock pin not supported"); + + mainPanel.removeAll(); + buttonPanel.removeAll(); + + if (renderHeaderPanel) { + titleLabel.setText(messages.getString(TITLE_ERROR)); + } + + helpListener.setHelpTopic(HELP_PINMGMT); + + String errorMsgPattern = cardmgmtMessages.getString(ERR_UNBLOCK); + String errorMsg = MessageFormat.format(errorMsgPattern, pin.getLocalizedName()); + + JLabel errorMsgLabel = new JLabel(); + errorMsgLabel.setFont(errorMsgLabel.getFont().deriveFont(errorMsgLabel.getFont().getStyle() & ~java.awt.Font.BOLD)); + errorMsgLabel.setText(errorMsg); + + GroupLayout mainPanelLayout = new GroupLayout(mainPanel); + mainPanel.setLayout(mainPanelLayout); + + GroupLayout.ParallelGroup mainHorizontal = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING); + GroupLayout.SequentialGroup mainVertical = mainPanelLayout.createSequentialGroup(); + + if (!renderHeaderPanel) { + JLabel errorTitleLabel = new JLabel(); + errorTitleLabel.setFont(errorTitleLabel.getFont().deriveFont(errorTitleLabel.getFont().getStyle() | java.awt.Font.BOLD)); + errorTitleLabel.setText(messages.getString(TITLE_ERROR)); + errorTitleLabel.setForeground(ERROR_COLOR); + + mainHorizontal + .addGroup(mainPanelLayout.createSequentialGroup() + .addComponent(errorTitleLabel) + .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE) + .addComponent(helpLabel)); + mainVertical + .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(errorTitleLabel) + .addComponent(helpLabel)); + } + + mainPanelLayout.setHorizontalGroup(mainHorizontal + .addComponent(errorMsgLabel)); + mainPanelLayout.setVerticalGroup(mainVertical + .addComponent(errorMsgLabel)); + + JButton okButton = new JButton(); + okButton.setFont(okButton.getFont().deriveFont(okButton.getFont().getStyle() & ~java.awt.Font.BOLD)); + okButton.setText(messages.getString(BUTTON_OK)); + okButton.setActionCommand(cancelCommand); + okButton.addActionListener(cancelListener); + + GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel); + buttonPanel.setLayout(buttonPanelLayout); + + buttonPanelLayout.setHorizontalGroup( + buttonPanelLayout.createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(okButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE)); + buttonPanelLayout.setVerticalGroup( + buttonPanelLayout.createSequentialGroup() + .addComponent(okButton)); + + contentPanel.validate(); + } + }); } diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUIFacade.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUIFacade.java index 3d653fab..2a8f28d2 100644 --- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUIFacade.java +++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINManagementGUIFacade.java @@ -17,7 +17,9 @@ package at.gv.egiz.bku.gui; +import at.gv.egiz.smcc.PINSpec; import java.awt.event.ActionListener; +import java.util.Map; /** * @@ -27,8 +29,49 @@ public interface PINManagementGUIFacade extends BKUGUIFacade { public static final String HELP_PINMGMT = "help.pin.mgmt"; public static final String TITLE_PINMGMT = "title.pin.mgmt"; + public static final String TITLE_ACTIVATE_PIN = "title.activate.pin"; + public static final String TITLE_CHANGE_PIN = "title.change.pin"; + public static final String TITLE_UNBLOCK_PIN = "title.unblock.pin"; public static final String MESSAGE_PINMGMT = "message.pin.mgmt"; - - public void showPINManagementDialog(PINStatusProvider pinStatusProvider, ActionListener activateListener, String activateCmd, ActionListener changeListener, String changeCmd, ActionListener unblockListener, String unblockCmd, ActionListener cancelListener, String cancelCmd); + public static final String MESSAGE_ACTIVATE_PIN = "message.activate.pin"; + public static final String MESSAGE_CHANGE_PIN = "message.change.pin"; + public static final String MESSAGE_UNBLOCK_PIN = "message.unblock.pin"; + public static final String LABEL_OLD_PIN = "label.old.pin"; + public static final String LABEL_NEW_PIN = "label.new.pin"; + public static final String LABEL_REPEAT_PIN = "label.repeat.pin"; + public static final String ERR_ACTIVATE = "err.activate"; + public static final String ERR_CHANGE = "err.change"; + public static final String ERR_UNBLOCK = "err.unblock"; + + public static final String BUTTON_ACTIVATE = "button.activate"; + public static final String BUTTON_UNBLOCK = "button.unblock"; + public static final String BUTTON_CHANGE = "button.change"; + + public static final String STATUS_ACTIVE = "status.active"; + public static final String STATUS_BLOCKED = "status.blocked"; + public static final String STATUS_NOT_ACTIVE = "status.not.active"; + public static final String STATUS_UNKNOWN = "status.unknown"; + + public enum STATUS { ACTIV, NOT_ACTIV, BLOCKED, UNKNOWN }; + + public void showPINManagementDialog(Map pins, + ActionListener activateListener, String activateCmd, String changeCmd, String unblockCmd, + ActionListener cancelListener, String cancelCmd); + + public void showActivatePINDialog(PINSpec pin, + ActionListener okListener, String okCmd, + ActionListener cancelListener, String cancelCmd); + + public void showChangePINDialog(PINSpec pin, + ActionListener okListener, String okCmd, + ActionListener cancelListener, String cancelCmd); + + public void showUnblockPINDialog(PINSpec pin, + ActionListener okListener, String okCmd, + ActionListener cancelListener, String cancelCmd); + + public char[] getOldPin(); + + public PINSpec getSelectedPIN(); } diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINSpecRenderer.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINSpecRenderer.java new file mode 100644 index 00000000..e3d73e1f --- /dev/null +++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINSpecRenderer.java @@ -0,0 +1,39 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + * + * 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 at.gv.egiz.bku.gui; + +import at.gv.egiz.smcc.PINSpec; +import javax.swing.table.DefaultTableCellRenderer; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author Clemens Orthacker + */ +public class PINSpecRenderer extends DefaultTableCellRenderer { + + private static final Log log = LogFactory.getLog(PINSpecRenderer.class); + + @Override + protected void setValue(Object value) { + PINSpec pinSpec = (PINSpec) value; + super.setText(pinSpec.getLocalizedName()); + } + +} diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusProvider.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusProvider.java deleted file mode 100644 index 73fa0920..00000000 --- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology - * - * 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 at.gv.egiz.bku.gui; - -import at.gv.egiz.smcc.SignatureCardException; - -/** - * - * @author Clemens Orthacker - */ -public interface PINStatusProvider { - - public enum STATUS { ACTIV, NOT_ACTIV, BLOCKED }; - - public STATUS getPINStatus(int pin) throws SignatureCardException; - -} diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusRenderer.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusRenderer.java new file mode 100644 index 00000000..2f8852ff --- /dev/null +++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusRenderer.java @@ -0,0 +1,63 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + * + * 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 at.gv.egiz.bku.gui; + +import at.gv.egiz.bku.gui.PINManagementGUIFacade.STATUS; +import java.awt.Color; +import java.awt.Font; +import java.util.ResourceBundle; +import javax.swing.table.DefaultTableCellRenderer; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author Clemens Orthacker + */ +public class PINStatusRenderer extends DefaultTableCellRenderer { + + private static final Log log = LogFactory.getLog(PINStatusRenderer.class); + + public static final Color RED = new Color(0.9f, 0.0f, 0.0f); + public static final Color GREEN = new Color(0.0f, 0.8f, 0.0f); + protected ResourceBundle messages; + + public PINStatusRenderer(ResourceBundle messages) { + this.messages = messages; + } + + @Override + protected void setValue(Object value) { + STATUS pinStatus = (STATUS) value; + super.setFont(super.getFont().deriveFont(super.getFont().getStyle() | Font.BOLD)); + + if (pinStatus == STATUS.NOT_ACTIV) { + super.setForeground(RED); + super.setText("" + messages.getString(PINManagementGUIFacade.STATUS_NOT_ACTIVE) + ""); + } else if (pinStatus == STATUS.ACTIV) { + super.setForeground(GREEN); + super.setText("" + messages.getString(PINManagementGUIFacade.STATUS_ACTIVE) + ""); + } else if (pinStatus == STATUS.BLOCKED) { + super.setForeground(RED); + super.setText("" + messages.getString(PINManagementGUIFacade.STATUS_BLOCKED) + ""); + } else { + super.setForeground(Color.BLACK); + super.setText("" + messages.getString(PINManagementGUIFacade.STATUS_UNKNOWN) + ""); + } + } +} diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusTableModel.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusTableModel.java new file mode 100644 index 00000000..feaa5072 --- /dev/null +++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/gui/PINStatusTableModel.java @@ -0,0 +1,60 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + * + * 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 at.gv.egiz.bku.gui; + +import at.gv.egiz.bku.gui.PINManagementGUIFacade.STATUS; +import at.gv.egiz.smcc.PINSpec; +import java.util.Map; +import javax.swing.table.DefaultTableModel; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author Clemens Orthacker + */ +public class PINStatusTableModel extends DefaultTableModel { + + protected static final Log log = LogFactory.getLog(PINStatusTableModel.class); + protected Class[] types; + + public PINStatusTableModel(Map pinStatuses) { + super(0, 2); + if (pinStatuses == null) { + throw new RuntimeException("pinStatuses must not be null"); + } + log.trace(pinStatuses.size() + " PINs"); + types = new Class[] { PINSpec.class, STATUS.class }; + for (PINSpec pinSpec : pinStatuses.keySet()) { + addRow(new Object[] { pinSpec, pinStatuses.get(pinSpec) }); + } +// PINSpec activePIN = new PINSpec(0, 1, null, "active-PIN", (byte) 0x01); +// PINSpec blockedPIN = new PINSpec(0, 1, null, "blocked-PIN", (byte) 0x01); +// addRow(new Object[] { activePIN, PINStatusProvider.STATUS.ACTIV }); +// addRow(new Object[] { blockedPIN, PINStatusProvider.STATUS.BLOCKED }); + } + + @Override + public Class getColumnClass(int columnIndex) { + return types[columnIndex]; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } +} diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/PINManagementApplet.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/PINManagementApplet.java index 72d06618..d948ac03 100644 --- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/PINManagementApplet.java +++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/PINManagementApplet.java @@ -19,6 +19,7 @@ package at.gv.egiz.bku.online.applet; import at.gv.egiz.bku.gui.AbstractHelpListener; import at.gv.egiz.bku.gui.BKUGUIFacade; import at.gv.egiz.bku.gui.PINManagementGUI; +import at.gv.egiz.bku.gui.PINManagementGUIFacade; import java.awt.Container; import java.net.URL; import java.util.Locale; @@ -45,6 +46,6 @@ public class PINManagementApplet extends BKUApplet { @Override protected AppletBKUWorker createBKUWorker(BKUApplet applet, BKUGUIFacade gui) { - return new PINManagementBKUWorker(applet, gui); + return new PINManagementBKUWorker(applet, (PINManagementGUIFacade) gui); } } diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/PINManagementBKUWorker.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/PINManagementBKUWorker.java index e65d98ca..ffd83e42 100644 --- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/PINManagementBKUWorker.java +++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/PINManagementBKUWorker.java @@ -18,35 +18,28 @@ package at.gv.egiz.bku.online.applet; import at.gv.egiz.bku.gui.BKUGUIFacade; import at.gv.egiz.bku.gui.PINManagementGUIFacade; -import at.gv.egiz.bku.smccstal.ext.PINMgmtRequestHandler; +import at.gv.egiz.bku.smccstal.ext.PINManagementRequestHandler; +import at.gv.egiz.stal.ErrorResponse; import at.gv.egiz.stal.STALResponse; -import at.gv.egiz.stal.ext.ActivatePINRequest; -import at.gv.egiz.stal.ext.ChangePINRequest; -import at.gv.egiz.stal.ext.UnblockPINRequest; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.Collection; +import at.gv.egiz.stal.ext.PINManagementRequest; +import at.gv.egiz.stal.ext.PINManagementResponse; import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** - * + * This BKU Worker does not connect to STAL webservice + * (no Internet connection permitted while activating PINs). + * * @author Clemens Orthacker */ public class PINManagementBKUWorker extends AppletBKUWorker { - protected PINMgmtRequestHandler handler = new PINMgmtRequestHandler(); - protected PINManagementActionListener listener = new PINManagementActionListener(); - - public PINManagementBKUWorker(BKUApplet applet, BKUGUIFacade gui) { + public PINManagementBKUWorker(BKUApplet applet, PINManagementGUIFacade gui) { super(applet, gui); handlerMap.clear(); -// PINMgmtRequestHandler handler = new PINMgmtRequestHandler(); -// addRequestHandler(ActivatePINRequest.class, handler); -// addRequestHandler(ChangePINRequest.class, handler); -// addRequestHandler(UnblockPINRequest.class, handler); + addRequestHandler(PINManagementRequest.class, new PINManagementRequestHandler()); } @Override @@ -54,22 +47,24 @@ public class PINManagementBKUWorker extends AppletBKUWorker { gui.showWelcomeDialog(); try { - - if (waitForCard()) { - gui.showErrorDialog("no card, canceled PIN mgmt dialog", null); + List responses = handleRequest(Collections.singletonList(new PINManagementRequest())); + + if (responses.size() == 1) { + STALResponse response = responses.get(0); + if (response instanceof PINManagementResponse) { + log.debug("PIN management dialog finished"); + } else if (response instanceof ErrorResponse) { + showErrorDialog(BKUGUIFacade.ERR_UNKNOWN, null); + } else { + throw new RuntimeException("Invalid STAL response: " + response.getClass().getName()); + } + } else { + throw new RuntimeException("invalid number of STAL responses: " + responses.size()); } - actionCommandList.clear(); - actionCommandList.add("cancel"); - - ((PINManagementGUIFacade) gui).showPINManagementDialog(handler, - listener, "activate", - listener, "change", - listener, "unblock", - this, "cancel"); - - waitForAction(); - + } catch (RuntimeException ex) { + log.error("unexpected error: " + ex.getMessage(), ex); + showErrorDialog(BKUGUIFacade.ERR_UNKNOWN, null); } catch (Exception ex) { log.error(ex.getMessage(), ex); showErrorDialog(BKUGUIFacade.ERR_UNKNOWN_WITH_PARAM, ex); @@ -82,31 +77,4 @@ public class PINManagementBKUWorker extends AppletBKUWorker { applet.sendRedirect(sessionId); } - protected class PINManagementActionListener implements ActionListener { - - @Override - public void actionPerformed(ActionEvent e) { - try { - String cmd = e.getActionCommand(); - if ("activate".equals(cmd)) { - //create STAL request, call handle(req) - ActivatePINRequest stalReq = new ActivatePINRequest(); - STALResponse stalResp = handler.handleRequest(stalReq); - gui.showErrorDialog(BKUGUIFacade.ERR_UNKNOWN_WITH_PARAM, new Object[]{"debug"}, this, "back"); - } else if ("change".equals(cmd)) { - } else if ("unblock".equals(cmd)) { - } else if ("back".equals(cmd)) { - - ((PINManagementGUIFacade) gui).showPINManagementDialog(handler, - this, "activate", - this, "change", - this, "unblock", - PINManagementBKUWorker.this, "cancel"); - - } - } catch (InterruptedException ex) { - log.fatal(ex); - } - } } -} diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PINManagementRequestHandler.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PINManagementRequestHandler.java new file mode 100644 index 00000000..fcef3191 --- /dev/null +++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PINManagementRequestHandler.java @@ -0,0 +1,331 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + * + * 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 at.gv.egiz.bku.smccstal.ext; + +import at.gv.egiz.bku.gui.BKUGUIFacade; +import at.gv.egiz.bku.gui.PINManagementGUIFacade; +import at.gv.egiz.bku.gui.PINManagementGUIFacade.STATUS; +import at.gv.egiz.bku.smccstal.AbstractRequestHandler; +import at.gv.egiz.smcc.PINSpec; +import at.gv.egiz.smcc.SignatureCardException; +import at.gv.egiz.smcc.util.SMCCHelper; +import at.gv.egiz.stal.ErrorResponse; +import at.gv.egiz.stal.STALRequest; +import at.gv.egiz.stal.STALResponse; +import at.gv.egiz.stal.ext.PINManagementRequest; +import at.gv.egiz.stal.ext.PINManagementResponse; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.smartcardio.Card; +import javax.smartcardio.CardChannel; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author Clemens Orthacker + */ +public class PINManagementRequestHandler extends AbstractRequestHandler { + + public static final String ERR_NOPIN_SELECTED = "err.no.pin.selected"; + protected static final Log log = LogFactory.getLog(PINManagementRequestHandler.class); + +// protected ResourceBundle messages; + +// public PINManagementRequestHandler(ResourceBundle messages) { +// this.messages = messages; +// } + @Override + public STALResponse handleRequest(STALRequest request) throws InterruptedException { + if (request instanceof PINManagementRequest) { + + PINManagementGUIFacade gui = (PINManagementGUIFacade) this.gui; + + showPINManagementDialog(gui); + + while (true) { + + waitForAction(); + + if ("cancel".equals(actionCommand)) { + return new PINManagementResponse(); + } else if ("back".equals(actionCommand)) { + showPINManagementDialog(gui); + } else { + PINSpec selectedPIN = gui.getSelectedPIN(); + + if (selectedPIN == null) { + throw new RuntimeException("no PIN selected for activation/change"); + } + + if ("activate_enterpin".equals(actionCommand)) { + gui.showActivatePINDialog(selectedPIN, this, "activate", this, "back"); + } else if ("change_enterpin".equals(actionCommand)) { + gui.showChangePINDialog(selectedPIN, this, "change", this, "back"); + } else if ("unblock_enterpuk".equals(actionCommand)) { + gui.showUnblockPINDialog(selectedPIN, this, "unblock", this, "back"); + } else if ("activate".equals(actionCommand)) { + try { + byte[] pin = encodePIN(gui.getPin()); + activatePIN(selectedPIN.getKID(), selectedPIN.getContextAID(), pin); + showPINManagementDialog(gui); + } catch (SignatureCardException ex) { + log.error("failed to activate " + selectedPIN.getLocalizedName() + ": " + ex.getMessage()); + gui.showErrorDialog(PINManagementGUIFacade.ERR_ACTIVATE, + new Object[] {selectedPIN.getLocalizedName()}, + this, "cancel"); + } + } else if ("change".equals(actionCommand)) { + try { + byte[] oldPin = encodePIN(gui.getOldPin()); //new byte[]{(byte) 0x25, (byte) 0x40, (byte) 0x01}; + byte[] pin = encodePIN(gui.getPin()); //new byte[]{(byte) 0x25, (byte) 0x40}; + changePIN(selectedPIN.getKID(), selectedPIN.getContextAID(), oldPin, pin); + showPINManagementDialog(gui); + } catch (SignatureCardException ex) { + log.error("failed to change " + selectedPIN.getLocalizedName() + ": " + ex.getMessage()); + gui.showErrorDialog(PINManagementGUIFacade.ERR_CHANGE, + new Object[] {selectedPIN.getLocalizedName()}, + this, "cancel"); + } + } else if ("unblock".equals(actionCommand)) { + log.error("unblock PIN not implemented"); + gui.showErrorDialog(PINManagementGUIFacade.ERR_UNBLOCK, null, this, "cancel"); + } else { + throw new RuntimeException("unsupported action " + actionCommand); + } + } + } + } else { + log.error("Got unexpected STAL request: " + request); + return new ErrorResponse(1000); + } + } + + @Override + public boolean requireCard() { + return true; + } + + /** + * pin.length < 4bit + * @param kid + * @param contextAID + * @param pin + * @throws at.gv.egiz.smcc.SignatureCardException + */ + private void activatePIN(byte kid, byte[] contextAID, byte[] pin) throws SignatureCardException { + try { + Card icc = card.getCard(); + icc.beginExclusive(); + CardChannel channel = icc.getBasicChannel(); + + if (contextAID != null) { + CommandAPDU selectAPDU = new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, contextAID); + ResponseAPDU responseAPDU = channel.transmit(selectAPDU); + if (responseAPDU.getSW() != 0x9000) { + String msg = "Failed to activate PIN " + SMCCHelper.toString(new byte[]{kid}) + + ": Failed to select AID " + SMCCHelper.toString(contextAID) + + ": " + SMCCHelper.toString(responseAPDU.getBytes()); + log.error(msg); + throw new SignatureCardException(msg); + } + } + + if (pin.length > 7) { + log.error("Invalid PIN"); + throw new SignatureCardException("Invalid PIN"); + } + byte length = (byte) (0x20 | pin.length * 2); + + byte[] apdu = new byte[]{ + (byte) 0x00, (byte) 0x24, (byte) 0x01, kid, (byte) 0x08, + (byte) length, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; + for (int i = 0; i < pin.length; i++) { + apdu[i + 6] = pin[i]; + } + + CommandAPDU verifyAPDU = new CommandAPDU(apdu); + ResponseAPDU responseAPDU = channel.transmit(verifyAPDU); + + if (responseAPDU.getSW() != 0x9000) { + String msg = "Failed to activate PIN " + SMCCHelper.toString(new byte[]{kid}) + ": " + SMCCHelper.toString(responseAPDU.getBytes()); + log.error(msg); + throw new SignatureCardException(msg); + } + + + icc.endExclusive(); + + + } catch (CardException ex) { + log.error("Failed to get PIN status: " + ex.getMessage()); + throw new SignatureCardException("Failed to get PIN status", ex); + } + } + + private void changePIN(byte kid, byte[] contextAID, byte[] oldPIN, byte[] newPIN) throws SignatureCardException { + try { + Card icc = card.getCard(); + icc.beginExclusive(); + CardChannel channel = icc.getBasicChannel(); + + if (contextAID != null) { + CommandAPDU selectAPDU = new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, contextAID); + ResponseAPDU responseAPDU = channel.transmit(selectAPDU); + if (responseAPDU.getSW() != 0x9000) { + String msg = "Failed to change PIN " + SMCCHelper.toString(new byte[]{kid}) + + ": Failed to select AID " + SMCCHelper.toString(contextAID) + + ": " + SMCCHelper.toString(responseAPDU.getBytes()); + log.error(msg); + throw new SignatureCardException(msg); + } + } + + if (oldPIN.length > 7 || newPIN.length > 7) { + log.error("Invalid PIN"); + throw new SignatureCardException("Invalid PIN"); + } + byte oldLength = (byte) (0x20 | oldPIN.length * 2); + byte newLength = (byte) (0x20 | newPIN.length * 2); + + byte[] apdu = new byte[]{ + (byte) 0x00, (byte) 0x24, (byte) 0x00, kid, (byte) 0x10, + oldLength, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + newLength, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; + for (int i = 0; i < oldPIN.length; i++) { + apdu[i + 6] = oldPIN[i]; + } + for (int i = 0; i < newPIN.length; i++) { + apdu[i + 14] = newPIN[i]; + } + + CommandAPDU verifyAPDU = new CommandAPDU(apdu); + ResponseAPDU responseAPDU = channel.transmit(verifyAPDU); + + if (responseAPDU.getSW() != 0x9000) { + String msg = "Failed to change PIN " + SMCCHelper.toString(new byte[]{kid}) + ": " + SMCCHelper.toString(responseAPDU.getBytes()); + log.error(msg); + throw new SignatureCardException(msg); + } + + + icc.endExclusive(); + + + } catch (CardException ex) { + log.error("Failed to get PIN status: " + ex.getMessage()); + throw new SignatureCardException("Failed to get PIN status", ex); + } + } + + public Map getPINStatuses() throws SignatureCardException { + try { + Card icc = card.getCard(); + icc.beginExclusive(); + CardChannel channel = icc.getBasicChannel(); + + HashMap pinStatuses = new HashMap(); + List pins = card.getPINSpecs(); + + //select DF_SichereSignatur 00 A4 04 0C 08 D0 40 00 00 17 00 12 01 +// CommandAPDU selectAPDU = new CommandAPDU(new byte[]{(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x0c, (byte) 0x08, +// (byte) 0xd0, (byte) 0x40, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00, (byte) 0x12, (byte) 0x01}); +// ResponseAPDU rAPDU = channel.transmit(selectAPDU); +// log.debug("SELECT FILE DF_SichereSignatur: " + SMCCHelper.toString(rAPDU.getBytes())); + + //select DF_SIG DF 70 +// CommandAPDU selectAPDU = new CommandAPDU(new byte[]{(byte) 0x00, (byte) 0xa4, (byte) 0x00, (byte) 0x0c, (byte) 0x02, +// (byte) 0xdf, (byte) 0x70 }); +// ResponseAPDU rAPDU = channel.transmit(selectAPDU); +// log.debug("SELECT FILE DF_SIG: " + SMCCHelper.toString(rAPDU.getBytes())); + + //select DF_DEC DF 71 +// CommandAPDU selectAPDU = new CommandAPDU(new byte[]{(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x0c, (byte) 0x08, +// (byte) 0xd0, (byte) 0x40, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00, (byte) 0x12, (byte) 0x01}); +// ResponseAPDU rAPDU = channel.transmit(selectAPDU); +// log.debug("SELECT FILE DF_SichereSignatur: " + SMCCHelper.toString(rAPDU.getBytes())); + + for (PINSpec pinSpec : pins) { + byte kid = pinSpec.getKID(); + byte[] contextAID = pinSpec.getContextAID(); + + if (contextAID != null) { + CommandAPDU selectAPDU = new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, contextAID); + ResponseAPDU responseAPDU = channel.transmit(selectAPDU); + if (responseAPDU.getSW() != 0x9000) { + String msg = "Failed to activate PIN " + SMCCHelper.toString(new byte[]{kid}) + + ": Failed to select AID " + SMCCHelper.toString(contextAID) + + ": " + SMCCHelper.toString(responseAPDU.getBytes()); + log.error(msg); + throw new SignatureCardException(msg); + } + } + + CommandAPDU verifyAPDU = new CommandAPDU(new byte[]{(byte) 0x00, (byte) 0x20, (byte) 00, kid}); + ResponseAPDU responseAPDU = channel.transmit(verifyAPDU); + + STATUS status = STATUS.UNKNOWN; + if (responseAPDU.getSW() == 0x6984) { + status = STATUS.NOT_ACTIV; + } else if (responseAPDU.getSW() == 0x63c0) { + status = STATUS.BLOCKED; + } else if (responseAPDU.getSW1() == 0x63) { + status = STATUS.ACTIV; + } + if (log.isDebugEnabled()) { + log.debug("PIN " + pinSpec.getLocalizedName() + " status: " + SMCCHelper.toString(responseAPDU.getBytes())); + } + + pinStatuses.put(pinSpec, status); + } + icc.endExclusive(); + + return pinStatuses; + + } catch (CardException ex) { + log.error("Failed to get PIN status: " + ex.getMessage()); + throw new SignatureCardException("Failed to get PIN status", ex); + } + } + + private byte[] encodePIN(char[] pinChars) { + int length = (int) Math.ceil(pinChars.length/2); + byte[] pin = new byte[length]; + for (int i = 0; i < length; i++) { + pin[i] = (byte) (16*Character.digit(pinChars[i*2], 16) + Character.digit(pinChars[i*2+1], 16)); + } + log.trace("***** " + SMCCHelper.toString(pin) + " ******"); + return pin; + } + + private void showPINManagementDialog(PINManagementGUIFacade gui) { + try { + Map pins = getPINStatuses(); + gui.showPINManagementDialog(pins, + this, "activate_enterpin", "change_enterpin", "unblock_enterpuk", + this, "cancel"); + } catch (SignatureCardException ex) { + gui.showErrorDialog(BKUGUIFacade.ERR_UNKNOWN_WITH_PARAM, + new Object[]{"FAILED TO GET PIN STATUSES: " + ex.getMessage()}, + this, "cancel"); + } + } +} diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PINMgmtRequestHandler.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PINMgmtRequestHandler.java deleted file mode 100644 index b2d34ff2..00000000 --- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/smccstal/ext/PINMgmtRequestHandler.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology - * - * 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 at.gv.egiz.bku.smccstal.ext; - -import at.gv.egiz.bku.gui.PINStatusProvider; -import at.gv.egiz.bku.smccstal.AbstractRequestHandler; -import at.gv.egiz.smcc.SignatureCardException; -import at.gv.egiz.stal.ErrorResponse; -import at.gv.egiz.stal.STALRequest; -import at.gv.egiz.stal.STALResponse; -import at.gv.egiz.stal.ext.ActivatePINRequest; -import at.gv.egiz.stal.ext.ChangePINRequest; -import at.gv.egiz.stal.ext.UnblockPINRequest; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.smartcardio.Card; -import javax.smartcardio.CardChannel; -import javax.smartcardio.CardException; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * - * @author Clemens Orthacker - */ -public class PINMgmtRequestHandler extends AbstractRequestHandler implements PINStatusProvider { - - protected static final Log log = LogFactory.getLog(PINMgmtRequestHandler.class); - - @Override - public STALResponse handleRequest(STALRequest request) throws InterruptedException { - if (request instanceof ActivatePINRequest) { - log.error("not implemented yet"); - return new ErrorResponse(1000); - - } else if (request instanceof ChangePINRequest) { - log.error("not implemented yet"); - return new ErrorResponse(1000); - - } else if (request instanceof UnblockPINRequest) { - log.error("not implemented yet"); - return new ErrorResponse(1000); - - } else { - log.error("Got unexpected STAL request: " + request); - return new ErrorResponse(1000); - } - } - - @Override - public boolean requireCard() { - return true; - } - - @Override - public STATUS getPINStatus(int pin) throws SignatureCardException { - try { - Card icc = card.getCard(); - icc.beginExclusive(); - CardChannel channel = icc.getBasicChannel(); - CommandAPDU verifyAPDU = new CommandAPDU(new byte[] {(byte) 0x00} ); - ResponseAPDU responseAPDU = channel.transmit(verifyAPDU); - byte sw1 = (byte) responseAPDU.getSW1(); - byte[] sw = new byte[] { - (byte) (0xFF & responseAPDU.getSW1()), - (byte) (0xFF & responseAPDU.getSW2()) }; - - icc.endExclusive(); - return STATUS.ACTIV; - } catch (CardException ex) { - log.error("Failed to get PIN status: " + ex.getMessage()); - throw new SignatureCardException("Failed to get PIN status", ex); - } - } - -} diff --git a/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages.properties b/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages.properties index 469af15f..e51044af 100644 --- a/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages.properties +++ b/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages.properties @@ -15,10 +15,34 @@ title.activation=Aktivierung title.pin.mgmt=PIN Verwaltung -message.pin.mgmt=under construction +title.activate.pin=PIN Aktivieren +title.change.pin=PIN \u00C4ndern +title.unblock.pin=PIN Entsperren + +message.pin.mgmt=Die Karte verf\u00FCgt \u00FCber {0} PINs +message.activate.pin={0} eingeben und best\u00E4tigen +message.change.pin={0} eingeben und best\u00E4tigen +message.unblock.pin=PUK zu {0} eingeben + label.activation=e-card Aktivierungsprozess label.activation.step=Schritt {0} label.activation.idle=Warte auf Server... +label.old.pin=Alte {0}: +label.new.pin=Neue {0}: +label.repeat.pin=Best\u00E4tigung: + button.activate=Aktivieren button.change=\u00C4ndern -button.unblock=Entsperren \ No newline at end of file +button.unblock=Entsperren + +help.activation=help.activation +help.pin.mgmt=help.pin.mgmt + +err.activate=Beim Aktivieren der {0} trat ein Fehler auf. +err.change=Beim \u00C4ndern der {0} trat ein Fehler auf. +err.unblock=Das Entsperren der {0} wird nicht unterst\u00FCtzt. + +status.not.active=NICHT AKTIV +status.active=AKTIV +status.blocked=GESPERRT +status.unknown=UNBEKANNT diff --git a/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages_en.properties b/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages_en.properties index 16ac7d0b..1cf4a102 100644 --- a/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages_en.properties +++ b/BKUAppletExt/src/main/resources/at/gv/egiz/bku/gui/ActivationMessages_en.properties @@ -13,12 +13,36 @@ # See the License for the specific language governing permissions and # limitations under the License. -title.activation=Aktivation +title.activation=Activation title.pin.mgmt=PIN Management -message.pin.mgmt=under construction +title.activate.pin=Activate PIN +title.change.pin=Change PIN +title.unblock.pin=Unblock PIN + +message.pin.mgmt=The smartcard has {0} PINs +message.activate.pin=Enter and confirm {0} +message.change.pin=Enter and confirm {0} +message.unblock.pin=Enter PUK for {0} + label.activation=e-card activation process label.activation.step=Step {0} label.activation.idle=Wait for server... +label.old.pin=Old {0}: +label.new.pin=New {0}: +label.repeat.pin=Confirmation: + button.activate=Activate button.change=Change -button.unblock=Unblock \ No newline at end of file +button.unblock=Unblock + +help.activation=help.activation +help.pin.mgmt=help.pin.mgmt + +err.activate=An error occured during activation of {0}. +err.change=An error occured during changing of {0}. +err.unblock=Unblocking of {0} is not supported. + +status.not.active=Not active +status.active=Active +status.blocked=Blocked +status.unknown=Unknown diff --git a/BKUAppletExt/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java b/BKUAppletExt/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java index 669a63fc..ef8c87e4 100644 --- a/BKUAppletExt/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java +++ b/BKUAppletExt/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java @@ -25,8 +25,6 @@ import at.gv.egiz.stal.HashDataInput; import at.gv.egiz.stal.impl.ByteArrayHashDataInput; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.io.ByteArrayInputStream; -import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -46,7 +44,7 @@ public class BKUGUIWorker implements Runnable { public void run() { try { - final PINSpec signPinSpec = new PINSpec(6, 10, "[0-9]", "Signatur-PIN"); + final PINSpec signPinSpec = new PINSpec(6, 10, "[0-9]", "Signatur-PIN", (byte)0x00, null); final ActionListener cancelListener = new ActionListener() { diff --git a/BKUAppletExt/src/test/resources/appletTest.html b/BKUAppletExt/src/test/resources/appletTest.html index 9add4309..813ee1f0 100644 --- a/BKUAppletExt/src/test/resources/appletTest.html +++ b/BKUAppletExt/src/test/resources/appletTest.html @@ -19,7 +19,7 @@
+ width=270 height=180> diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java index f564c07a..1d5a2cf4 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java @@ -38,9 +38,6 @@ import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.CellRendererPane; import javax.swing.GroupLayout; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -51,7 +48,6 @@ import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JScrollPane; import javax.swing.JTable; -import javax.swing.JTextField; import javax.swing.LayoutStyle; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; @@ -1064,7 +1060,9 @@ public class BKUGUIImpl implements BKUGUIFacade { @Override public char[] getPin() { if (pinField != null) { - return pinField.getPassword(); + char[] pin = pinField.getPassword(); + pinField = null; + return pin; } return null; } diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/PinDocument.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/PinDocument.java index 2054ae86..87b636f0 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/PinDocument.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/PinDocument.java @@ -22,6 +22,7 @@ import java.util.regex.Pattern; import javax.swing.JButton; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; +import javax.swing.text.Document; import javax.swing.text.PlainDocument; /** @@ -30,9 +31,10 @@ import javax.swing.text.PlainDocument; */ class PINDocument extends PlainDocument { - private PINSpec pinSpec; - private Pattern pinPattern; - private JButton enterButton; + protected PINSpec pinSpec; + protected Pattern pinPattern; + protected JButton enterButton; + protected Document compareTo; public PINDocument(PINSpec pinSpec, JButton enterButton) { this.pinSpec = pinSpec; @@ -44,6 +46,11 @@ class PINDocument extends PlainDocument { this.enterButton = enterButton; } + public PINDocument(PINSpec pinSpec, JButton enterButton, Document compareTo) { + this(pinSpec, enterButton); + this.compareTo = compareTo; + } + @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { if (pinSpec.getMaxLength() < 0 || pinSpec.getMaxLength() >= (getLength() + str.length())) { @@ -58,12 +65,23 @@ class PINDocument extends PlainDocument { super.insertString(offs, str, a); } } - enterButton.setEnabled(getLength() >= pinSpec.getMinLength()); + if (enterButton != null) { + enterButton.setEnabled(getLength() >= pinSpec.getMinLength() && compare()); + } } @Override public void remove(int offs, int len) throws BadLocationException { super.remove(offs, len); - enterButton.setEnabled(getLength() >= pinSpec.getMinLength()); + if (enterButton != null) { + enterButton.setEnabled(getLength() >= pinSpec.getMinLength() && compare()); + } + } + + private boolean compare() throws BadLocationException { + if (compareTo == null) { + return true; + } + return compareTo.getText(0, compareTo.getLength()).equals(getText(0, getLength())); } } \ No newline at end of file diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties index 8436a730..1e0bc9f5 100644 --- a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties @@ -20,7 +20,7 @@ title.cardnotsupported=Die Karte wird nicht unterst\u00FCtzt title.cardpin=Karte wird gelesen title.sign=Signatur erstellen title.error=Fehler -title.retry=Falscher PIN +title.retry=Falsche PIN title.wait=Bitte warten title.hashdata=Signaturdaten windowtitle.save=Signaturdaten speichern @@ -84,7 +84,7 @@ help.cardnotsupported=Nicht unterst\u00FCtzte B\u00FCrgerkarte help.insertcard=Keine B\u00FCrgerkarte im Kartenleser help.cardpin=Pineingabe help.signpin=Signatur-Pineingabe -help.retry=Falscher Pin +help.retry=Falsche Pin help.hashdata=Signierte Inhalte help.hashdatalist=Signierte Inhalte help.hashdataviewer=Anzeige signierter Inhalte \ No newline at end of file diff --git a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java index 73aaab46..08ecaa7f 100644 --- a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java +++ b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java @@ -46,7 +46,7 @@ public class BKUGUIWorker implements Runnable { public void run() { // try { - final PINSpec signPinSpec = new PINSpec(6, 10, "[0-9]", "Signatur-PIN"); + final PINSpec signPinSpec = new PINSpec(6, 10, "[0-9]", "Signatur-PIN", (byte) 0x81, null); final ActionListener cancelListener = new ActionListener() { diff --git a/STALExt/src/main/java/at/gv/egiz/stal/ext/ActivatePINRequest.java b/STALExt/src/main/java/at/gv/egiz/stal/ext/ActivatePINRequest.java deleted file mode 100644 index f2039388..00000000 --- a/STALExt/src/main/java/at/gv/egiz/stal/ext/ActivatePINRequest.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology - * - * 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 at.gv.egiz.stal.ext; - -import at.gv.egiz.stal.STALRequest; - -/** - * - * @author Clemens Orthacker - */ -public class ActivatePINRequest extends STALRequest { - -} diff --git a/STALExt/src/main/java/at/gv/egiz/stal/ext/ChangePINRequest.java b/STALExt/src/main/java/at/gv/egiz/stal/ext/ChangePINRequest.java deleted file mode 100644 index ea508146..00000000 --- a/STALExt/src/main/java/at/gv/egiz/stal/ext/ChangePINRequest.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology - * - * 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 at.gv.egiz.stal.ext; - -import at.gv.egiz.stal.STALRequest; - -/** - * - * @author Clemens Orthacker - */ -public class ChangePINRequest extends STALRequest { - -} diff --git a/STALExt/src/main/java/at/gv/egiz/stal/ext/PINManagementRequest.java b/STALExt/src/main/java/at/gv/egiz/stal/ext/PINManagementRequest.java new file mode 100644 index 00000000..87c53e24 --- /dev/null +++ b/STALExt/src/main/java/at/gv/egiz/stal/ext/PINManagementRequest.java @@ -0,0 +1,31 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + * + * 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 at.gv.egiz.stal.ext; + +import at.gv.egiz.stal.STALRequest; + +/** + * Dummy STAL request to trigger PIN Management. (no proper STAL requests + * for PIN activation, unblocking) + * + * + * @author Clemens Orthacker + */ +public class PINManagementRequest extends STALRequest { + +} diff --git a/STALExt/src/main/java/at/gv/egiz/stal/ext/PINManagementResponse.java b/STALExt/src/main/java/at/gv/egiz/stal/ext/PINManagementResponse.java new file mode 100644 index 00000000..b8b90604 --- /dev/null +++ b/STALExt/src/main/java/at/gv/egiz/stal/ext/PINManagementResponse.java @@ -0,0 +1,28 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + * + * 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 at.gv.egiz.stal.ext; + +import at.gv.egiz.stal.STALResponse; + +/** + * + * @author Clemens Orthacker + */ +public class PINManagementResponse extends STALResponse { + +} diff --git a/STALExt/src/main/java/at/gv/egiz/stal/ext/UnblockPINRequest.java b/STALExt/src/main/java/at/gv/egiz/stal/ext/UnblockPINRequest.java deleted file mode 100644 index 543de31c..00000000 --- a/STALExt/src/main/java/at/gv/egiz/stal/ext/UnblockPINRequest.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology - * - * 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 at.gv.egiz.stal.ext; - -import at.gv.egiz.stal.STALRequest; - -/** - * - * @author Clemens Orthacker - */ -public class UnblockPINRequest extends STALRequest { - -} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java index ae4918ce..b64306aa 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java @@ -14,98 +14,105 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package at.gv.egiz.bku.slcommands.impl.xsect; - -import iaik.xml.crypto.dom.DOMCryptoContext; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.SequenceInputStream; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.net.URISyntaxException; -import java.nio.charset.Charset; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; +package at.gv.egiz.bku.slcommands.impl.xsect; + +import iaik.xml.crypto.dom.DOMCryptoContext; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.SequenceInputStream; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; +import java.nio.charset.Charset; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.xml.crypto.MarshalException; -import javax.xml.crypto.dom.DOMStructure; -import javax.xml.crypto.dsig.CanonicalizationMethod; -import javax.xml.crypto.dsig.DigestMethod; -import javax.xml.crypto.dsig.Reference; -import javax.xml.crypto.dsig.Transform; -import javax.xml.crypto.dsig.XMLObject; -import javax.xml.crypto.dsig.spec.TransformParameterSpec; -import javax.xml.crypto.dsig.spec.XPathFilter2ParameterSpec; -import javax.xml.crypto.dsig.spec.XPathType; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.w3c.dom.DOMConfiguration; -import org.w3c.dom.DOMException; -import org.w3c.dom.Document; -import org.w3c.dom.DocumentFragment; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.Text; -import org.w3c.dom.bootstrap.DOMImplementationRegistry; -import org.w3c.dom.ls.DOMImplementationLS; -import org.w3c.dom.ls.LSException; -import org.w3c.dom.ls.LSInput; -import org.w3c.dom.ls.LSOutput; -import org.w3c.dom.ls.LSParser; -import org.w3c.dom.ls.LSSerializer; - -import at.buergerkarte.namespaces.securitylayer._1.Base64XMLLocRefOptRefContentType; -import at.buergerkarte.namespaces.securitylayer._1.DataObjectInfoType; -import at.buergerkarte.namespaces.securitylayer._1.MetaInfoType; -import at.buergerkarte.namespaces.securitylayer._1.TransformsInfoType; -import at.gv.egiz.bku.binding.HttpUtil; -import at.gv.egiz.bku.slexceptions.SLCommandException; -import at.gv.egiz.bku.slexceptions.SLRequestException; -import at.gv.egiz.bku.slexceptions.SLRuntimeException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.crypto.MarshalException; +import javax.xml.crypto.dom.DOMStructure; +import javax.xml.crypto.dsig.CanonicalizationMethod; +import javax.xml.crypto.dsig.DigestMethod; +import javax.xml.crypto.dsig.Reference; +import javax.xml.crypto.dsig.Transform; +import javax.xml.crypto.dsig.XMLObject; +import javax.xml.crypto.dsig.spec.TransformParameterSpec; +import javax.xml.crypto.dsig.spec.XPathFilter2ParameterSpec; +import javax.xml.crypto.dsig.spec.XPathType; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3._2000._09.xmldsig_.TransformType; +import org.w3._2000._09.xmldsig_.TransformsType; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import org.w3c.dom.bootstrap.DOMImplementationRegistry; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSException; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSParser; +import org.w3c.dom.ls.LSSerializer; + +import at.buergerkarte.namespaces.securitylayer._1.Base64XMLLocRefOptRefContentType; +import at.buergerkarte.namespaces.securitylayer._1.DataObjectInfoType; +import at.buergerkarte.namespaces.securitylayer._1.MetaInfoType; +import at.buergerkarte.namespaces.securitylayer._1.TransformsInfoType; +import at.gv.egiz.bku.binding.HttpUtil; +import at.gv.egiz.bku.slexceptions.SLCommandException; +import at.gv.egiz.bku.slexceptions.SLRequestException; +import at.gv.egiz.bku.slexceptions.SLRuntimeException; import at.gv.egiz.bku.slexceptions.SLViewerException; -import at.gv.egiz.bku.utils.urldereferencer.StreamData; -import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; +import at.gv.egiz.bku.utils.urldereferencer.StreamData; +import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; import at.gv.egiz.bku.viewer.ValidationException; import at.gv.egiz.bku.viewer.Validator; import at.gv.egiz.bku.viewer.ValidatorFactory; -import at.gv.egiz.dom.DOMUtils; -import at.gv.egiz.slbinding.impl.XMLContentType; - -/** - * This class represents a DataObject of an XML-Signature - * created by the security layer command CreateXMLSignature. - * - * @author mcentner - */ -public class DataObject { - - /** - * Logging facility. - */ - private static Log log = LogFactory.getLog(DataObject.class); - - /** - * DOM Implementation. - */ - private static final String DOM_LS_3_0 = "LS 3.0"; - - /** - * The array of the default preferred MIME type order. - */ - private static final String[] DEFAULT_PREFFERED_MIME_TYPES = - new String[] { +import at.gv.egiz.dom.DOMUtils; +import at.gv.egiz.marshal.NamespacePrefix; +import at.gv.egiz.marshal.NamespacePrefixMapperImpl; +import at.gv.egiz.slbinding.impl.XMLContentType; +import javax.xml.namespace.NamespaceContext; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +/** + * This class represents a DataObject of an XML-Signature + * created by the security layer command CreateXMLSignature. + * + * @author mcentner + */ +public class DataObject { + + /** + * Logging facility. + */ + private static Log log = LogFactory.getLog(DataObject.class); + + /** + * DOM Implementation. + */ + private static final String DOM_LS_3_0 = "LS 3.0"; + + /** + * The array of the default preferred MIME type order. + */ + private static final String[] DEFAULT_PREFFERED_MIME_TYPES = + new String[] { "text/plain", - "application/xhtml+xml" + "application/xhtml+xml" }; /** @@ -149,87 +156,87 @@ public class DataObject { validMimeTypes = mediaTypes; } - /** - * The DOM implementation used. - */ - private DOMImplementationLS domImplLS; - - /** - * The signature context. - */ - private SignatureContext ctx; - - /** - * The Reference for this DataObject. - */ - private XSECTReference reference; - - /** - * The XMLObject for this DataObject. - */ - private XMLObject xmlObject; - - /** - * The MIME-Type of the digest input. - */ - private String mimeType; - - /** - * An optional description of the digest input. - */ - private String description; - - /** - * Creates a new instance. - * - * @param document the document of the target signature - */ - public DataObject(SignatureContext signatureContext) { - this.ctx = signatureContext; - - DOMImplementationRegistry registry; - try { - registry = DOMImplementationRegistry.newInstance(); - } catch (Exception e) { - log.error("Failed to get DOMImplementationRegistry.", e); - throw new SLRuntimeException("Failed to get DOMImplementationRegistry."); - } - - domImplLS = (DOMImplementationLS) registry.getDOMImplementation(DOM_LS_3_0); - if (domImplLS == null) { - log.error("Failed to get DOMImplementation " + DOM_LS_3_0); - throw new SLRuntimeException("Failed to get DOMImplementation " + DOM_LS_3_0); - } - - } - - /** - * @return the reference - */ - public Reference getReference() { - return reference; - } - - /** - * @return the xmlObject - */ - public XMLObject getXmlObject() { - return xmlObject; - } - - /** - * @return the mimeType - */ - public String getMimeType() { - return mimeType; - } - - /** - * @return the description - */ - public String getDescription() { - return description; - } + /** + * The DOM implementation used. + */ + private DOMImplementationLS domImplLS; + + /** + * The signature context. + */ + private SignatureContext ctx; + + /** + * The Reference for this DataObject. + */ + private XSECTReference reference; + + /** + * The XMLObject for this DataObject. + */ + private XMLObject xmlObject; + + /** + * The MIME-Type of the digest input. + */ + private String mimeType; + + /** + * An optional description of the digest input. + */ + private String description; + + /** + * Creates a new instance. + * + * @param document the document of the target signature + */ + public DataObject(SignatureContext signatureContext) { + this.ctx = signatureContext; + + DOMImplementationRegistry registry; + try { + registry = DOMImplementationRegistry.newInstance(); + } catch (Exception e) { + log.error("Failed to get DOMImplementationRegistry.", e); + throw new SLRuntimeException("Failed to get DOMImplementationRegistry."); + } + + domImplLS = (DOMImplementationLS) registry.getDOMImplementation(DOM_LS_3_0); + if (domImplLS == null) { + log.error("Failed to get DOMImplementation " + DOM_LS_3_0); + throw new SLRuntimeException("Failed to get DOMImplementation " + DOM_LS_3_0); + } + + } + + /** + * @return the reference + */ + public Reference getReference() { + return reference; + } + + /** + * @return the xmlObject + */ + public XMLObject getXmlObject() { + return xmlObject; + } + + /** + * @return the mimeType + */ + public String getMimeType() { + return mimeType; + } + + /** + * @return the description + */ + public String getDescription() { + return description; + } public void validateHashDataInput() throws SLViewerException { @@ -293,823 +300,920 @@ public class DataObject { } } - - /** - * Configures this DataObject with the information provided within the given - * sl:DataObjectInfo. - * - * @param dataObjectInfo - * the sl:DataObjectInfo - * - * @throws SLCommandException - * if configuring this DataObject with the information provided in - * the sl:DataObjectInfo fails. - * @throws SLRequestException - * if the information provided in the sl:DataObjectInfo - * does not conform to the security layer specification. - * @throws NullPointerException - * if dataObjectInfo is null - */ - public void setDataObjectInfo(DataObjectInfoType dataObjectInfo) throws SLCommandException, SLRequestException { - - Base64XMLLocRefOptRefContentType dataObject = dataObjectInfo.getDataObject(); - String structure = dataObjectInfo.getStructure(); - - // select and unmarshal an appropriate transformation path if provided - // and set the final data meta information - XSECTTransforms transforms = createTransformsAndSetFinalDataMetaInfo(dataObjectInfo.getTransformsInfo()); - - if ("enveloping".equals(structure)) { - - // configure this DataObject as an enveloped DataObject - setEnvelopedDataObject(dataObject, transforms); - - } else if ("detached".equals(structure)) { - - // configure this DataObject as an detached DataObject - setDetachedDataObject(dataObject, transforms); - - } - // other values are not allowed by the schema and are therefore ignored - - } - - /** - * Configures this DataObject as an enveloped DataObject with the information - * provided within the given sl:DataObject. - * - * @param dataObject - * the sl:DataObject - * @param transforms - * an optional Transforms element (may be - * null) - * - * @throws SLCommandException - * if configuring this DataObject with the information provided in - * the sl:DataObject fails. - * @throws SLRequestException - * if the information provided in the sl:DataObject - * does not conform to the security layer specification. - * @throws NullPointerException - * if dataObject is null - */ - private void setEnvelopedDataObject( - Base64XMLLocRefOptRefContentType dataObject, XSECTTransforms transforms) - throws SLCommandException, SLRequestException { - - String reference = dataObject.getReference(); - if (reference == null) { - // - // case A - // - // The Reference attribute is not used; the content of sl:DataObject represents the data object. - // If the data object is XML-coded (the sl:XMLContent element is used in sl:DataObject), then it - // must be incorporated in the signature structure as parsed XML. - // - - if (dataObject.getBase64Content() != null) { - - log.debug("Adding DataObject (Base64Content) without a reference URI."); - - // create XMLObject - XMLObject xmlObject = createXMLObject(new ByteArrayInputStream(dataObject.getBase64Content())); - - setXMLObjectAndReferenceBase64(xmlObject, transforms); - - } else if (dataObject.getXMLContent() != null) { - - log.debug("Adding DataObject (XMLContent) without a reference URI."); - - // create XMLObject - DocumentFragment content = parseDataObject((XMLContentType) dataObject.getXMLContent()); - XMLObject xmlObject = createXMLObject(content); - - setXMLObjectAndReferenceXML(xmlObject, transforms); - - } else if (dataObject.getLocRefContent() != null) { - - log.debug("Adding DataObject (LocRefContent) without a reference URI."); - - setEnvelopedDataObject(dataObject.getLocRefContent(), transforms); - - } else { - - // not allowed - log.info("XML structure of the command request contains an " + - "invalid combination of optional elements or attributes. " + - "DataObject of structure='enveloped' without a reference must contain content."); - throw new SLRequestException(3003); - - } - - } else { - - if (dataObject.getBase64Content() == null && - dataObject.getXMLContent() == null && - dataObject.getLocRefContent() == null) { - - // - // case B - // - // The Reference attribute contains a URI that must be resolved by the - // Citizen Card Environment to obtain the data object. - // The content of sl:DataObject remains empty - // - - log.debug("Adding DataObject from reference URI '" + reference + "'."); - - setEnvelopedDataObject(reference, transforms); - - } else { - - // not allowed - log.info("XML structure of the command request contains an " + - "invalid combination of optional elements or attributes. " + - "DataObject of structure='enveloped' with reference must not contain content."); - throw new SLRequestException(3003); - - } - - - } - - } - - /** - * Configures this DataObject as an enveloped DataObject with the content to - * be dereferenced from the given reference. - * - * @param reference - * the reference URI - * @param transforms - * an optional Transforms element (may be - * null) - * - * @throws SLCommandException - * if dereferencing the given reference fails, or if - * configuring this DataObject with the data dereferenced from the - * given reference fails. - * @throws NullPointerException - * if reference is null - */ - private void setEnvelopedDataObject(String reference, XSECTTransforms transforms) throws SLCommandException { - - if (reference == null) { - throw new NullPointerException("Argument 'reference' must not be null."); - } - - // dereference URL - URLDereferencer dereferencer = URLDereferencer.getInstance(); - - StreamData streamData; - try { - streamData = dereferencer.dereference(reference, ctx.getDereferencerContext()); - } catch (IOException e) { - log.info("Failed to dereference XMLObject from '" + reference + "'.", e); - throw new SLCommandException(4110); - } - - Node childNode; - - String contentType = streamData.getContentType(); - if (contentType.startsWith("text/xml")) { - - // If content type is text/xml parse content. - String charset = HttpUtil.getCharset(contentType, true); - - Document doc = parseDataObject(streamData.getStream(), charset); - - childNode = doc.getDocumentElement(); - - if (childNode == null) { - log.info("Failed to parse XMLObject from '" + reference + "'."); - throw new SLCommandException(4111); - } - - XMLObject xmlObject = createXMLObject(childNode); - - setXMLObjectAndReferenceXML(xmlObject, transforms); - - } else { - - // Include content Base64 encoded. - XMLObject xmlObject = createXMLObject(streamData.getStream()); - - setXMLObjectAndReferenceBase64(xmlObject, transforms); - - } - - } - - /** - * Configures this DataObject as an detached DataObject with the information - * provided in the given sl:DataObject and optionally - * transforms. - * - * @param dataObject - * the sl:DataObject - * @param transforms - * an optional Transforms object, may be null - * - * @throws SLCommandException - * if configuring this DataObject with the information provided in - * the sl:DataObject fails. - * @throws SLRequestException - * if the information provided in the sl:DataObject - * does not conform to the security layer specification. - * @throws NullPointerException - * if dataObject is null - */ - private void setDetachedDataObject( - Base64XMLLocRefOptRefContentType dataObject, XSECTTransforms transforms) - throws SLCommandException, SLRequestException { - - String referenceURI = dataObject.getReference(); - - if (referenceURI == null) { - - // not allowed - log.info("XML structure of the command request contains an " + - "invalid combination of optional elements or attributes. " + - "DataObject of structure='detached' must contain a reference."); - throw new SLRequestException(3003); - - } else { - - DigestMethod dm; - try { - dm = ctx.getAlgorithmMethodFactory().createDigestMethod(ctx); - } catch (NoSuchAlgorithmException e) { - log.error("Failed to get DigestMethod.", e); - throw new SLCommandException(4006); - } catch (InvalidAlgorithmParameterException e) { - log.error("Failed to get DigestMethod.", e); - throw new SLCommandException(4006); - } - - String idValue = ctx.getIdValueFactory().createIdValue("Reference"); - - reference = new XSECTReference(referenceURI, dm, transforms, null, idValue); - - // case D: - // - // The Reference attribute contains a URI that is used by the Citizen Card - // Environment to code the reference to the data object as part of the XML - // signature (attribute URI in the dsig:Reference) element. The content of - // sl:DataObject represents the data object. - - if (dataObject.getLocRefContent() != null) { - String locRef = dataObject.getLocRefContent(); - try { - this.reference.setDereferencer(new LocRefDereferencer(ctx.getDereferencerContext(), locRef)); - } catch (URISyntaxException e) { - log.info("Invalid URI '" + locRef + "' in DataObject.", e); - throw new SLCommandException(4003); - } catch (IllegalArgumentException e) { - log.info("LocRef URI of '" + locRef + "' not supported in DataObject. ", e); - throw new SLCommandException(4003); - } - } else if (dataObject.getBase64Content() != null) { - byte[] base64Content = dataObject.getBase64Content(); - this.reference.setDereferencer(new ByteArrayDereferencer(base64Content)); - } else if (dataObject.getXMLContent() != null) { - XMLContentType xmlContent = (XMLContentType) dataObject.getXMLContent(); - byte[] bytes = xmlContent.getRedirectedStream().toByteArray(); - this.reference.setDereferencer(new ByteArrayDereferencer(bytes)); - } else { - - // case C: - // - // The Reference attribute contains a URI that must be resolved by the - // Citizen Card Environment to obtain the data object. The Reference - // attribute contains a URI that is used by the Citizen Card Environment - // to code the reference to the data object as part of the XML signature - // (attribute URI in the dsig:Reference) element. The content of - // sl:DataObject remains empty. - - } - - } - } - - /** - * Returns the preferred sl:TransformInfo from the given list of - * transformInfos, or null if none of the given - * transformInfos is preferred over the others. - * - * @param transformsInfos - * a list of sl:TransformInfos - * - * @return the selected sl:TransformInfo or null, if - * none is preferred over the others - */ - private TransformsInfoType selectPreferredTransformsInfo(List transformsInfos) { - - Map mimeTypes = new HashMap(); - - StringBuilder debugString = null; - if (log.isDebugEnabled()) { - debugString = new StringBuilder(); - debugString.append("Got " + transformsInfos.size() + " TransformsInfo(s):"); - } - - for (TransformsInfoType transformsInfoType : transformsInfos) { - MetaInfoType finalDataMetaInfo = transformsInfoType.getFinalDataMetaInfo(); - String mimeType = finalDataMetaInfo.getMimeType(); - String description = finalDataMetaInfo.getDescription(); - mimeTypes.put(mimeType, transformsInfoType); - if (debugString != null) { - debugString.append("\n FinalDataMetaInfo: MIME-Type="); - debugString.append(mimeType); - if (description != null) { - debugString.append(" "); - debugString.append(description); - } - } - } - - if (debugString != null) { - log.debug(debugString); - } - - // look for preferred transform - for (String mimeType : DEFAULT_PREFFERED_MIME_TYPES) { - if (mimeTypes.containsKey(mimeType)) { - return mimeTypes.get(mimeType); - } - } - - // no preferred transform - return null; - - } - - /** - * Create an instance of ds:Transforms from the given - * sl:TransformsInfo. - * - * @param transformsInfo - * the sl:TransformsInfo - * - * @return a corresponding unmarshalled ds:Transforms, or - * null if the given sl:TransformsInfo does - * not contain a dsig:Transforms element - * - * @throws SLRequestException - * if the ds:Transforms in the given - * transformsInfo are not valid or cannot be parsed. - * - * @throws MarshalException - * if the ds:Transforms in the given - * transformsInfo cannot be unmarshalled. - */ - private XSECTTransforms createTransforms(TransformsInfoType transformsInfo) throws SLRequestException, MarshalException { - - ByteArrayOutputStream redirectedStream = ((at.gv.egiz.slbinding.impl.TransformsInfoType) transformsInfo).getRedirectedStream(); - byte[] transformBytes = (redirectedStream != null) ? redirectedStream.toByteArray() : null; - - if (transformBytes != null && transformBytes.length > 0) { - - // debug - if (log.isTraceEnabled()) { - StringBuilder sb = new StringBuilder(); - sb.append("Trying to parse transforms:\n"); - sb.append(new String(transformBytes, Charset.forName("UTF-8"))); - log.trace(sb); - } - - DOMImplementationLS domImplLS = DOMUtils.getDOMImplementationLS(); - LSInput input = domImplLS.createLSInput(); - input.setByteStream(new ByteArrayInputStream(transformBytes)); - - LSParser parser = domImplLS.createLSParser( - DOMImplementationLS.MODE_SYNCHRONOUS, null); - DOMConfiguration domConfig = parser.getDomConfig(); - SimpleDOMErrorHandler errorHandler = new SimpleDOMErrorHandler(); - domConfig.setParameter("error-handler", errorHandler); - domConfig.setParameter("validate", Boolean.FALSE); - - Document document; - try { - document = parser.parse(input); - } catch (DOMException e) { - log.info("Failed to parse dsig:Transforms.", e); - throw new SLRequestException(3002); - } catch (LSException e) { - log.info("Failed to parse dsig:Transforms.", e); - throw new SLRequestException(3002); - } - - // adopt ds:Transforms - Element documentElement = document.getDocumentElement(); - Node adoptedTransforms = ctx.getDocument().adoptNode(documentElement); - - DOMCryptoContext context = new DOMCryptoContext(); - - // unmarshall ds:Transforms - return new XSECTTransforms(context, adoptedTransforms); - - } else { - return null; - } - - } - - /** - * Sets the mimeType and the description value - * for this DataObject. - * - * @param metaInfoType the sl:FinalMetaDataInfo - * - * @throws NullPointerException if metaInfoType is null - */ - private void setFinalDataMetaInfo(MetaInfoType metaInfoType) { - - this.mimeType = metaInfoType.getMimeType(); - this.description = metaInfoType.getDescription(); - - } - - /** - * Selects an appropriate transformation path (if present) from the given list - * of sl:TransformInfos, sets the corresponding final data meta info and - * returns the corresponding unmarshalled ds:Transforms. - * - * @param transformsInfos the sl:TransformInfos - * - * @return the unmarshalled ds:Transforms, or null if - * no transformation path has been selected. - * - * @throws SLRequestException if the given list ds:TransformsInfo contains - * an invalid ds:Transforms element, or no suitable transformation path - * can be found. - */ - private XSECTTransforms createTransformsAndSetFinalDataMetaInfo( - List transformsInfos) throws SLRequestException { - - TransformsInfoType preferredTransformsInfo = selectPreferredTransformsInfo(transformsInfos); - // try preferred transform - if (preferredTransformsInfo != null) { - - try { - XSECTTransforms transforms = createTransforms(preferredTransformsInfo); - setFinalDataMetaInfo(preferredTransformsInfo.getFinalDataMetaInfo()); - return transforms; - } catch (MarshalException e) { - - String mimeType = preferredTransformsInfo.getFinalDataMetaInfo().getMimeType(); - log.info("Failed to unmarshal preferred transformation path (MIME-Type=" - + mimeType + ").", e); - - } - - } - - // look for another suitable transformation path - for (TransformsInfoType transformsInfoType : transformsInfos) { - - try { - XSECTTransforms transforms = createTransforms(transformsInfoType); - setFinalDataMetaInfo(transformsInfoType.getFinalDataMetaInfo()); - return transforms; - } catch (MarshalException e) { - - String mimeType = transformsInfoType.getFinalDataMetaInfo().getMimeType(); - log.info("Failed to unmarshal transformation path (MIME-Type=" - + mimeType + ").", e); - } - - } - - // no suitable transformation path found - throw new SLRequestException(3003); - - } - - /** - * Create an XMLObject with the Base64 encoding of the given - * content. - * - * @param content - * the to-be Base64 encoded content - * @return an XMLObject with the Base64 encoded content - */ - private XMLObject createXMLObject(InputStream content) { - - Text textNode; - try { - textNode = at.gv.egiz.dom.DOMUtils.createBase64Text(content, ctx.getDocument()); - } catch (IOException e) { - log.error(e); - throw new SLRuntimeException(e); - } - - DOMStructure structure = new DOMStructure(textNode); - - String idValue = ctx.getIdValueFactory().createIdValue("Object"); - - return ctx.getSignatureFactory().newXMLObject(Collections.singletonList(structure), idValue, null, null); - - } - - /** - * Create an XMLObject with the given content node. - * - * @param content the content node - * - * @return an XMLObject with the given content - */ - private XMLObject createXMLObject(Node content) { - - String idValue = ctx.getIdValueFactory().createIdValue("Object"); - - List structures = Collections.singletonList(new DOMStructure(content)); - - return ctx.getSignatureFactory().newXMLObject(structures, idValue, null, null); - - } - - /** - * Sets the given xmlObject and creates and sets a corresponding - * Reference. - *

- * A transform to Base64-decode the xmlObject's content is inserted at the top - * of to the optional transforms if given, or to a newly created - * Transforms element if transforms is - * null. - * - * @param xmlObject - * the XMLObject - * @param transforms - * an optional Transforms element (may be - * null) - * - * @throws SLCommandException - * if creating the Reference fails - * @throws NullPointerException - * if xmlObject is null - */ - private void setXMLObjectAndReferenceBase64(XMLObject xmlObject, XSECTTransforms transforms) throws SLCommandException { - - // create reference URI - // - // NOTE: the ds:Object can be referenced directly, as the Base64 transform - // operates on the text() of the input nodelist. - // - String referenceURI = "#" + xmlObject.getId(); - - // create Base64 Transform - Transform transform; - try { - transform = ctx.getSignatureFactory().newTransform(Transform.BASE64, (TransformParameterSpec) null); - } catch (NoSuchAlgorithmException e) { - // algorithm must be present - throw new SLRuntimeException(e); - } catch (InvalidAlgorithmParameterException e) { - // algorithm does not take parameters - throw new SLRuntimeException(e); - } - - if (transforms == null) { - transforms = new XSECTTransforms(Collections.singletonList(transform)); - } else { - transforms.insertTransform(transform); - } - - DigestMethod dm; - try { - dm = ctx.getAlgorithmMethodFactory().createDigestMethod(ctx); - } catch (NoSuchAlgorithmException e) { - log.error("Failed to get DigestMethod.", e); - throw new SLCommandException(4006); - } catch (InvalidAlgorithmParameterException e) { - log.error("Failed to get DigestMethod.", e); - throw new SLCommandException(4006); - } - String id = ctx.getIdValueFactory().createIdValue("Reference"); - - this.xmlObject = xmlObject; - this.reference = new XSECTReference(referenceURI, dm, transforms, null, id); - - } - - /** - * Sets the given xmlObject and creates and sets a corresponding - * Reference. - *

- * A transform to select the xmlObject's content is inserted at the top of to - * the optional transforms if given, or to a newly created - * Transforms element if transforms is - * null. - *

- * - * @param xmlObject - * the XMLObject - * @param transforms - * an optional Transforms element (may be - * null) - * - * @throws SLCommandException - * if creating the Reference fails - * @throws NullPointerException - * if xmlObject is null - */ - private void setXMLObjectAndReferenceXML(XMLObject xmlObject, XSECTTransforms transforms) throws SLCommandException { - - // create reference URI - String referenceURI = "#" + xmlObject.getId(); - - // create Transform to select ds:Object's children - Transform xpathTransform; - Transform c14nTransform; - try { - - XPathType xpath = new XPathType("id(\"" + xmlObject.getId() + "\")/node()", XPathType.Filter.INTERSECT); - List xpaths = Collections.singletonList(xpath); - XPathFilter2ParameterSpec params = new XPathFilter2ParameterSpec(xpaths); - - xpathTransform = ctx.getSignatureFactory().newTransform(Transform.XPATH2, params); - - // add exclusive canonicalization to avoid signing the namespace context of the ds:Object - c14nTransform = ctx.getSignatureFactory().newTransform(CanonicalizationMethod.EXCLUSIVE, (TransformParameterSpec) null); - - } catch (NoSuchAlgorithmException e) { - // algorithm must be present - throw new SLRuntimeException(e); - } catch (InvalidAlgorithmParameterException e) { - // params must be appropriate - throw new SLRuntimeException(e); - } - - if (transforms == null) { - List newTransfroms = new ArrayList(); - newTransfroms.add(xpathTransform); - newTransfroms.add(c14nTransform); - transforms = new XSECTTransforms(newTransfroms); - } else { - transforms.insertTransform(xpathTransform); - } - - DigestMethod dm; - try { - dm = ctx.getAlgorithmMethodFactory().createDigestMethod(ctx); - } catch (NoSuchAlgorithmException e) { - log.error("Failed to get DigestMethod.", e); - throw new SLCommandException(4006); - } catch (InvalidAlgorithmParameterException e) { - log.error("Failed to get DigestMethod.", e); - throw new SLCommandException(4006); - } - String id = ctx.getIdValueFactory().createIdValue("Reference"); - - this.xmlObject = xmlObject; - this.reference = new XSECTReference(referenceURI, dm, transforms, null, id); - - } - - /** - * Parses the given xmlContent and returns a corresponding - * document fragment. - * - *

- * The to-be parsed content is surrounded by ... elements to - * allow for mixed (e.g. Text and Element) content in XMLContent. - *

- * - * @param xmlContent - * the XMLContent to-be parsed - * - * @return a document fragment containing the parsed nodes - * - * @throws SLCommandException - * if parsing the given xmlContent fails - * - * @throws NullPointerException - * if xmlContent is null - */ - private DocumentFragment parseDataObject(XMLContentType xmlContent) throws SLCommandException { - - ByteArrayOutputStream redirectedStream = xmlContent.getRedirectedStream(); - - // Note: We can assume a fixed character encoding of UTF-8 for the - // content of the redirect stream as the content has already been parsed - // and serialized again to the redirect stream. - - List inputStreams = new ArrayList(); - try { - // dummy start element - inputStreams.add(new ByteArrayInputStream("".getBytes("UTF-8"))); - - // content - inputStreams.add(new ByteArrayInputStream(redirectedStream.toByteArray())); - - // dummy end element - inputStreams.add(new ByteArrayInputStream("".getBytes("UTF-8"))); - } catch (UnsupportedEncodingException e) { - throw new SLRuntimeException(e); - } - - SequenceInputStream inputStream = new SequenceInputStream(Collections.enumeration(inputStreams)); - - // parse DataObject - Document doc = parseDataObject(inputStream, "UTF-8"); - - Element documentElement = doc.getDocumentElement(); - - if (documentElement == null || - !"dummy".equals(documentElement.getLocalName())) { - log.info("Failed to parse DataObject XMLContent."); - throw new SLCommandException(4111); - } - - DocumentFragment fragment = doc.createDocumentFragment(); - while (documentElement.getFirstChild() != null) { - fragment.appendChild(documentElement.getFirstChild()); - } - - // log parsed document - if (log.isTraceEnabled()) { - - StringWriter writer = new StringWriter(); - - writer.write("DataObject:\n"); - - LSOutput output = domImplLS.createLSOutput(); - output.setCharacterStream(writer); - output.setEncoding("UTF-8"); - LSSerializer serializer = domImplLS.createLSSerializer(); - serializer.getDomConfig().setParameter("xml-declaration", Boolean.FALSE); - serializer.write(fragment, output); - - log.trace(writer.toString()); - } - - return fragment; - - } - - /** - * Parses the given inputStream using the given - * encoding and returns the parsed document. - * - * @param inputStream - * the to-be parsed input - * - * @param encoding - * the encoding to be used for parsing the given - * inputStream - * - * @return the parsed document - * - * @throws SLCommandException - * if parsing the inputStream fails. - * - * @throws NullPointerException - * if inputStram is null - */ - private Document parseDataObject(InputStream inputStream, String encoding) throws SLCommandException { - - LSInput input = domImplLS.createLSInput(); - input.setByteStream(inputStream); - - if (encoding != null) { - input.setEncoding(encoding); - } - - LSParser parser = domImplLS.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null); - DOMConfiguration domConfig = parser.getDomConfig(); - SimpleDOMErrorHandler errorHandler = new SimpleDOMErrorHandler(); - domConfig.setParameter("error-handler", errorHandler); - domConfig.setParameter("validate", Boolean.FALSE); - - Document doc; - try { - doc = parser.parse(input); - } catch (DOMException e) { - log.info("Existing XML document cannot be parsed.", e); - throw new SLCommandException(4111); - } catch (LSException e) { - log.info("Existing XML document cannot be parsed. ", e); - throw new SLCommandException(4111); - } - - if (errorHandler.hasErrors()) { - // log errors - if (log.isInfoEnabled()) { - List errorMessages = errorHandler.getErrorMessages(); - StringBuffer sb = new StringBuffer(); - for (String errorMessage : errorMessages) { - sb.append(" "); - sb.append(errorMessage); - } - log.info("Existing XML document cannot be parsed. " + sb.toString()); - } - throw new SLCommandException(4111); - } - - return doc; - - } - - -} + + /** + * Configures this DataObject with the information provided within the given + * sl:DataObjectInfo. + * + * @param dataObjectInfo + * the sl:DataObjectInfo + * + * @throws SLCommandException + * if configuring this DataObject with the information provided in + * the sl:DataObjectInfo fails. + * @throws SLRequestException + * if the information provided in the sl:DataObjectInfo + * does not conform to the security layer specification. + * @throws NullPointerException + * if dataObjectInfo is null + */ + public void setDataObjectInfo(DataObjectInfoType dataObjectInfo) throws SLCommandException, SLRequestException { + + Base64XMLLocRefOptRefContentType dataObject = dataObjectInfo.getDataObject(); + String structure = dataObjectInfo.getStructure(); + + // select and unmarshal an appropriate transformation path if provided + // and set the final data meta information + XSECTTransforms transforms = createTransformsAndSetFinalDataMetaInfo(dataObjectInfo.getTransformsInfo()); + + if ("enveloping".equals(structure)) { + + // configure this DataObject as an enveloped DataObject + setEnvelopedDataObject(dataObject, transforms); + + } else if ("detached".equals(structure)) { + + // configure this DataObject as an detached DataObject + setDetachedDataObject(dataObject, transforms); + + } + // other values are not allowed by the schema and are therefore ignored + + } + + private byte[] getTransformsBytes(at.gv.egiz.slbinding.impl.TransformsInfoType ti) { + return ti.getRedirectedStream().toByteArray(); +// byte[] transformsBytes = ti.getRedirectedStream().toByteArray(); +// +// if (transformsBytes == null || transformsBytes.length == 0) { +// return null; +// } +// +// String dsigPrefix = ti.getNamespaceContext().getNamespaceURI("http://www.w3.org/2000/09/xmldsig#"); +// byte[] pre, post; +// if (dsigPrefix == null) { +// log.trace("XMLDSig not declared in outside dsig:Transforms"); +// pre = "".getBytes(); +// post = "".getBytes(); +// } else { +// log.trace("XMLDSig bound to prefix " + dsigPrefix); +// pre = ("").getBytes(); +// post = "".getBytes(); +// } +// +// byte[] workaround = new byte[pre.length + transformsBytes.length + post.length]; +// System.arraycopy(pre, 0, workaround, 0, pre.length); +// System.arraycopy(transformsBytes, 0, workaround, pre.length, transformsBytes.length); +// System.arraycopy(post, 0, workaround, pre.length + transformsBytes.length, post.length); +// return workaround; + } + + /** + * Configures this DataObject as an enveloped DataObject with the information + * provided within the given sl:DataObject. + * + * @param dataObject + * the sl:DataObject + * @param transforms + * an optional Transforms element (may be + * null) + * + * @throws SLCommandException + * if configuring this DataObject with the information provided in + * the sl:DataObject fails. + * @throws SLRequestException + * if the information provided in the sl:DataObject + * does not conform to the security layer specification. + * @throws NullPointerException + * if dataObject is null + */ + private void setEnvelopedDataObject( + Base64XMLLocRefOptRefContentType dataObject, XSECTTransforms transforms) + throws SLCommandException, SLRequestException { + + String reference = dataObject.getReference(); + if (reference == null) { + // + // case A + // + // The Reference attribute is not used; the content of sl:DataObject represents the data object. + // If the data object is XML-coded (the sl:XMLContent element is used in sl:DataObject), then it + // must be incorporated in the signature structure as parsed XML. + // + + if (dataObject.getBase64Content() != null) { + + log.debug("Adding DataObject (Base64Content) without a reference URI."); + + // create XMLObject + XMLObject xmlObject = createXMLObject(new ByteArrayInputStream(dataObject.getBase64Content())); + + setXMLObjectAndReferenceBase64(xmlObject, transforms); + + } else if (dataObject.getXMLContent() != null) { + + log.debug("Adding DataObject (XMLContent) without a reference URI."); + + // create XMLObject + DocumentFragment content = parseDataObject((XMLContentType) dataObject.getXMLContent()); + XMLObject xmlObject = createXMLObject(content); + + setXMLObjectAndReferenceXML(xmlObject, transforms); + + } else if (dataObject.getLocRefContent() != null) { + + log.debug("Adding DataObject (LocRefContent) without a reference URI."); + + setEnvelopedDataObject(dataObject.getLocRefContent(), transforms); + + } else { + + // not allowed + log.info("XML structure of the command request contains an " + + "invalid combination of optional elements or attributes. " + + "DataObject of structure='enveloped' without a reference must contain content."); + throw new SLRequestException(3003); + + } + + } else { + + if (dataObject.getBase64Content() == null && + dataObject.getXMLContent() == null && + dataObject.getLocRefContent() == null) { + + // + // case B + // + // The Reference attribute contains a URI that must be resolved by the + // Citizen Card Environment to obtain the data object. + // The content of sl:DataObject remains empty + // + + log.debug("Adding DataObject from reference URI '" + reference + "'."); + + setEnvelopedDataObject(reference, transforms); + + } else { + + // not allowed + log.info("XML structure of the command request contains an " + + "invalid combination of optional elements or attributes. " + + "DataObject of structure='enveloped' with reference must not contain content."); + throw new SLRequestException(3003); + + } + + + } + + } + + /** + * Configures this DataObject as an enveloped DataObject with the content to + * be dereferenced from the given reference. + * + * @param reference + * the reference URI + * @param transforms + * an optional Transforms element (may be + * null) + * + * @throws SLCommandException + * if dereferencing the given reference fails, or if + * configuring this DataObject with the data dereferenced from the + * given reference fails. + * @throws NullPointerException + * if reference is null + */ + private void setEnvelopedDataObject(String reference, XSECTTransforms transforms) throws SLCommandException { + + if (reference == null) { + throw new NullPointerException("Argument 'reference' must not be null."); + } + + // dereference URL + URLDereferencer dereferencer = URLDereferencer.getInstance(); + + StreamData streamData; + try { + streamData = dereferencer.dereference(reference, ctx.getDereferencerContext()); + } catch (IOException e) { + log.info("Failed to dereference XMLObject from '" + reference + "'.", e); + throw new SLCommandException(4110); + } + + Node childNode; + + String contentType = streamData.getContentType(); + if (contentType.startsWith("text/xml")) { + + // If content type is text/xml parse content. + String charset = HttpUtil.getCharset(contentType, true); + + Document doc = parseDataObject(streamData.getStream(), charset); + + childNode = doc.getDocumentElement(); + + if (childNode == null) { + log.info("Failed to parse XMLObject from '" + reference + "'."); + throw new SLCommandException(4111); + } + + XMLObject xmlObject = createXMLObject(childNode); + + setXMLObjectAndReferenceXML(xmlObject, transforms); + + } else { + + // Include content Base64 encoded. + XMLObject xmlObject = createXMLObject(streamData.getStream()); + + setXMLObjectAndReferenceBase64(xmlObject, transforms); + + } + + } + + /** + * Configures this DataObject as an detached DataObject with the information + * provided in the given sl:DataObject and optionally + * transforms. + * + * @param dataObject + * the sl:DataObject + * @param transforms + * an optional Transforms object, may be null + * + * @throws SLCommandException + * if configuring this DataObject with the information provided in + * the sl:DataObject fails. + * @throws SLRequestException + * if the information provided in the sl:DataObject + * does not conform to the security layer specification. + * @throws NullPointerException + * if dataObject is null + */ + private void setDetachedDataObject( + Base64XMLLocRefOptRefContentType dataObject, XSECTTransforms transforms) + throws SLCommandException, SLRequestException { + + String referenceURI = dataObject.getReference(); + + if (referenceURI == null) { + + // not allowed + log.info("XML structure of the command request contains an " + + "invalid combination of optional elements or attributes. " + + "DataObject of structure='detached' must contain a reference."); + throw new SLRequestException(3003); + + } else { + + DigestMethod dm; + try { + dm = ctx.getAlgorithmMethodFactory().createDigestMethod(ctx); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get DigestMethod.", e); + throw new SLCommandException(4006); + } catch (InvalidAlgorithmParameterException e) { + log.error("Failed to get DigestMethod.", e); + throw new SLCommandException(4006); + } + + String idValue = ctx.getIdValueFactory().createIdValue("Reference"); + + reference = new XSECTReference(referenceURI, dm, transforms, null, idValue); + + // case D: + // + // The Reference attribute contains a URI that is used by the Citizen Card + // Environment to code the reference to the data object as part of the XML + // signature (attribute URI in the dsig:Reference) element. The content of + // sl:DataObject represents the data object. + + if (dataObject.getLocRefContent() != null) { + String locRef = dataObject.getLocRefContent(); + try { + this.reference.setDereferencer(new LocRefDereferencer(ctx.getDereferencerContext(), locRef)); + } catch (URISyntaxException e) { + log.info("Invalid URI '" + locRef + "' in DataObject.", e); + throw new SLCommandException(4003); + } catch (IllegalArgumentException e) { + log.info("LocRef URI of '" + locRef + "' not supported in DataObject. ", e); + throw new SLCommandException(4003); + } + } else if (dataObject.getBase64Content() != null) { + byte[] base64Content = dataObject.getBase64Content(); + this.reference.setDereferencer(new ByteArrayDereferencer(base64Content)); + } else if (dataObject.getXMLContent() != null) { + XMLContentType xmlContent = (XMLContentType) dataObject.getXMLContent(); + byte[] bytes = xmlContent.getRedirectedStream().toByteArray(); + this.reference.setDereferencer(new ByteArrayDereferencer(bytes)); + } else { + + // case C: + // + // The Reference attribute contains a URI that must be resolved by the + // Citizen Card Environment to obtain the data object. The Reference + // attribute contains a URI that is used by the Citizen Card Environment + // to code the reference to the data object as part of the XML signature + // (attribute URI in the dsig:Reference) element. The content of + // sl:DataObject remains empty. + + } + + } + } + + /** + * Returns the preferred sl:TransformInfo from the given list of + * transformInfos, or null if none of the given + * transformInfos is preferred over the others. + * + * @param transformsInfos + * a list of sl:TransformInfos + * + * @return the selected sl:TransformInfo or null, if + * none is preferred over the others + */ + private TransformsInfoType selectPreferredTransformsInfo(List transformsInfos) { + + Map mimeTypes = new HashMap(); + + StringBuilder debugString = null; + if (log.isDebugEnabled()) { + debugString = new StringBuilder(); + debugString.append("Got " + transformsInfos.size() + " TransformsInfo(s):"); + } + + for (TransformsInfoType transformsInfoType : transformsInfos) { + MetaInfoType finalDataMetaInfo = transformsInfoType.getFinalDataMetaInfo(); + String mimeType = finalDataMetaInfo.getMimeType(); + String description = finalDataMetaInfo.getDescription(); + mimeTypes.put(mimeType, transformsInfoType); + if (debugString != null) { + debugString.append("\n FinalDataMetaInfo: MIME-Type="); + debugString.append(mimeType); + if (description != null) { + debugString.append(" "); + debugString.append(description); + } + } + } + + if (debugString != null) { + log.debug(debugString); + } + + // look for preferred transform + for (String mimeType : DEFAULT_PREFFERED_MIME_TYPES) { + if (mimeTypes.containsKey(mimeType)) { + return mimeTypes.get(mimeType); + } + } + + // no preferred transform + return null; + + } + + /** + * Create an instance of ds:Transforms from the given + * sl:TransformsInfo. + * + * @param transformsInfo + * the sl:TransformsInfo + * + * @return a corresponding unmarshalled ds:Transforms, or + * null if the given sl:TransformsInfo does + * not contain a dsig:Transforms element + * + * @throws SLRequestException + * if the ds:Transforms in the given + * transformsInfo are not valid or cannot be parsed. + * + * @throws MarshalException + * if the ds:Transforms in the given + * transformsInfo cannot be unmarshalled. + */ + private XSECTTransforms createTransforms(TransformsInfoType transformsInfo) throws SLRequestException, MarshalException { + + byte[] transforms = getTransformsBytes((at.gv.egiz.slbinding.impl.TransformsInfoType) transformsInfo); + + if (transforms != null && transforms.length > 0) { + // debug + if (log.isTraceEnabled()) { + StringBuilder sb = new StringBuilder(); + sb.append("Trying to parse transforms:\n"); + sb.append(new String(transforms, Charset.forName("UTF-8"))); + log.trace(sb); + } + + DOMImplementationLS domImplLS = DOMUtils.getDOMImplementationLS(); + LSInput input = domImplLS.createLSInput(); + input.setByteStream(new ByteArrayInputStream(transforms)); + + LSParser parser = domImplLS.createLSParser( + DOMImplementationLS.MODE_SYNCHRONOUS, null); + DOMConfiguration domConfig = parser.getDomConfig(); + SimpleDOMErrorHandler errorHandler = new SimpleDOMErrorHandler(); + domConfig.setParameter("error-handler", errorHandler); + domConfig.setParameter("validate", Boolean.FALSE); + + Document document; + try { + document = parser.parse(input); + } catch (DOMException e) { + log.info("Failed to parse dsig:Transforms.", e); + throw new SLRequestException(3002); + } catch (LSException e) { + log.info("Failed to parse dsig:Transforms.", e); + throw new SLRequestException(3002); + } + + // adopt ds:Transforms + Element transformsElt = document.getDocumentElement(); + Node adoptedTransforms = ctx.getDocument().adoptNode(transformsElt); + + DOMCryptoContext context = new DOMCryptoContext(); + + // unmarshall ds:Transforms + return new XSECTTransforms(context, adoptedTransforms); + + } else { + return null; + } + + +// TransformsType transformsType = transformsInfo.getTransforms(); +// if (transformsType == null) { +// return null; +// } +// List transformList = transformsType.getTransform(); +// +// DOMImplementationLS domImplLS = DOMUtils.getDOMImplementationLS(); +//// Document transformsDoc = ((DOMImplementation) domImplLS).createDocument("http://www.w3.org/2000/09/xmldsig#", "Transforms", null); +//// Element transforms = transformsDoc.getDocumentElement(); +// Document transformsDoc = DOMUtils.createDocument(); +// Element transforms = transformsDoc.createElementNS( +// "http://www.w3.org/2000/09/xmldsig#", +// Signature.XMLDSIG_PREFIX + ":Transforms"); +// transformsDoc.appendChild(transforms); +// +// for (TransformType transformType : transformList) { +// log.trace("found " + transformType.getClass().getName()); +// Element transform = transformsDoc.createElementNS( +// "http://www.w3.org/2000/09/xmldsig#", +// Signature.XMLDSIG_PREFIX + ":Transform"); +// String algorithm = transformType.getAlgorithm(); +// if (algorithm != null) { +// log.trace("found algorithm " + algorithm); +// transform.setAttribute("Algorithm", algorithm); +// } +// +// at.gv.egiz.slbinding.impl.TransformType t = (at.gv.egiz.slbinding.impl.TransformType) transformType; +// byte[] redirectedBytes = t.getRedirectedStream().toByteArray(); +// if (redirectedBytes != null && redirectedBytes.length > 0) { +// if (log.isTraceEnabled()) { +// StringBuilder sb = new StringBuilder(); +// sb.append("Trying to parse dsig:Transform:\n"); +// sb.append(new String(redirectedBytes, Charset.forName("UTF-8"))); +// log.trace(sb); +// } +// LSInput input = domImplLS.createLSInput(); +// input.setByteStream(new ByteArrayInputStream(redirectedBytes)); +// +// LSParser parser = domImplLS.createLSParser( +// DOMImplementationLS.MODE_SYNCHRONOUS, null); +// DOMConfiguration domConfig = parser.getDomConfig(); +// SimpleDOMErrorHandler errorHandler = new SimpleDOMErrorHandler(); +// domConfig.setParameter("error-handler", errorHandler); +// domConfig.setParameter("validate", Boolean.FALSE); +// +// try { +// Document redirectedDoc = parser.parse(input); +// Node redirected = transformsDoc.adoptNode(redirectedDoc.getDocumentElement()); +// transform.appendChild(redirected); +// +// //not supported by Xerces2.9.1 +//// Node redirected = parser.parseWithContext(input, transform, LSParser.ACTION_APPEND_AS_CHILDREN); +// +// } catch (DOMException e) { +// log.info("Failed to parse dsig:Transform.", e); +// throw new SLRequestException(3002); +// } catch (LSException e) { +// log.info("Failed to parse dsig:Transform.", e); +// throw new SLRequestException(3002); +// } +// } +// transforms.appendChild(transform); +// } +// +// //adopt ds:Transforms +// Node adoptedTransforms = ctx.getDocument().adoptNode(transforms); +// DOMCryptoContext context = new DOMCryptoContext(); +// +// // unmarshall ds:Transforms +// return new XSECTTransforms(context, adoptedTransforms); + + } + + /** + * Sets the mimeType and the description value + * for this DataObject. + * + * @param metaInfoType the sl:FinalMetaDataInfo + * + * @throws NullPointerException if metaInfoType is null + */ + private void setFinalDataMetaInfo(MetaInfoType metaInfoType) { + + this.mimeType = metaInfoType.getMimeType(); + this.description = metaInfoType.getDescription(); + + } + + /** + * Selects an appropriate transformation path (if present) from the given list + * of sl:TransformInfos, sets the corresponding final data meta info and + * returns the corresponding unmarshalled ds:Transforms. + * + * @param transformsInfos the sl:TransformInfos + * + * @return the unmarshalled ds:Transforms, or null if + * no transformation path has been selected. + * + * @throws SLRequestException if the given list ds:TransformsInfo contains + * an invalid ds:Transforms element, or no suitable transformation path + * can be found. + */ + private XSECTTransforms createTransformsAndSetFinalDataMetaInfo( + List transformsInfos) throws SLRequestException { + + TransformsInfoType preferredTransformsInfo = selectPreferredTransformsInfo(transformsInfos); + // try preferred transform + if (preferredTransformsInfo != null) { + + try { + XSECTTransforms transforms = createTransforms(preferredTransformsInfo); + setFinalDataMetaInfo(preferredTransformsInfo.getFinalDataMetaInfo()); + return transforms; + } catch (MarshalException e) { + + String mimeType = preferredTransformsInfo.getFinalDataMetaInfo().getMimeType(); + log.info("Failed to unmarshal preferred transformation path (MIME-Type=" + + mimeType + ").", e); + + } + + } + + // look for another suitable transformation path + for (TransformsInfoType transformsInfoType : transformsInfos) { + + try { + XSECTTransforms transforms = createTransforms(transformsInfoType); + setFinalDataMetaInfo(transformsInfoType.getFinalDataMetaInfo()); + return transforms; + } catch (MarshalException e) { + + String mimeType = transformsInfoType.getFinalDataMetaInfo().getMimeType(); + log.info("Failed to unmarshal transformation path (MIME-Type=" + + mimeType + ").", e); + } + + } + + // no suitable transformation path found + throw new SLRequestException(3003); + + } + + /** + * Create an XMLObject with the Base64 encoding of the given + * content. + * + * @param content + * the to-be Base64 encoded content + * @return an XMLObject with the Base64 encoded content + */ + private XMLObject createXMLObject(InputStream content) { + + Text textNode; + try { + textNode = at.gv.egiz.dom.DOMUtils.createBase64Text(content, ctx.getDocument()); + } catch (IOException e) { + log.error(e); + throw new SLRuntimeException(e); + } + + DOMStructure structure = new DOMStructure(textNode); + + String idValue = ctx.getIdValueFactory().createIdValue("Object"); + + return ctx.getSignatureFactory().newXMLObject(Collections.singletonList(structure), idValue, null, null); + + } + + /** + * Create an XMLObject with the given content node. + * + * @param content the content node + * + * @return an XMLObject with the given content + */ + private XMLObject createXMLObject(Node content) { + + String idValue = ctx.getIdValueFactory().createIdValue("Object"); + + List structures = Collections.singletonList(new DOMStructure(content)); + + return ctx.getSignatureFactory().newXMLObject(structures, idValue, null, null); + + } + + /** + * Sets the given xmlObject and creates and sets a corresponding + * Reference. + *

+ * A transform to Base64-decode the xmlObject's content is inserted at the top + * of to the optional transforms if given, or to a newly created + * Transforms element if transforms is + * null. + * + * @param xmlObject + * the XMLObject + * @param transforms + * an optional Transforms element (may be + * null) + * + * @throws SLCommandException + * if creating the Reference fails + * @throws NullPointerException + * if xmlObject is null + */ + private void setXMLObjectAndReferenceBase64(XMLObject xmlObject, XSECTTransforms transforms) throws SLCommandException { + + // create reference URI + // + // NOTE: the ds:Object can be referenced directly, as the Base64 transform + // operates on the text() of the input nodelist. + // + String referenceURI = "#" + xmlObject.getId(); + + // create Base64 Transform + Transform transform; + try { + transform = ctx.getSignatureFactory().newTransform(Transform.BASE64, (TransformParameterSpec) null); + } catch (NoSuchAlgorithmException e) { + // algorithm must be present + throw new SLRuntimeException(e); + } catch (InvalidAlgorithmParameterException e) { + // algorithm does not take parameters + throw new SLRuntimeException(e); + } + + if (transforms == null) { + transforms = new XSECTTransforms(Collections.singletonList(transform)); + } else { + transforms.insertTransform(transform); + } + + DigestMethod dm; + try { + dm = ctx.getAlgorithmMethodFactory().createDigestMethod(ctx); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get DigestMethod.", e); + throw new SLCommandException(4006); + } catch (InvalidAlgorithmParameterException e) { + log.error("Failed to get DigestMethod.", e); + throw new SLCommandException(4006); + } + String id = ctx.getIdValueFactory().createIdValue("Reference"); + + this.xmlObject = xmlObject; + this.reference = new XSECTReference(referenceURI, dm, transforms, null, id); + + } + + /** + * Sets the given xmlObject and creates and sets a corresponding + * Reference. + *

+ * A transform to select the xmlObject's content is inserted at the top of to + * the optional transforms if given, or to a newly created + * Transforms element if transforms is + * null. + *

+ * + * @param xmlObject + * the XMLObject + * @param transforms + * an optional Transforms element (may be + * null) + * + * @throws SLCommandException + * if creating the Reference fails + * @throws NullPointerException + * if xmlObject is null + */ + private void setXMLObjectAndReferenceXML(XMLObject xmlObject, XSECTTransforms transforms) throws SLCommandException { + + // create reference URI + String referenceURI = "#" + xmlObject.getId(); + + // create Transform to select ds:Object's children + Transform xpathTransform; + Transform c14nTransform; + try { + + XPathType xpath = new XPathType("id(\"" + xmlObject.getId() + "\")/node()", XPathType.Filter.INTERSECT); + List xpaths = Collections.singletonList(xpath); + XPathFilter2ParameterSpec params = new XPathFilter2ParameterSpec(xpaths); + + xpathTransform = ctx.getSignatureFactory().newTransform(Transform.XPATH2, params); + + // add exclusive canonicalization to avoid signing the namespace context of the ds:Object + c14nTransform = ctx.getSignatureFactory().newTransform(CanonicalizationMethod.EXCLUSIVE, (TransformParameterSpec) null); + + } catch (NoSuchAlgorithmException e) { + // algorithm must be present + throw new SLRuntimeException(e); + } catch (InvalidAlgorithmParameterException e) { + // params must be appropriate + throw new SLRuntimeException(e); + } + + if (transforms == null) { + List newTransfroms = new ArrayList(); + newTransfroms.add(xpathTransform); + newTransfroms.add(c14nTransform); + transforms = new XSECTTransforms(newTransfroms); + } else { + transforms.insertTransform(xpathTransform); + } + + DigestMethod dm; + try { + dm = ctx.getAlgorithmMethodFactory().createDigestMethod(ctx); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to get DigestMethod.", e); + throw new SLCommandException(4006); + } catch (InvalidAlgorithmParameterException e) { + log.error("Failed to get DigestMethod.", e); + throw new SLCommandException(4006); + } + String id = ctx.getIdValueFactory().createIdValue("Reference"); + + this.xmlObject = xmlObject; + this.reference = new XSECTReference(referenceURI, dm, transforms, null, id); + + } + + /** + * Parses the given xmlContent and returns a corresponding + * document fragment. + * + *

+ * The to-be parsed content is surrounded by ... elements to + * allow for mixed (e.g. Text and Element) content in XMLContent. + *

+ * + * @param xmlContent + * the XMLContent to-be parsed + * + * @return a document fragment containing the parsed nodes + * + * @throws SLCommandException + * if parsing the given xmlContent fails + * + * @throws NullPointerException + * if xmlContent is null + */ + private DocumentFragment parseDataObject(XMLContentType xmlContent) throws SLCommandException { + + ByteArrayOutputStream redirectedStream = xmlContent.getRedirectedStream(); + + // Note: We can assume a fixed character encoding of UTF-8 for the + // content of the redirect stream as the content has already been parsed + // and serialized again to the redirect stream. + + List inputStreams = new ArrayList(); + try { + // dummy start element + inputStreams.add(new ByteArrayInputStream("".getBytes("UTF-8"))); + + // content + inputStreams.add(new ByteArrayInputStream(redirectedStream.toByteArray())); + + // dummy end element + inputStreams.add(new ByteArrayInputStream("".getBytes("UTF-8"))); + } catch (UnsupportedEncodingException e) { + throw new SLRuntimeException(e); + } + + SequenceInputStream inputStream = new SequenceInputStream(Collections.enumeration(inputStreams)); + + // parse DataObject + Document doc = parseDataObject(inputStream, "UTF-8"); + + Element documentElement = doc.getDocumentElement(); + + if (documentElement == null || + !"dummy".equals(documentElement.getLocalName())) { + log.info("Failed to parse DataObject XMLContent."); + throw new SLCommandException(4111); + } + + DocumentFragment fragment = doc.createDocumentFragment(); + while (documentElement.getFirstChild() != null) { + fragment.appendChild(documentElement.getFirstChild()); + } + + // log parsed document + if (log.isTraceEnabled()) { + + StringWriter writer = new StringWriter(); + + writer.write("DataObject:\n"); + + LSOutput output = domImplLS.createLSOutput(); + output.setCharacterStream(writer); + output.setEncoding("UTF-8"); + LSSerializer serializer = domImplLS.createLSSerializer(); + serializer.getDomConfig().setParameter("xml-declaration", Boolean.FALSE); + serializer.write(fragment, output); + + log.trace(writer.toString()); + } + + return fragment; + + } + + /** + * Parses the given inputStream using the given + * encoding and returns the parsed document. + * + * @param inputStream + * the to-be parsed input + * + * @param encoding + * the encoding to be used for parsing the given + * inputStream + * + * @return the parsed document + * + * @throws SLCommandException + * if parsing the inputStream fails. + * + * @throws NullPointerException + * if inputStram is null + */ + private Document parseDataObject(InputStream inputStream, String encoding) throws SLCommandException { + + LSInput input = domImplLS.createLSInput(); + input.setByteStream(inputStream); + + if (encoding != null) { + input.setEncoding(encoding); + } + + LSParser parser = domImplLS.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null); + DOMConfiguration domConfig = parser.getDomConfig(); + SimpleDOMErrorHandler errorHandler = new SimpleDOMErrorHandler(); + domConfig.setParameter("error-handler", errorHandler); + domConfig.setParameter("validate", Boolean.FALSE); + + Document doc; + try { + doc = parser.parse(input); + } catch (DOMException e) { + log.info("Existing XML document cannot be parsed.", e); + throw new SLCommandException(4111); + } catch (LSException e) { + log.info("Existing XML document cannot be parsed. ", e); + throw new SLCommandException(4111); + } + + if (errorHandler.hasErrors()) { + // log errors + if (log.isInfoEnabled()) { + List errorMessages = errorHandler.getErrorMessages(); + StringBuffer sb = new StringBuffer(); + for (String errorMessage : errorMessages) { + sb.append(" "); + sb.append(errorMessage); + } + log.info("Existing XML document cannot be parsed. " + sb.toString()); + } + throw new SLCommandException(4111); + } + + return doc; + + } + + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java index 8baa0137..9182e824 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java @@ -87,6 +87,8 @@ import at.gv.egiz.bku.utils.urldereferencer.StreamData; import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerContext; import at.gv.egiz.dom.DOMUtils; +import at.gv.egiz.marshal.NamespacePrefix; +import at.gv.egiz.marshal.NamespacePrefixMapperImpl; import at.gv.egiz.slbinding.impl.XMLContentType; import at.gv.egiz.stal.STAL; import at.gv.egiz.xades.QualifyingPropertiesException; @@ -99,6 +101,7 @@ import at.gv.egiz.xades.QualifyingPropertiesFactory; * @author mcentner */ public class Signature { + public static final String XMLDSIG_PREFIX = "dsig"; /** * Logging facility. @@ -407,7 +410,7 @@ public class Signature { signContext.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE); - signContext.putNamespacePrefix(XMLSignature.XMLNS, "dsig"); + signContext.putNamespacePrefix(XMLSignature.XMLNS,XMLDSIG_PREFIX); signContext.setURIDereferencer(new URIDereferncerAdapter(ctx.getDereferencerContext())); diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java index 78172dcb..7ce7b42d 100644 --- a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java @@ -14,185 +14,186 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package at.gv.egiz.bku.slcommands.impl.xsect; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import iaik.xml.crypto.XSecProvider; - -import java.io.IOException; -import java.io.InputStream; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.List; - +package at.gv.egiz.bku.slcommands.impl.xsect; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import iaik.xml.crypto.XSecProvider; + +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.List; + import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSocketFactory; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBElement; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Unmarshaller; -import javax.xml.crypto.MarshalException; -import javax.xml.crypto.dsig.CanonicalizationMethod; -import javax.xml.crypto.dsig.DigestMethod; -import javax.xml.crypto.dsig.Reference; -import javax.xml.crypto.dsig.SignatureMethod; -import javax.xml.crypto.dsig.Transform; -import javax.xml.crypto.dsig.XMLObject; -import javax.xml.crypto.dsig.XMLSignatureException; -import javax.xml.crypto.dsig.XMLSignatureFactory; -import javax.xml.crypto.dsig.dom.DOMSignContext; -import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec; -import javax.xml.crypto.dsig.spec.DigestMethodParameterSpec; -import javax.xml.crypto.dsig.spec.SignatureMethodParameterSpec; -import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamException; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.ls.DOMImplementationLS; -import org.w3c.dom.ls.LSOutput; -import org.w3c.dom.ls.LSSerializer; - -import at.buergerkarte.namespaces.securitylayer._1.CreateXMLSignatureRequestType; -import at.buergerkarte.namespaces.securitylayer._1.DataObjectInfoType; -import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory; -import at.buergerkarte.namespaces.securitylayer._1.SignatureInfoCreationType; -import at.gv.egiz.bku.slexceptions.SLCommandException; -import at.gv.egiz.bku.slexceptions.SLRequestException; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.crypto.MarshalException; +import javax.xml.crypto.dsig.CanonicalizationMethod; +import javax.xml.crypto.dsig.DigestMethod; +import javax.xml.crypto.dsig.Reference; +import javax.xml.crypto.dsig.SignatureMethod; +import javax.xml.crypto.dsig.Transform; +import javax.xml.crypto.dsig.XMLObject; +import javax.xml.crypto.dsig.XMLSignatureException; +import javax.xml.crypto.dsig.XMLSignatureFactory; +import javax.xml.crypto.dsig.dom.DOMSignContext; +import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec; +import javax.xml.crypto.dsig.spec.DigestMethodParameterSpec; +import javax.xml.crypto.dsig.spec.SignatureMethodParameterSpec; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSSerializer; + +import at.buergerkarte.namespaces.securitylayer._1.CreateXMLSignatureRequestType; +import at.buergerkarte.namespaces.securitylayer._1.DataObjectInfoType; +import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory; +import at.buergerkarte.namespaces.securitylayer._1.SignatureInfoCreationType; +import at.gv.egiz.bku.slexceptions.SLCommandException; +import at.gv.egiz.bku.slexceptions.SLRequestException; import at.gv.egiz.bku.slexceptions.SLViewerException; -import at.gv.egiz.bku.utils.urldereferencer.StreamData; -import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; -import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerContext; -import at.gv.egiz.bku.utils.urldereferencer.URLProtocolHandler; -import at.gv.egiz.dom.DOMUtils; -import at.gv.egiz.slbinding.RedirectEventFilter; -import at.gv.egiz.slbinding.RedirectUnmarshallerListener; - -public class SignatureTest { - - private class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory { - - @Override - public CanonicalizationMethod createCanonicalizationMethod( - SignatureContext signatureContext) { - - XMLSignatureFactory signatureFactory = signatureContext.getSignatureFactory(); - - try { - return signatureFactory.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public DigestMethod createDigestMethod(SignatureContext signatureContext) { - - XMLSignatureFactory signatureFactory = signatureContext.getSignatureFactory(); - - try { - return signatureFactory.newDigestMethod(DigestMethod.SHA1, (DigestMethodParameterSpec) null); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public SignatureMethod createSignatureMethod( - SignatureContext signatureContext) { - - XMLSignatureFactory signatureFactory = signatureContext.getSignatureFactory(); - - try { - return signatureFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, (SignatureMethodParameterSpec) null); - } catch (Exception e) { - throw new RuntimeException(e); - } - - } - - } - - private static final String RESOURCE_PREFIX = "at/gv/egiz/bku/slcommands/impl/"; - - private static Unmarshaller unmarshaller; - - private static PrivateKey privateKey; - - private static X509Certificate certificate; - - @BeforeClass - public static void setUpClass() throws JAXBException, NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException, UnrecoverableKeyException { - - XSecProvider.addAsProvider(true); - - String packageName = ObjectFactory.class.getPackage().getName(); - packageName += ":" - + org.w3._2000._09.xmldsig_.ObjectFactory.class.getPackage().getName(); - JAXBContext jaxbContext = JAXBContext.newInstance(packageName); - - unmarshaller = jaxbContext.createUnmarshaller(); - - initURLDereferencer(); - - ClassLoader classLoader = SignatureTest.class.getClassLoader(); - InputStream certStream = classLoader.getResourceAsStream(RESOURCE_PREFIX + "Cert.p12"); - assertNotNull("Certificate not found.", certStream); - - char[] passwd = "1622".toCharArray(); - - KeyStore keystore = KeyStore.getInstance("PKCS12"); - keystore.load(certStream, passwd); - String firstAlias = keystore.aliases().nextElement(); - certificate = (X509Certificate) keystore.getCertificate(firstAlias); - privateKey = (PrivateKey) keystore.getKey(firstAlias, passwd); - - } - - private static void initURLDereferencer() { - - URLDereferencer.getInstance().registerHandler("testlocal", new URLProtocolHandler() { - - @Override - public StreamData dereference(String url, URLDereferencerContext context) - throws IOException { - - ClassLoader classLoader = SignatureTest.class.getClassLoader(); - - String filename = url.split(":", 2)[1]; - - InputStream stream = classLoader.getResourceAsStream(RESOURCE_PREFIX + filename); - - if (stream == null) { - - throw new IOException("Failed to resolve resource '" + url + "'."); - - } else { - - String contentType; - if (filename.endsWith(".xml")) { - contentType = "text/xml"; - } else if (filename.endsWith(".txt")) { - contentType = "text/plain"; - } else { - contentType = ""; - } - - return new StreamData(url, contentType, stream); - - } - +import at.gv.egiz.bku.utils.urldereferencer.StreamData; +import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; +import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerContext; +import at.gv.egiz.bku.utils.urldereferencer.URLProtocolHandler; +import at.gv.egiz.dom.DOMUtils; +import at.gv.egiz.slbinding.RedirectEventFilter; +import at.gv.egiz.slbinding.RedirectUnmarshallerListener; +import org.junit.Ignore; + +public class SignatureTest { + + private class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory { + + @Override + public CanonicalizationMethod createCanonicalizationMethod( + SignatureContext signatureContext) { + + XMLSignatureFactory signatureFactory = signatureContext.getSignatureFactory(); + + try { + return signatureFactory.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public DigestMethod createDigestMethod(SignatureContext signatureContext) { + + XMLSignatureFactory signatureFactory = signatureContext.getSignatureFactory(); + + try { + return signatureFactory.newDigestMethod(DigestMethod.SHA1, (DigestMethodParameterSpec) null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public SignatureMethod createSignatureMethod( + SignatureContext signatureContext) { + + XMLSignatureFactory signatureFactory = signatureContext.getSignatureFactory(); + + try { + return signatureFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, (SignatureMethodParameterSpec) null); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + + } + + private static final String RESOURCE_PREFIX = "at/gv/egiz/bku/slcommands/impl/"; + + private static Unmarshaller unmarshaller; + + private static PrivateKey privateKey; + + private static X509Certificate certificate; + + @BeforeClass + public static void setUpClass() throws JAXBException, NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException, UnrecoverableKeyException { + + XSecProvider.addAsProvider(true); + + String packageName = ObjectFactory.class.getPackage().getName(); + packageName += ":" + + org.w3._2000._09.xmldsig_.ObjectFactory.class.getPackage().getName(); + JAXBContext jaxbContext = JAXBContext.newInstance(packageName); + + unmarshaller = jaxbContext.createUnmarshaller(); + + initURLDereferencer(); + + ClassLoader classLoader = SignatureTest.class.getClassLoader(); + InputStream certStream = classLoader.getResourceAsStream(RESOURCE_PREFIX + "Cert.p12"); + assertNotNull("Certificate not found.", certStream); + + char[] passwd = "1622".toCharArray(); + + KeyStore keystore = KeyStore.getInstance("PKCS12"); + keystore.load(certStream, passwd); + String firstAlias = keystore.aliases().nextElement(); + certificate = (X509Certificate) keystore.getCertificate(firstAlias); + privateKey = (PrivateKey) keystore.getKey(firstAlias, passwd); + + } + + private static void initURLDereferencer() { + + URLDereferencer.getInstance().registerHandler("testlocal", new URLProtocolHandler() { + + @Override + public StreamData dereference(String url, URLDereferencerContext context) + throws IOException { + + ClassLoader classLoader = SignatureTest.class.getClassLoader(); + + String filename = url.split(":", 2)[1]; + + InputStream stream = classLoader.getResourceAsStream(RESOURCE_PREFIX + filename); + + if (stream == null) { + + throw new IOException("Failed to resolve resource '" + url + "'."); + + } else { + + String contentType; + if (filename.endsWith(".xml")) { + contentType = "text/xml"; + } else if (filename.endsWith(".txt")) { + contentType = "text/plain"; + } else { + contentType = ""; + } + + return new StreamData(url, contentType, stream); + + } + } @Override @@ -205,558 +206,600 @@ public class SignatureTest { public void setSSLSocketFactory(SSLSocketFactory socketFactory) { // TODO Auto-generated method stub - } - - }); - - } - - private Object unmarshal(String file) throws XMLStreamException, JAXBException { - - ClassLoader classLoader = SignatureTest.class.getClassLoader(); - InputStream resourceStream = classLoader.getResourceAsStream(RESOURCE_PREFIX + file); - assertNotNull(resourceStream); - - XMLInputFactory inputFactory = XMLInputFactory.newInstance(); - XMLEventReader eventReader = inputFactory.createXMLEventReader(resourceStream); - RedirectEventFilter redirectEventFilter = new RedirectEventFilter(); - XMLEventReader filteredReader = inputFactory.createFilteredReader(eventReader, redirectEventFilter); - - unmarshaller.setListener(new RedirectUnmarshallerListener(redirectEventFilter)); - - return unmarshaller.unmarshal(filteredReader); - - } - - // - // - // SignatureInfo - // - // - - @SuppressWarnings("unchecked") - private SignatureInfoCreationType unmarshalSignatureInfo(String file) throws JAXBException, XMLStreamException { - - Object object = unmarshal(file); - - Object requestType = ((JAXBElement) object).getValue(); - - assertTrue(requestType instanceof CreateXMLSignatureRequestType); - - SignatureInfoCreationType signatureInfo = ((CreateXMLSignatureRequestType) requestType).getSignatureInfo(); - - assertNotNull(signatureInfo); - - return signatureInfo; - - } - - @Test - public void testSetSignatureInfo_Base64_1() throws JAXBException, SLCommandException, XMLStreamException { - - SignatureInfoCreationType signatureInfo = unmarshalSignatureInfo("SignatureInfo_Base64_1.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), null); - - signature.setSignatureInfo(signatureInfo); - - Node parent = signature.getParent(); - Node nextSibling = signature.getNextSibling(); - - assertNotNull(parent); - assertTrue("urn:document".equals(parent.getNamespaceURI())); - assertTrue("XMLDocument".equals(parent.getLocalName())); - - assertNotNull(nextSibling); - assertTrue("urn:document".equals(nextSibling.getNamespaceURI())); - assertTrue("Paragraph".equals(nextSibling.getLocalName())); - - } - - @Test - public void testSetSignature_Base64_2() throws JAXBException, SLCommandException, XMLStreamException { - - SignatureInfoCreationType signatureInfo = unmarshalSignatureInfo("SignatureInfo_Base64_2.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), null); - - signature.setSignatureInfo(signatureInfo); - - Node parent = signature.getParent(); - Node nextSibling = signature.getNextSibling(); - - assertNotNull(parent); - assertTrue("XMLDocument".equals(parent.getLocalName())); - - assertNotNull(nextSibling); - assertTrue("Paragraph".equals(nextSibling.getLocalName())); - - } - - @Test - public void testSetSignature_Base64_3() throws JAXBException, SLCommandException, XMLStreamException { - - SignatureInfoCreationType signatureInfo = unmarshalSignatureInfo("SignatureInfo_Base64_3.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), null); - - signature.setSignatureInfo(signatureInfo); - - Node parent = signature.getParent(); - Node nextSibling = signature.getNextSibling(); - - assertNotNull(parent); - assertTrue("XMLDocument".equals(parent.getLocalName())); - - assertNotNull(nextSibling); - assertTrue("Paragraph".equals(nextSibling.getLocalName())); - - } - - @Test - public void testSetSignatureInfo_XMLContent_1() throws JAXBException, SLCommandException, XMLStreamException { - - SignatureInfoCreationType signatureInfo = unmarshalSignatureInfo("SignatureInfo_XMLContent_1.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), null); - - signature.setSignatureInfo(signatureInfo); - - Node parent = signature.getParent(); - Node nextSibling = signature.getNextSibling(); - - assertNotNull(parent); - assertTrue("urn:document".equals(parent.getNamespaceURI())); - assertTrue("Whole".equals(parent.getLocalName())); - - assertNull(nextSibling); - - } - - @Test - public void testSetSignature_Reference_1() throws JAXBException, SLCommandException, XMLStreamException { - - SignatureInfoCreationType signatureInfo = unmarshalSignatureInfo("SignatureInfo_Reference_1.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), null); - - signature.setSignatureInfo(signatureInfo); - - Node parent = signature.getParent(); - Node nextSibling = signature.getNextSibling(); - - assertNotNull(parent); - assertTrue("urn:document".equals(parent.getNamespaceURI())); - assertTrue("Paragraph".equals(parent.getLocalName())); - - assertNull(nextSibling); - - } - - // - // - // DataObject - // - // - - @SuppressWarnings("unchecked") - private List unmarshalDataObjectInfo(String file) throws JAXBException, XMLStreamException { - - Object object = unmarshal(file); - - Object requestType = ((JAXBElement) object).getValue(); - - assertTrue(requestType instanceof CreateXMLSignatureRequestType); - - List dataObjectInfos = ((CreateXMLSignatureRequestType) requestType).getDataObjectInfo(); - - assertNotNull(dataObjectInfos); - - return dataObjectInfos; - - } - - private void signAndMarshalSignature(Signature signature) throws MarshalException, XMLSignatureException, SLCommandException, SLViewerException { - - Node parent = signature.getParent(); - Node nextSibling = signature.getNextSibling(); - - DOMSignContext signContext = (nextSibling == null) - ? new DOMSignContext(privateKey, parent) - : new DOMSignContext(privateKey, parent, nextSibling); - - signature.sign(signContext); - - Document document = signature.getDocument(); - - DOMImplementationLS domImplLS = DOMUtils.getDOMImplementationLS(); - LSOutput output = domImplLS.createLSOutput(); - output.setByteStream(System.out); - - LSSerializer serializer = domImplLS.createLSSerializer(); -// serializer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE); - serializer.getDomConfig().setParameter("namespaces", Boolean.FALSE); - serializer.write(document, output); - - } - - @SuppressWarnings("unchecked") - @Test - public void testDataObject_Base64Content_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { - - List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Base64Content_1.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); - - for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { - signature.addDataObject(dataObjectInfo); - } - - signature.setSignerCeritifcate(certificate); - - signature.buildXMLSignature(); - - signAndMarshalSignature(signature); - - List references = signature.getReferences(); - assertTrue(references.size() == 2); - - Reference reference = references.get(0); - assertNotNull(reference.getId()); - - List transforms = reference.getTransforms(); - assertTrue(transforms.size() == 1); - - Transform transform = transforms.get(0); - assertTrue(Transform.BASE64.equals(transform.getAlgorithm())); - - List objects = signature.getXMLObjects(); - assertNotNull(objects); - assertTrue("Size " + objects.size() + " but should be 2.", objects.size() == 2); - - XMLObject object = objects.get(0); - - assertTrue(("#" + object.getId()).equals(reference.getURI())); - - } - - @SuppressWarnings("unchecked") - @Test - public void testDataObject_XMLContent_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { - - List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_XMLContent_1.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); - - for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { - signature.addDataObject(dataObjectInfo); - } - - signature.setSignerCeritifcate(certificate); - - signature.buildXMLSignature(); - - signAndMarshalSignature(signature); - - List references = signature.getReferences(); - assertTrue(references.size() == 2); - - Reference reference = references.get(0); - assertNotNull(reference.getId()); - - List transforms = reference.getTransforms(); - assertTrue(transforms.size() == 2); - - Transform transform = transforms.get(0); - assertTrue(Transform.XPATH2.equals(transform.getAlgorithm())); - - List objects = signature.getXMLObjects(); - assertNotNull(objects); - assertTrue("Size " + objects.size() + " but should be 2.", objects.size() == 2); - - XMLObject object = objects.get(0); - - assertTrue(("#" + object.getId()).equals(reference.getURI())); - - } - - @SuppressWarnings("unchecked") - @Test - public void testDataObject_XMLContent_2() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { - - List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_XMLContent_2.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); - - for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { - signature.addDataObject(dataObjectInfo); - } - - signature.setSignerCeritifcate(certificate); - - signature.buildXMLSignature(); - - signAndMarshalSignature(signature); - - List references = signature.getReferences(); - assertTrue(references.size() == 2); - - Reference reference = references.get(0); - assertNotNull(reference.getId()); - - List transforms = reference.getTransforms(); - assertTrue(transforms.size() == 2); - - Transform transform = transforms.get(0); - assertTrue(Transform.XPATH2.equals(transform.getAlgorithm())); - - List objects = signature.getXMLObjects(); - assertNotNull(objects); - assertTrue("Size " + objects.size() + " but should be 2.", objects.size() == 2); - - XMLObject object = objects.get(0); - - assertTrue(("#" + object.getId()).equals(reference.getURI())); - - } - - - @SuppressWarnings("unchecked") - @Test - public void testDataObject_LocRefContent_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { - - List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_LocRefContent_1.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); - - for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { - signature.addDataObject(dataObjectInfo); - } - - signature.buildXMLSignature(); - - signAndMarshalSignature(signature); - - List references = signature.getReferences(); - assertTrue(references.size() == 2); - - Reference reference = references.get(0); - assertNotNull(reference.getId()); - - List transforms = reference.getTransforms(); - assertTrue(transforms.size() == 2); - - Transform transform = transforms.get(0); - assertTrue(Transform.XPATH2.equals(transform.getAlgorithm())); - - List objects = signature.getXMLObjects(); - assertNotNull(objects); - assertTrue("Size " + objects.size() + " but should be 2.", objects.size() == 2); - - XMLObject object = objects.get(0); - - assertTrue(("#" + object.getId()).equals(reference.getURI())); - - } - - @SuppressWarnings("unchecked") - @Test - public void testDataObject_LocRefContent_2() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { - - List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_LocRefContent_2.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); - - for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { - signature.addDataObject(dataObjectInfo); - } - - signature.buildXMLSignature(); - - signAndMarshalSignature(signature); - - List references = signature.getReferences(); - assertTrue(references.size() == 2); - - Reference reference = references.get(0); - assertNotNull(reference.getId()); - - List transforms = reference.getTransforms(); - assertTrue(transforms.size() == 1); - - Transform transform = transforms.get(0); - assertTrue(Transform.BASE64.equals(transform.getAlgorithm())); - - List objects = signature.getXMLObjects(); - assertNotNull(objects); - assertTrue("Size " + objects.size() + " but should be 2.", objects.size() == 2); - - XMLObject object = objects.get(0); - - assertTrue(("#" + object.getId()).equals(reference.getURI())); - - } - - @SuppressWarnings("unchecked") - @Test - public void testDataObject_Reference_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { - - List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Reference_1.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); - - for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { - signature.addDataObject(dataObjectInfo); - } - - signature.buildXMLSignature(); - - signAndMarshalSignature(signature); - - List references = signature.getReferences(); - assertTrue(references.size() == 2); - - Reference reference = references.get(0); - assertNotNull(reference.getId()); - - List transforms = reference.getTransforms(); - assertTrue(transforms.size() == 1); - - Transform transform = transforms.get(0); - assertTrue(Transform.BASE64.equals(transform.getAlgorithm())); - - List objects = signature.getXMLObjects(); - assertNotNull(objects); - assertTrue("Size " + objects.size() + " but should be 2.", objects.size() == 2); - - XMLObject object = objects.get(0); - - assertTrue(("#" + object.getId()).equals(reference.getURI())); - - } - - @SuppressWarnings("unchecked") - @Test - public void testDataObject_Detached_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { - - List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Detached_1.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); - - for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { - signature.addDataObject(dataObjectInfo); - } - - signature.buildXMLSignature(); - - signAndMarshalSignature(signature); - - List references = signature.getReferences(); - assertTrue(references.size() == 2); - - Reference reference = references.get(0); - assertNotNull(reference.getId()); - - List transforms = reference.getTransforms(); - assertTrue(transforms.size() == 0); - - List objects = signature.getXMLObjects(); - assertNotNull(objects); - assertTrue(objects.size() == 1); - - } - - @SuppressWarnings("unchecked") - @Test - public void testDataObject_Detached_Base64Content() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { - - List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Detached_Base64Content.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); - - for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { - signature.addDataObject(dataObjectInfo); - } - - signature.buildXMLSignature(); - - signAndMarshalSignature(signature); - - List references = signature.getReferences(); - assertTrue(references.size() == 2); - - Reference reference = references.get(0); - assertNotNull(reference.getId()); - - List transforms = reference.getTransforms(); - assertTrue(transforms.size() == 0); - - List objects = signature.getXMLObjects(); - assertNotNull(objects); - assertTrue(objects.size() == 1); - - } - - // - // - // TransformsInfo - // - // - - @SuppressWarnings("unchecked") - private CreateXMLSignatureRequestType unmarshalCreateXMLSignatureRequest(String file) throws JAXBException, XMLStreamException { - - Object object = unmarshal(file); - - Object requestType = ((JAXBElement) object).getValue(); - - assertTrue(requestType instanceof CreateXMLSignatureRequestType); - - return (CreateXMLSignatureRequestType) requestType; - - } - - - @SuppressWarnings("unchecked") - @Test - public void testTransformsInfo_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { - - CreateXMLSignatureRequestType requestType = unmarshalCreateXMLSignatureRequest("TransformsInfo_1.xml"); - - Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); - - - signature.setSignatureInfo(requestType.getSignatureInfo()); - - List dataObjectInfos = requestType.getDataObjectInfo(); - - for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { - signature.addDataObject(dataObjectInfo); - } - - signature.setSignerCeritifcate(certificate); - - signature.buildXMLSignature(); - - signAndMarshalSignature(signature); - - List references = signature.getReferences(); - assertTrue(references.size() == 2); - - Reference reference = references.get(0); - assertNotNull(reference.getId()); - - List transforms = reference.getTransforms(); - assertTrue("Size " + transforms.size() + "", transforms.size() == 3); - - Transform transform = transforms.get(0); - assertTrue(Transform.ENVELOPED.equals(transform.getAlgorithm())); - - List objects = signature.getXMLObjects(); - assertNotNull(objects); - assertTrue("Size " + objects.size() + " but should be 1.", objects.size() == 1); - - } - - -} + } + + }); + + } + + private Object unmarshal(String file) throws XMLStreamException, JAXBException { + + ClassLoader classLoader = SignatureTest.class.getClassLoader(); + InputStream resourceStream = classLoader.getResourceAsStream(RESOURCE_PREFIX + file); + assertNotNull(resourceStream); + + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLEventReader eventReader = inputFactory.createXMLEventReader(resourceStream); + RedirectEventFilter redirectEventFilter = new RedirectEventFilter(); + XMLEventReader filteredReader = inputFactory.createFilteredReader(eventReader, redirectEventFilter); + + unmarshaller.setListener(new RedirectUnmarshallerListener(redirectEventFilter)); + + return unmarshaller.unmarshal(filteredReader); + + } + + // + // + // SignatureInfo + // + // + + @SuppressWarnings("unchecked") + private SignatureInfoCreationType unmarshalSignatureInfo(String file) throws JAXBException, XMLStreamException { + + Object object = unmarshal(file); + + Object requestType = ((JAXBElement) object).getValue(); + + assertTrue(requestType instanceof CreateXMLSignatureRequestType); + + SignatureInfoCreationType signatureInfo = ((CreateXMLSignatureRequestType) requestType).getSignatureInfo(); + + assertNotNull(signatureInfo); + + return signatureInfo; + + } + + @Test + public void testSetSignatureInfo_Base64_1() throws JAXBException, SLCommandException, XMLStreamException { + + SignatureInfoCreationType signatureInfo = unmarshalSignatureInfo("SignatureInfo_Base64_1.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), null); + + signature.setSignatureInfo(signatureInfo); + + Node parent = signature.getParent(); + Node nextSibling = signature.getNextSibling(); + + assertNotNull(parent); + assertTrue("urn:document".equals(parent.getNamespaceURI())); + assertTrue("XMLDocument".equals(parent.getLocalName())); + + assertNotNull(nextSibling); + assertTrue("urn:document".equals(nextSibling.getNamespaceURI())); + assertTrue("Paragraph".equals(nextSibling.getLocalName())); + + } + + @Test + public void testSetSignature_Base64_2() throws JAXBException, SLCommandException, XMLStreamException { + + SignatureInfoCreationType signatureInfo = unmarshalSignatureInfo("SignatureInfo_Base64_2.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), null); + + signature.setSignatureInfo(signatureInfo); + + Node parent = signature.getParent(); + Node nextSibling = signature.getNextSibling(); + + assertNotNull(parent); + assertTrue("XMLDocument".equals(parent.getLocalName())); + + assertNotNull(nextSibling); + assertTrue("Paragraph".equals(nextSibling.getLocalName())); + + } + + @Test + public void testSetSignature_Base64_3() throws JAXBException, SLCommandException, XMLStreamException { + + SignatureInfoCreationType signatureInfo = unmarshalSignatureInfo("SignatureInfo_Base64_3.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), null); + + signature.setSignatureInfo(signatureInfo); + + Node parent = signature.getParent(); + Node nextSibling = signature.getNextSibling(); + + assertNotNull(parent); + assertTrue("XMLDocument".equals(parent.getLocalName())); + + assertNotNull(nextSibling); + assertTrue("Paragraph".equals(nextSibling.getLocalName())); + + } + + @Test + public void testSetSignatureInfo_XMLContent_1() throws JAXBException, SLCommandException, XMLStreamException { + + SignatureInfoCreationType signatureInfo = unmarshalSignatureInfo("SignatureInfo_XMLContent_1.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), null); + + signature.setSignatureInfo(signatureInfo); + + Node parent = signature.getParent(); + Node nextSibling = signature.getNextSibling(); + + assertNotNull(parent); + assertTrue("urn:document".equals(parent.getNamespaceURI())); + assertTrue("Whole".equals(parent.getLocalName())); + + assertNull(nextSibling); + + } + + @Test + public void testSetSignature_Reference_1() throws JAXBException, SLCommandException, XMLStreamException { + + SignatureInfoCreationType signatureInfo = unmarshalSignatureInfo("SignatureInfo_Reference_1.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), null); + + signature.setSignatureInfo(signatureInfo); + + Node parent = signature.getParent(); + Node nextSibling = signature.getNextSibling(); + + assertNotNull(parent); + assertTrue("urn:document".equals(parent.getNamespaceURI())); + assertTrue("Paragraph".equals(parent.getLocalName())); + + assertNull(nextSibling); + + } + + // + // + // DataObject + // + // + + @SuppressWarnings("unchecked") + private List unmarshalDataObjectInfo(String file) throws JAXBException, XMLStreamException { + + Object object = unmarshal(file); + + Object requestType = ((JAXBElement) object).getValue(); + + assertTrue(requestType instanceof CreateXMLSignatureRequestType); + + List dataObjectInfos = ((CreateXMLSignatureRequestType) requestType).getDataObjectInfo(); + + assertNotNull(dataObjectInfos); + + return dataObjectInfos; + + } + + private void signAndMarshalSignature(Signature signature) throws MarshalException, XMLSignatureException, SLCommandException, SLViewerException { + + Node parent = signature.getParent(); + Node nextSibling = signature.getNextSibling(); + + DOMSignContext signContext = (nextSibling == null) + ? new DOMSignContext(privateKey, parent) + : new DOMSignContext(privateKey, parent, nextSibling); + + signature.sign(signContext); + + Document document = signature.getDocument(); + + DOMImplementationLS domImplLS = DOMUtils.getDOMImplementationLS(); + LSOutput output = domImplLS.createLSOutput(); + output.setByteStream(System.out); + + LSSerializer serializer = domImplLS.createLSSerializer(); +// serializer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE); + serializer.getDomConfig().setParameter("namespaces", Boolean.FALSE); + serializer.write(document, output); + + } + + @SuppressWarnings("unchecked") + @Test + public void testDataObject_Base64Content_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Base64Content_1.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); + + for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { + signature.addDataObject(dataObjectInfo); + } + + signature.setSignerCeritifcate(certificate); + + signature.buildXMLSignature(); + + signAndMarshalSignature(signature); + + List references = signature.getReferences(); + assertTrue(references.size() == 2); + + Reference reference = references.get(0); + assertNotNull(reference.getId()); + + List transforms = reference.getTransforms(); + assertTrue(transforms.size() == 1); + + Transform transform = transforms.get(0); + assertTrue(Transform.BASE64.equals(transform.getAlgorithm())); + + List objects = signature.getXMLObjects(); + assertNotNull(objects); + assertTrue("Size " + objects.size() + " but should be 2.", objects.size() == 2); + + XMLObject object = objects.get(0); + + assertTrue(("#" + object.getId()).equals(reference.getURI())); + + } + + @SuppressWarnings("unchecked") + @Test + public void testDataObject_XMLContent_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_XMLContent_1.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); + + for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { + signature.addDataObject(dataObjectInfo); + } + + signature.setSignerCeritifcate(certificate); + + signature.buildXMLSignature(); + + signAndMarshalSignature(signature); + + List references = signature.getReferences(); + assertTrue(references.size() == 2); + + Reference reference = references.get(0); + assertNotNull(reference.getId()); + + List transforms = reference.getTransforms(); + assertTrue(transforms.size() == 2); + + Transform transform = transforms.get(0); + assertTrue(Transform.XPATH2.equals(transform.getAlgorithm())); + + List objects = signature.getXMLObjects(); + assertNotNull(objects); + assertTrue("Size " + objects.size() + " but should be 2.", objects.size() == 2); + + XMLObject object = objects.get(0); + + assertTrue(("#" + object.getId()).equals(reference.getURI())); + + } + + @SuppressWarnings("unchecked") + @Test + public void testDataObject_XMLContent_2() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_XMLContent_2.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); + + for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { + signature.addDataObject(dataObjectInfo); + } + + signature.setSignerCeritifcate(certificate); + + signature.buildXMLSignature(); + + signAndMarshalSignature(signature); + + List references = signature.getReferences(); + assertTrue(references.size() == 2); + + Reference reference = references.get(0); + assertNotNull(reference.getId()); + + List transforms = reference.getTransforms(); + assertTrue(transforms.size() == 2); + + Transform transform = transforms.get(0); + assertTrue(Transform.XPATH2.equals(transform.getAlgorithm())); + + List objects = signature.getXMLObjects(); + assertNotNull(objects); + assertTrue("Size " + objects.size() + " but should be 2.", objects.size() == 2); + + XMLObject object = objects.get(0); + + assertTrue(("#" + object.getId()).equals(reference.getURI())); + + } + + + @SuppressWarnings("unchecked") + @Test + public void testDataObject_LocRefContent_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_LocRefContent_1.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); + + for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { + signature.addDataObject(dataObjectInfo); + } + + signature.buildXMLSignature(); + + signAndMarshalSignature(signature); + + List references = signature.getReferences(); + assertTrue(references.size() == 2); + + Reference reference = references.get(0); + assertNotNull(reference.getId()); + + List transforms = reference.getTransforms(); + assertTrue(transforms.size() == 2); + + Transform transform = transforms.get(0); + assertTrue(Transform.XPATH2.equals(transform.getAlgorithm())); + + List objects = signature.getXMLObjects(); + assertNotNull(objects); + assertTrue("Size " + objects.size() + " but should be 2.", objects.size() == 2); + + XMLObject object = objects.get(0); + + assertTrue(("#" + object.getId()).equals(reference.getURI())); + + } + + @SuppressWarnings("unchecked") + @Test + public void testDataObject_LocRefContent_2() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_LocRefContent_2.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); + + for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { + signature.addDataObject(dataObjectInfo); + } + + signature.buildXMLSignature(); + + signAndMarshalSignature(signature); + + List references = signature.getReferences(); + assertTrue(references.size() == 2); + + Reference reference = references.get(0); + assertNotNull(reference.getId()); + + List transforms = reference.getTransforms(); + assertTrue(transforms.size() == 1); + + Transform transform = transforms.get(0); + assertTrue(Transform.BASE64.equals(transform.getAlgorithm())); + + List objects = signature.getXMLObjects(); + assertNotNull(objects); + assertTrue("Size " + objects.size() + " but should be 2.", objects.size() == 2); + + XMLObject object = objects.get(0); + + assertTrue(("#" + object.getId()).equals(reference.getURI())); + + } + + @SuppressWarnings("unchecked") + @Test + public void testDataObject_Reference_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Reference_1.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); + + for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { + signature.addDataObject(dataObjectInfo); + } + + signature.buildXMLSignature(); + + signAndMarshalSignature(signature); + + List references = signature.getReferences(); + assertTrue(references.size() == 2); + + Reference reference = references.get(0); + assertNotNull(reference.getId()); + + List transforms = reference.getTransforms(); + assertTrue(transforms.size() == 1); + + Transform transform = transforms.get(0); + assertTrue(Transform.BASE64.equals(transform.getAlgorithm())); + + List objects = signature.getXMLObjects(); + assertNotNull(objects); + assertTrue("Size " + objects.size() + " but should be 2.", objects.size() == 2); + + XMLObject object = objects.get(0); + + assertTrue(("#" + object.getId()).equals(reference.getURI())); + + } + + @SuppressWarnings("unchecked") + @Test + public void testDataObject_Detached_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Detached_1.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); + + for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { + signature.addDataObject(dataObjectInfo); + } + + signature.buildXMLSignature(); + + signAndMarshalSignature(signature); + + List references = signature.getReferences(); + assertTrue(references.size() == 2); + + Reference reference = references.get(0); + assertNotNull(reference.getId()); + + List transforms = reference.getTransforms(); + assertTrue(transforms.size() == 0); + + List objects = signature.getXMLObjects(); + assertNotNull(objects); + assertTrue(objects.size() == 1); + + } + + @SuppressWarnings("unchecked") + @Test + public void testDataObject_Detached_Base64Content() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Detached_Base64Content.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); + + for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { + signature.addDataObject(dataObjectInfo); + } + + signature.buildXMLSignature(); + + signAndMarshalSignature(signature); + + List references = signature.getReferences(); + assertTrue(references.size() == 2); + + Reference reference = references.get(0); + assertNotNull(reference.getId()); + + List transforms = reference.getTransforms(); + assertTrue(transforms.size() == 0); + + List objects = signature.getXMLObjects(); + assertNotNull(objects); + assertTrue(objects.size() == 1); + + } + + // + // + // TransformsInfo + // + // + + @SuppressWarnings("unchecked") + private CreateXMLSignatureRequestType unmarshalCreateXMLSignatureRequest(String file) throws JAXBException, XMLStreamException { + + Object object = unmarshal(file); + + Object requestType = ((JAXBElement) object).getValue(); + + assertTrue(requestType instanceof CreateXMLSignatureRequestType); + + return (CreateXMLSignatureRequestType) requestType; + + } + + + @SuppressWarnings("unchecked") + @Test + public void testTransformsInfo_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + + CreateXMLSignatureRequestType requestType = unmarshalCreateXMLSignatureRequest("TransformsInfo_1.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); + + + signature.setSignatureInfo(requestType.getSignatureInfo()); + + List dataObjectInfos = requestType.getDataObjectInfo(); + + for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { + signature.addDataObject(dataObjectInfo); + } + + signature.setSignerCeritifcate(certificate); + + signature.buildXMLSignature(); + + signAndMarshalSignature(signature); + + List references = signature.getReferences(); + assertTrue(references.size() == 2); + + Reference reference = references.get(0); + assertNotNull(reference.getId()); + + List transforms = reference.getTransforms(); + assertTrue("Size " + transforms.size() + "", transforms.size() == 3); + + Transform transform = transforms.get(0); + assertTrue(Transform.ENVELOPED.equals(transform.getAlgorithm())); + + List objects = signature.getXMLObjects(); + assertNotNull(objects); + assertTrue("Size " + objects.size() + " but should be 1.", objects.size() == 1); + + } + + @SuppressWarnings("unchecked") + @Test + @Ignore + public void testTransformsInfo_2() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + + CreateXMLSignatureRequestType requestType = unmarshalCreateXMLSignatureRequest("TransformsInfo_2.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); + + + signature.setSignatureInfo(requestType.getSignatureInfo()); + + List dataObjectInfos = requestType.getDataObjectInfo(); + + for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { + signature.addDataObject(dataObjectInfo); + } + + signature.setSignerCeritifcate(certificate); + + signature.buildXMLSignature(); + + signAndMarshalSignature(signature); + + List references = signature.getReferences(); + assertTrue(references.size() == 2); + + Reference reference = references.get(0); + assertNotNull(reference.getId()); + + List transforms = reference.getTransforms(); + assertTrue("Size " + transforms.size() + "", transforms.size() == 2); + + Transform transform = transforms.get(0); + assertTrue(Transform.XSLT.equals(transform.getAlgorithm())); + + List objects = signature.getXMLObjects(); + assertNotNull(objects); + assertTrue("Size " + objects.size() + " but should be 1.", objects.size() == 1); + + } + + +} diff --git a/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/impl/TransformsInfo_2.xml b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/impl/TransformsInfo_2.xml new file mode 100644 index 00000000..f43dc61a --- /dev/null +++ b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/impl/TransformsInfo_2.xml @@ -0,0 +1,397 @@ + + + SecureSignatureKeypair + + + + + + + + + + + Signatur der Anmeldedaten + + + +

Signatur der Anmeldedaten

+

+

Mit meiner elektronischen Signatur beantrage ich, + + , geboren am . . , in der Rolle als (OID***= ), den Zugang zur gesicherten Anwendung.

+

+

Datum und Uhrzeit: . . , : + : +

+ +

HPI(**):

+
+ +

wbPK(*):

+
+ +
+

Ich bin weiters ermächtigt als von + , geboren am . . + + , + , in deren Auftrag zu handeln. +

wbPK(*) des Vollmachtgebers:

+
+

+

+ + + +

+


+ + +

+


+
+ +

+


+
+ + +
(*) wbPK: Das wirtschaftsbereichsspezifische + Personenkennzeichen wird aus den jeweiligen + Stammzahlen des Bürgers und des Wirtschaftsunternehmens + berechnet und ermöglicht eine eindeutige Zuordnung des + Bürgers zum Wirtschaftsunternehmen.
+
+ +
(**) HPI: Der eHealth Professional + Identifier wird aus den jeweiligen Stammzahlen + der Gesundheitsdiensteanbieterinnen / + Gesundheitsdiensteanbieter berechnet und ermöglicht eine + eindeutige Zuordnung der Gesundheitsdiensteanbieterin / + des Gesundheitsdiensteanbieters im + Gesundheitsbereich.
+
+ +
(***) OID: Object Identifier sind + standardisierte Objekt-Bezeichner und beschreiben + eindeutig die Rollen des GDA-Token Inhabers.
+
+ + +
+
+
+ +
+ + application/xhtml+xml + +
+ + + + + + + + + + Signatur der Anmeldedaten + + +

Signatur der Anmeldedaten

+

+

Mit meiner elektronischen Signatur beantrage ich, + + , geboren am . . , in der Rolle als (OID***= ), den Zugang zur gesicherten Anwendung.

+

+

Datum und Uhrzeit: . . , : + : +

+ +

HPI(**):

+
+ +

wbPK(*):

+
+ +
+

Ich bin weiters ermächtigt als von + , geboren am . . + + , + , in deren Auftrag zu handeln. +

wbPK(*) des Vollmachtgebers:

+
+

+

+ + + +

+


+ + +

+


+
+ +

+


+
+ + +
(*) wbPK: Das wirtschaftsbereichsspezifische + Personenkennzeichen wird aus den jeweiligen + Stammzahlen des Bürgers und des Wirtschaftsunternehmens + berechnet und ermöglicht eine eindeutige Zuordnung des + Bürgers zum Wirtschaftsunternehmen.
+
+ +
(**) HPI: Der eHealth Professional Identifier + wird aus den jeweiligen Stammzahlen der + Gesundheitsdiensteanbieterinnen / + Gesundheitsdiensteanbieter berechnet und ermöglicht eine + eindeutige Zuordnung der Gesundheitsdiensteanbieterin / + des Gesundheitsdiensteanbieters im + Gesundheitsbereich.
+
+ +
(***) OID: Object Identifier sind standardisierte + Objekt-Bezeichner und beschreiben eindeutig die Rollen + des GDA-Token Inhabers.
+
+ + +
+
+
+ +
+ + text/html + +
+ + + + + + + + Mit meiner elektronischen Signatur beantrage ich, + + , geboren am + + . + + . + + , + + in der Rolle als + + (OID***= + ) + , + + den Zugang zur gesicherten Anwendung. + Datum und Uhrzeit: + + . + + . + + , + + : + + : + + + + HPI(**): + + + + + wbPK(*): + + + + + Ich bin weiters ermächtigt als + + von + + + , geboren am + + . + + . + + + + , + + + , in deren Auftrag zu handeln. + + + wbPK(*) des Vollmachtgebers: + + + + + + (*) wbPK: Das wirtschaftsbereichsspezifische Personenkennzeichen wird aus den jeweiligen Stammzahlen des Bürgers und des Wirtschaftsunternehmens berechnet und ermöglicht eine eindeutige Zuordnung des Bürgers zum Wirtschaftsunternehmen. + + + (**) HPI: Der eHealth Professional Identifier wird aus den jeweiligen Stammzahlen der Gesundheitsdiensteanbieterinnen / Gesundheitsdiensteanbieter berechnet und ermöglicht eine eindeutige Zuordnung der Gesundheitsdiensteanbieterin / des Gesundheitsdiensteanbieters im Gesundheitsbereich. + + + (***) OID: Object Identifier sind standardisierte Objekt-Bezeichner und beschreiben eindeutig die Rollen des GDA-Token Inhabers. + + + + + + + not(text()) + + + + text/plain + + +
+ + + + + + + https://demo.egiz.gv.at/exchange-moa-id-auth/ + + + + + LTpz8VYzns2jrx0J8Gm/R/nAhxA= + urn:publicid:gv.at:wbpk+FN+TODO + + + + + https://apps.egiz.gv.at/urlaubsschein-frontend/moaid-login + + + 1971-11-10 + + + + + + /saml:Assertion + +
diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java index 13c57686..86223854 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java @@ -30,8 +30,6 @@ package at.gv.egiz.smcc; import java.nio.charset.Charset; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.smartcardio.CardChannel; import javax.smartcardio.CardException; import javax.smartcardio.CommandAPDU; @@ -41,7 +39,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class ACOSCard extends AbstractSignatureCard implements SignatureCard { - + private static Log log = LogFactory.getLog(ACOSCard.class); public static final byte[] AID_DEC = new byte[] { (byte) 0xA0, (byte) 0x00, @@ -100,8 +98,15 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard { (byte) 0x01 // RSA // TODO: Not verified yet }; + private static final int PINSPEC_INF = 0; + private static final int PINSPEC_DEC = 1; + private static final int PINSPEC_SIG = 2; + public ACOSCard() { super("at/gv/egiz/smcc/ACOSCard"); + pinSpecs.add(PINSPEC_INF, new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name"), KID_PIN_INF, null)); + pinSpecs.add(PINSPEC_DEC, new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("dec.pin.name"), KID_PIN_DEC, null)); + pinSpecs.add(PINSPEC_SIG, new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"), KID_PIN_SIG, null)); } /* (non-Javadoc) @@ -165,7 +170,8 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard { try { if ("IdentityLink".equals(infobox)) { - PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name")); + PINSpec spec = pinSpecs.get(PINSPEC_INF); + //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name")); int retries = -1; String pin = null; @@ -219,7 +225,8 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard { if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) { - PINSpec spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name")); + PINSpec spec = pinSpecs.get(PINSPEC_SIG); + //new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name")); int retries = -1; String pin = null; @@ -260,7 +267,8 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard { } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) { - PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("dec.pin.name")); + PINSpec spec = pinSpecs.get(PINSPEC_DEC); + //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("dec.pin.name")); int retries = -1; String pin = null; @@ -321,11 +329,6 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard { 0x00, fid, 256)); } - @Override - public byte[] getKIDs() { - return new byte[] { KID_PIN_DEC, KID_PIN_INF, KID_PIN_SIG }; - } - @Override public int verifyPIN(String pin, byte kid) throws LockedException, NotActivatedException, SignatureCardException { diff --git a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java index 67f090a5..cb068725 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java @@ -31,7 +31,11 @@ package at.gv.egiz.smcc; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.ResourceBundle; import javax.smartcardio.ATR; @@ -49,6 +53,8 @@ public abstract class AbstractSignatureCard implements SignatureCard { private static Log log = LogFactory.getLog(AbstractSignatureCard.class); + protected List pinSpecs = new ArrayList(); + private ResourceBundle i18n; private String resourceBundleName; @@ -433,4 +439,8 @@ public abstract class AbstractSignatureCard implements SignatureCard { } } + @Override + public List getPINSpecs() { + return pinSpecs; + } } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/PINSpec.java b/smcc/src/main/java/at/gv/egiz/smcc/PINSpec.java index 0852d664..d180ddf0 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/PINSpec.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/PINSpec.java @@ -35,23 +35,40 @@ public class PINSpec { String name_; + byte kid_; + + byte[] context_aid_; + + /** + * + * @param minLenght + * @param maxLength + * @param rexepPattern + * @param resourceBundle + * @param name + * @param kid the keyId for this pin + */ public PINSpec(int minLenght, int maxLength, String rexepPattern, - ResourceBundle resourceBundle, String name) { + ResourceBundle resourceBundle, String name, byte kid, byte[] contextAID) { minLength_ = minLenght; maxLength_ = maxLength; rexepPattern_ = rexepPattern; resourceBundle_ = resourceBundle; name_ = name; + kid_ = kid; + context_aid_ = contextAID; } public PINSpec(int minLenght, int maxLength, String rexepPattern, - String name) { + String name, byte kid, byte[] contextAID) { minLength_ = minLenght; maxLength_ = maxLength; rexepPattern_ = rexepPattern; name_ = name; + kid_ = kid; + context_aid_ = contextAID; } @@ -75,7 +92,14 @@ public class PINSpec { public String getRexepPattern() { return rexepPattern_; } - + + public byte getKID() { + return kid_; + } + + public byte[] getContextAID() { + return context_aid_; + } } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java index e80c6683..ae43629e 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java @@ -29,10 +29,8 @@ package at.gv.egiz.smcc; import java.math.BigInteger; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import javax.smartcardio.CardChannel; import javax.smartcardio.CardException; import javax.smartcardio.CommandAPDU; @@ -42,7 +40,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class STARCOSCard extends AbstractSignatureCard implements SignatureCard { - + /** * Logging facility. */ @@ -155,12 +153,17 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard }; public static final byte KID_PIN_CARD = (byte) 0x01; - + + private static final int PINSPEC_CARD = 0; + private static final int PINSPEC_SS = 1; + /** * Creates an new instance. */ public STARCOSCard() { super("at/gv/egiz/smcc/STARCOSCard"); + pinSpecs.add(PINSPEC_CARD, new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name"), KID_PIN_CARD, null)); + pinSpecs.add(PINSPEC_SS, new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name"), KID_PIN_SS, AID_DF_SS)); } @Override @@ -210,7 +213,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard try { if ("IdentityLink".equals(infobox)) { - PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); + PINSpec spec = pinSpecs.get(PINSPEC_CARD); + //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); int retries = -1; String pin = null; @@ -302,7 +306,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) { - PINSpec spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name")); + PINSpec spec = pinSpecs.get(PINSPEC_SS); + //new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name")); int retries = -1; String pin = null; @@ -334,7 +339,8 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) { - PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); + PINSpec spec = pinSpecs.get(PINSPEC_CARD); + //new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); int retries = -1; String pin = null; @@ -455,11 +461,6 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard } } - @Override - public byte[] getKIDs() { - return new byte[] { KID_PIN_CARD, KID_PIN_SS }; - } - /** * VERIFY PIN *

diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java index bad7ccf6..8dc4ac2a 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java @@ -36,9 +36,13 @@ import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; +import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; import java.util.Locale; +import java.util.Map; import javax.smartcardio.Card; import javax.smartcardio.CardTerminal; @@ -311,7 +315,7 @@ public class SWCard implements SignatureCard { if (password == null) { - PINSpec pinSpec = new PINSpec(0, -1, ".", "KeyStore-Password"); + PINSpec pinSpec = new PINSpec(0, -1, ".", "KeyStore-Password", (byte) 0x01, null); password = provider.providePIN(pinSpec, -1); @@ -390,13 +394,13 @@ public class SWCard implements SignatureCard { } @Override - public byte[] getKIDs() { - return null; + public int verifyPIN(String pin, byte kid) throws LockedException, NotActivatedException, SignatureCardException { + return -1; } @Override - public int verifyPIN(String pin, byte kid) throws LockedException, NotActivatedException, SignatureCardException { - return -1; + public List getPINSpecs() { + return new ArrayList(); } } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java index 1ec35b78..1e5e09c8 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCard.java @@ -31,6 +31,7 @@ package at.gv.egiz.smcc; import java.util.List; import java.util.Locale; +import java.util.Map; import javax.smartcardio.Card; import javax.smartcardio.CardTerminal; @@ -118,10 +119,10 @@ public interface SignatureCard { PINProvider provider) throws SignatureCardException, InterruptedException; /** - * get the KIDs for the availabel PINs + * Get the KIDs for all available PINs and the corresponding PINSpecs * @return array of KIDs */ - public byte[] getKIDs(); + public List getPINSpecs(); /** * diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/AbstractBKUWorker.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/AbstractBKUWorker.java index e10ba8f9..b6c5a8ca 100644 --- a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/AbstractBKUWorker.java +++ b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/AbstractBKUWorker.java @@ -102,6 +102,9 @@ public abstract class AbstractBKUWorker extends AbstractSMCCSTAL implements Acti @Override protected boolean waitForCard() { + if (signatureCard != null) { + return false; + } SMCCHelper smccHelper = new SMCCHelper(); actionCommandList.clear(); actionCommandList.add("cancel"); diff --git a/smccSTAL/src/test/java/at/gv/egiz/smcc/AbstractSMCCSTALTest.java b/smccSTAL/src/test/java/at/gv/egiz/smcc/AbstractSMCCSTALTest.java index a5f8a771..a5d6df23 100644 --- a/smccSTAL/src/test/java/at/gv/egiz/smcc/AbstractSMCCSTALTest.java +++ b/smccSTAL/src/test/java/at/gv/egiz/smcc/AbstractSMCCSTALTest.java @@ -86,15 +86,16 @@ public class AbstractSMCCSTALTest extends AbstractSMCCSTAL implements } - @Override - public byte[] getKIDs() { - return null; - } @Override public int verifyPIN(String pin, byte kid) throws LockedException, NotActivatedException, SignatureCardException { return 0; } + + @Override + public List getPINSpecs() { + return new ArrayList(); + } }; return false; diff --git a/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefix.java b/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefix.java new file mode 100644 index 00000000..c03f17cd --- /dev/null +++ b/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefix.java @@ -0,0 +1,34 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + * + * 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 at.gv.egiz.marshal; + +/** + * + * @author Clemens Orthacker + */ +public interface NamespacePrefix { + String CARDCHANNEL_PREFIX = "cc"; + String ECDSA_PREFIX = "ecdsa"; + String PERSONDATA_PREFIX = "pr"; + String SAML10_PREFIX = "saml"; + String SL_PREFIX = "sl"; + String XADES_PREFIX = "xades"; + String XMLDSIG_PREFIX = "xmldsig"; + String XSI_PREFIX = "xsi"; + +} diff --git a/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefixMapperImpl.java b/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefixMapperImpl.java index a08c1188..519f6b1f 100644 --- a/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefixMapperImpl.java +++ b/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefixMapperImpl.java @@ -36,35 +36,35 @@ public class NamespacePrefixMapperImpl extends NamespacePrefixMapper { log.trace("prefix for namespace " + namespaceUri + " requested"); } if ("http://www.w3.org/2001/XMLSchema-instance".equals(namespaceUri)) { - return "xsi"; + return NamespacePrefix.XSI_PREFIX; } if ("http://www.w3.org/2000/09/xmldsig#".equals(namespaceUri)) { - return "dsig"; + return NamespacePrefix.XMLDSIG_PREFIX; } if ("http://www.buergerkarte.at/namespaces/securitylayer/1.2#".equals(namespaceUri)) { - return "sl"; + return NamespacePrefix.SL_PREFIX; } if ("http://www.buergerkarte.at/cardchannel".equals(namespaceUri)) { - return "cc"; + return NamespacePrefix.CARDCHANNEL_PREFIX; } if ("http://www.w3.org/2001/04/xmldsig-more#".equals(namespaceUri)) { - return "ecdsa"; + return NamespacePrefix.ECDSA_PREFIX; } if ("http://reference.e-government.gv.at/namespace/persondata/20020228#".equals(namespaceUri)) { - return "pr"; + return NamespacePrefix.PERSONDATA_PREFIX; } if ("urn:oasis:names:tc:SAML:1.0:assertion".equals(namespaceUri)) { - return "saml"; + return NamespacePrefix.SAML10_PREFIX; } if ("http://uri.etsi.org/01903/v1.1.1#".equals(namespaceUri)) { - return "xades"; + return NamespacePrefix.XADES_PREFIX; } return suggestion; diff --git a/utils/src/main/java/at/gv/egiz/slbinding/RedirectEventFilter.java b/utils/src/main/java/at/gv/egiz/slbinding/RedirectEventFilter.java index d2a7fb30..14c5ba48 100644 --- a/utils/src/main/java/at/gv/egiz/slbinding/RedirectEventFilter.java +++ b/utils/src/main/java/at/gv/egiz/slbinding/RedirectEventFilter.java @@ -1,19 +1,19 @@ /* -* Copyright 2008 Federal Chancellery Austria and -* Graz University of Technology -* -* 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. -*/ + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + * + * 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. + */ /* * To change this template, choose Tools | Templates * and open the template in the editor. @@ -33,79 +33,84 @@ import javax.xml.stream.events.XMLEvent; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +/* + * TODO: don't set redirect stream from caller (caller does not know whether redirection will be triggered) + * rather create on trigger and pass to caller + */ public class RedirectEventFilter implements EventFilter { - public static final String DEFAULT_ENCODING = "UTF-8"; - private static Log log = LogFactory.getLog(RedirectEventFilter.class); - protected XMLEventWriter redirectWriter = null; - protected Set redirectTriggers = null; - private int depth = -1; - protected NamespaceContext currentNamespaceContext = null; + public static final String DEFAULT_ENCODING = "UTF-8"; + private static Log log = LogFactory.getLog(RedirectEventFilter.class); + protected XMLEventWriter redirectWriter = null; + protected Set redirectTriggers = null; + private int depth = -1; + protected NamespaceContext currentNamespaceContext = null; - /** - * Event redirection is disabled, set a redirect stream to enable. - */ - public RedirectEventFilter() { - redirectWriter = null; - // redirectTriggers = null; - } + /** + * Event redirection is disabled, set a redirect stream to enable. + */ + public RedirectEventFilter() { + redirectWriter = null; + // redirectTriggers = null; + } - /** - * - * @param redirectStream - * if null, no events are redirected - * @param redirectTriggers - * if null, all events are redirected - */ - public RedirectEventFilter(OutputStream redirectStream, String encoding) - throws XMLStreamException { // , List redirectTriggers - if (redirectStream != null) { - XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); - if (encoding == null) { - encoding = DEFAULT_ENCODING; - } - this.redirectWriter = outputFactory.createXMLEventWriter(redirectStream, + /** + * + * @param redirectStream + * if null, no events are redirected + * @param redirectTriggers + * if null, all events are redirected + */ + public RedirectEventFilter(OutputStream redirectStream, String encoding) + throws XMLStreamException { // , List redirectTriggers + if (redirectStream != null) { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + if (encoding == null) { + encoding = DEFAULT_ENCODING; + } + this.redirectWriter = outputFactory.createXMLEventWriter(redirectStream, encoding); - } - // this.redirectTriggers = redirectTriggers; } + // this.redirectTriggers = redirectTriggers; + } - /** - * All startElement events occuring in the redirectTriggers list will trigger - * redirection of the entire (sub-)fragment. - * - * @param event - * @return false if an event is redirected - */ - @Override - public boolean accept(XMLEvent event) { - int eventType = event.getEventType(); + /** + * All startElement events occuring in the redirectTriggers list will trigger + * redirection of the entire (sub-)fragment. + * + * @param event + * @return false if an event is redirected + */ + @Override + public boolean accept(XMLEvent event) { + int eventType = event.getEventType(); - if (eventType == XMLStreamConstants.START_ELEMENT) { - currentNamespaceContext = event.asStartElement().getNamespaceContext(); - } - if (redirectWriter == null) { - return true; - } - if (eventType == XMLStreamConstants.START_ELEMENT) { - if (depth >= 0 || triggersRedirect(event.asStartElement().getName())) { - depth++; - } - } else if (eventType == XMLStreamConstants.END_ELEMENT) { - if (depth >= 0 && --depth < 0) { - // redirect the end element of the trigger, - // but do not redirect the end element of the calling type - if (redirectTriggers != null) { - redirectEvent(event); - return false; - } - } - } - if (depth >= 0) { //|| (depth == 0 && redirectTriggers == null)) { - redirectEvent(event); - return false; + if (eventType == XMLStreamConstants.START_ELEMENT) { + //hopefully, this is a copy + currentNamespaceContext = event.asStartElement().getNamespaceContext(); + } + if (redirectWriter == null) { + return true; + } + if (eventType == XMLStreamConstants.START_ELEMENT) { + if (depth >= 0 || triggersRedirect(event.asStartElement().getName())) { + depth++; + } + } else if (eventType == XMLStreamConstants.END_ELEMENT) { + if (depth >= 0 && --depth < 0) { + // redirect the end element of the trigger, + // but do not redirect the end element of the calling type + if (redirectTriggers != null) { + redirectEvent(event); + return false; } - return true; // depth < 0; + } + } + if (depth >= 0) { //|| (depth == 0 && redirectTriggers == null)) { + redirectEvent(event); + return false; + } + return true; // depth < 0; // switch (event.getEventType()) { // case XMLStreamConstants.START_ELEMENT: @@ -132,128 +137,130 @@ public class RedirectEventFilter implements EventFilter { // return false; // } // return true; // depth < 0; - } + } - /** - * @param startElt - * @return true if the set of triggers contains startElement - * (or no triggers are registered, i.e. everything is redirected) - */ - private boolean triggersRedirect(QName startElement) { - if (redirectTriggers != null) { - return redirectTriggers.contains(startElement); - } - return true; + /** + * @param startElt + * @return true if the set of triggers contains startElement + * (or no triggers are registered, i.e. everything is redirected) + */ + private boolean triggersRedirect(QName startElement) { + if (redirectTriggers != null) { + return redirectTriggers.contains(startElement); } + return true; + } - private void redirectEvent(XMLEvent event) { - try { - if (log.isTraceEnabled()) { - log.trace("redirecting StAX event " + event); - } - redirectWriter.add(event); - } catch (XMLStreamException ex) { - ex.printStackTrace(); - } + private void redirectEvent(XMLEvent event) { + try { + if (log.isTraceEnabled()) { + log.trace("redirecting StAX event " + event); + } + redirectWriter.add(event); + } catch (XMLStreamException ex) { + ex.printStackTrace(); } + } - /** - * Enable/disable redirection of all events from now on. - * The redirected events will be UTF-8 encoded and written to the stream. - * - * @param redirectstream - * if null, redirection is disabled - */ - public void setRedirectStream(OutputStream redirectStream) throws XMLStreamException { - setRedirectStream(redirectStream, DEFAULT_ENCODING, null); - } + /** + * Enable/disable redirection of all events from now on. + * The redirected events will be UTF-8 encoded and written to the stream. + * + * @param redirectstream + * if null, redirection is disabled + */ + public void setRedirectStream(OutputStream redirectStream) throws XMLStreamException { + setRedirectStream(redirectStream, DEFAULT_ENCODING, null); + } - /** - * Enable/disable redirection of all events from now on. - * - * @param redirectStream if null, redirection is disabled - * @param encoding The encoding for the redirect stream - * @throws javax.xml.stream.XMLStreamException - */ - public void setRedirectStream(OutputStream redirectStream, String encoding) throws XMLStreamException { - setRedirectStream(redirectStream, encoding, null); - } + /** + * Enable/disable redirection of all events from now on. + * + * @param redirectStream if null, redirection is disabled + * @param encoding The encoding for the redirect stream + * @throws javax.xml.stream.XMLStreamException + */ + public void setRedirectStream(OutputStream redirectStream, String encoding) throws XMLStreamException { + setRedirectStream(redirectStream, encoding, null); + } - /** - * Enable/disable redirection of all (child) elements contained in redirect triggers. - * The redirected events will be UTF-8 encoded and written to the stream. - * - * @param redirectstream - * if null, redirection is disabled - * @param redirectTriggers elements that trigger the redirection - */ - public void setRedirectStream(OutputStream redirectStream, Set redirectTriggers) throws XMLStreamException { - setRedirectStream(redirectStream, DEFAULT_ENCODING, redirectTriggers); - } + /** + * Enable/disable redirection of all (child) elements contained in redirect triggers. + * The redirected events will be UTF-8 encoded and written to the stream. + * + * @param redirectstream + * if null, redirection is disabled + * @param redirectTriggers elements that trigger the redirection + */ + public void setRedirectStream(OutputStream redirectStream, Set redirectTriggers) throws XMLStreamException { + setRedirectStream(redirectStream, DEFAULT_ENCODING, redirectTriggers); + } - /** - * Enable/disable redirection of all (child) elements contained in redirect triggers. - * - * @param redirectstream - * if null, redirection is disabled - * @param encoding The encoding for the redirect stream - * @param redirectTriggers elements that trigger the redirection - */ - public void setRedirectStream(OutputStream redirectStream, String encoding, Set redirectTriggers) throws XMLStreamException { - if (redirectStream != null) { - XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); - if (encoding == null) { - encoding = DEFAULT_ENCODING; - } - redirectWriter = outputFactory.createXMLEventWriter(redirectStream, + /** + * Enable/disable redirection of all (child) elements contained in redirect triggers. + * + * TODO: don't set redirect stream from caller (caller does not know whether redirection will be triggered) + * rather create on trigger and pass to caller + * @param redirectstream + * if null, redirection is disabled + * @param encoding The encoding for the redirect stream + * @param redirectTriggers elements that trigger the redirection + */ + public void setRedirectStream(OutputStream redirectStream, String encoding, Set redirectTriggers) throws XMLStreamException { + if (redirectStream != null) { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + if (encoding == null) { + encoding = DEFAULT_ENCODING; + } + redirectWriter = outputFactory.createXMLEventWriter(redirectStream, encoding); - if (redirectTriggers == null) { - // start redirecting - depth = 0; - } - this.redirectTriggers = redirectTriggers; - } else { - redirectWriter = null; - this.redirectTriggers = null; - } + if (redirectTriggers == null) { + // start redirecting + depth = 0; + } + this.redirectTriggers = redirectTriggers; + } else { + redirectWriter = null; + this.redirectTriggers = null; } + } - /** - * Enable/disable redirection of fragments (defined by elements in - * redirectTriggers) - * - * @param redirectStream - * if null, redirection is disabled - * @param redirectTriggers - * All startElement events occuring in this list will trigger - * redirection of the entire fragment. If null, all events are - * redirected - */ - // public void setRedirectStream(OutputStream redirectStream, List - // redirectTriggers) throws XMLStreamException { - // if (redirectStream != null) { - // XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); - // redirectWriter = outputFactory.createXMLEventWriter(redirectStream); - // } else { - // redirectWriter = null; - // } - // this.redirectTriggers = (redirectStream == null) ? null : redirectTriggers; - // } - /** - * flushes the internal EventWriter - * - * @throws javax.xml.stream.XMLStreamException - */ - public void flushRedirectStream() throws XMLStreamException { - redirectWriter.flush(); - } + /** + * Enable/disable redirection of fragments (defined by elements in + * redirectTriggers) + * + * @param redirectStream + * if null, redirection is disabled + * @param redirectTriggers + * All startElement events occuring in this list will trigger + * redirection of the entire fragment. If null, all events are + * redirected + */ + // public void setRedirectStream(OutputStream redirectStream, List + // redirectTriggers) throws XMLStreamException { + // if (redirectStream != null) { + // XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + // redirectWriter = outputFactory.createXMLEventWriter(redirectStream); + // } else { + // redirectWriter = null; + // } + // this.redirectTriggers = (redirectStream == null) ? null : redirectTriggers; + // } + /** + * flushes the internal EventWriter + * + * @throws javax.xml.stream.XMLStreamException + */ + public void flushRedirectStream() throws XMLStreamException { + redirectWriter.flush(); + } - /** - * the namespaceContext of the last startelement event read - * - * @return - */ - public NamespaceContext getCurrentNamespaceContext() { - return currentNamespaceContext; - } + /** + * the namespaceContext of the last startelement event read + * + * @return + */ + public NamespaceContext getCurrentNamespaceContext() { + return currentNamespaceContext; + } } diff --git a/utils/src/main/java/at/gv/egiz/slbinding/impl/TransformsInfoType.java b/utils/src/main/java/at/gv/egiz/slbinding/impl/TransformsInfoType.java index b4e988f0..1180e9fa 100644 --- a/utils/src/main/java/at/gv/egiz/slbinding/impl/TransformsInfoType.java +++ b/utils/src/main/java/at/gv/egiz/slbinding/impl/TransformsInfoType.java @@ -25,6 +25,7 @@ import java.io.ByteArrayOutputStream; import java.util.HashSet; import java.util.Set; import javax.xml.bind.annotation.XmlTransient; +import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; import org.apache.commons.logging.Log; diff --git a/utils/src/main/java/at/gv/egiz/slbinding/impl/XMLContentType.java b/utils/src/main/java/at/gv/egiz/slbinding/impl/XMLContentType.java index c32542aa..eb147f88 100644 --- a/utils/src/main/java/at/gv/egiz/slbinding/impl/XMLContentType.java +++ b/utils/src/main/java/at/gv/egiz/slbinding/impl/XMLContentType.java @@ -35,7 +35,7 @@ import org.apache.commons.logging.LogFactory; public class XMLContentType extends at.buergerkarte.namespaces.securitylayer._1.XMLContentType implements RedirectCallback { @XmlTransient - private static Log log = LogFactory.getLog(TransformsInfoType.class); + private static Log log = LogFactory.getLog(XMLContentType.class); @XmlTransient protected ByteArrayOutputStream redirectOS = null; diff --git a/utils/src/main/java/org/w3/_2000/_09/xmldsig_/ObjectFactory.java b/utils/src/main/java/org/w3/_2000/_09/xmldsig_/ObjectFactory.java index 4ab376f1..fae77451 100644 --- a/utils/src/main/java/org/w3/_2000/_09/xmldsig_/ObjectFactory.java +++ b/utils/src/main/java/org/w3/_2000/_09/xmldsig_/ObjectFactory.java @@ -167,6 +167,7 @@ public class ObjectFactory { * */ public TransformType createTransformType() { +// return new at.gv.egiz.slbinding.impl.TransformType(); return new TransformType(); } diff --git a/utils/src/main/java/org/w3/_2000/_09/xmldsig_/TransformsType.java b/utils/src/main/java/org/w3/_2000/_09/xmldsig_/TransformsType.java index 584baf80..c7044c4c 100644 --- a/utils/src/main/java/org/w3/_2000/_09/xmldsig_/TransformsType.java +++ b/utils/src/main/java/org/w3/_2000/_09/xmldsig_/TransformsType.java @@ -57,7 +57,7 @@ import javax.xml.bind.annotation.XmlType; }) public class TransformsType { - @XmlElement(name = "Transform", required = true) + @XmlElement(name = "Transform", required = true) //, type=at.gv.egiz.slbinding.impl.TransformType.class) protected List transform; /** diff --git a/utils/src/test/java/at/gv/egiz/slbinding/RedirectTest.java b/utils/src/test/java/at/gv/egiz/slbinding/RedirectTest.java index 99d353ac..7c8c206a 100644 --- a/utils/src/test/java/at/gv/egiz/slbinding/RedirectTest.java +++ b/utils/src/test/java/at/gv/egiz/slbinding/RedirectTest.java @@ -52,6 +52,8 @@ import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import static org.junit.Assert.*; +import org.w3._2000._09.xmldsig_.TransformType; +import org.w3._2000._09.xmldsig_.TransformsType; /** * @@ -131,11 +133,34 @@ public class RedirectTest { Iterator tiIt = transformsInfos.iterator(); while (tiIt.hasNext()) { at.gv.egiz.slbinding.impl.TransformsInfoType ti = (at.gv.egiz.slbinding.impl.TransformsInfoType) tiIt.next(); +// TransformsInfoType ti = tiIt.next(); assertNotNull(ti); - System.out.println("found at.gv.egiz.slbinding.impl.TransformsInfoType TransformsInfo"); + System.out.println("found sl:TransformsInfo: " + ti.getClass().getName()); //at.gv.egiz.slbinding.impl.TransformsInfoType TransformsInfo"); +// TransformsType ts = ti.getTransforms(); +// assertNotNull(ts); +// System.out.println("found dsig:Transforms " + ts.getClass().getName()); //org.w3._2000._09.xmldsig_.TransformsType dsig:Transforms"); +// List tL = ts.getTransform(); +// assertNotNull(tL); +// System.out.println("found " + tL.size() + " org.w3._2000._09.xmldsig_.TransformType dsig:Transform"); +// for (TransformType t : tL) { +// if (t instanceof at.gv.egiz.slbinding.impl.TransformType) { +// System.out.println("found at.gv.egiz.slbinding.impl.TransformType"); +// byte[] redirectedBytes = ((at.gv.egiz.slbinding.impl.TransformType) t).getRedirectedStream().toByteArray(); +// if (redirectedBytes != null && redirectedBytes.length > 0) { +// System.out.println("reading redirected stream..."); +// os.write("--- redirected Transform ---".getBytes()); +// os.write(redirectedBytes); +// os.write("\n".getBytes()); +// } else { +// System.out.println("no redirected stream"); +// } +// } +// } + ByteArrayOutputStream dsigTransforms = ti.getRedirectedStream(); + os.write("--- redirected TransformsInfo content ---".getBytes()); os.write(dsigTransforms.toByteArray()); - os.write("\n".getBytes()); + os.write("\n---".getBytes()); MetaInfoType mi = ti.getFinalDataMetaInfo(); assertNotNull(mi); diff --git a/utils/src/test/requests/CreateXMLSignatureRequest02.xml_redirect.txt b/utils/src/test/requests/CreateXMLSignatureRequest02.xml_redirect.txt index 31be50b7..fc0e4f14 100644 --- a/utils/src/test/requests/CreateXMLSignatureRequest02.xml_redirect.txt +++ b/utils/src/test/requests/CreateXMLSignatureRequest02.xml_redirect.txt @@ -1,4 +1,4 @@ - +--- redirected TransformsInfo content --- @@ -82,7 +82,7 @@ - +------ redirected TransformsInfo content --- @@ -162,3 +162,4 @@ +--- \ No newline at end of file -- cgit v1.2.3 From bd070e82c276afb8c1c3a9ddc3b5712783760881 Mon Sep 17 00:00:00 2001 From: mcentner Date: Tue, 29 Sep 2009 17:36:06 +0000 Subject: Logging issues fixed: - Added possibility to configure logging of BKUWebstart. Logging is now configured from log4j configuration deployed with BKUWebstart in a first step. In a second step the webstart launcher looks for a log4j configuration file in the user's mooca configuration directory and updates the log4j configuration. - Logging of IAIK PKI properly initialized. IAIK PKI does not mess with the log4j configuration any longer. - Changed log4j accordingly (an appender is now needed as IAIK PKI does not reconfigure log4j any longer). Added css-stylesheet to ErrorResponses issued by the BKU to improve the presentation to the user. Changed dependencies of BKUWebStart (see Issue#469 https://egovlabs.gv.at/tracker/index.php?func=detail&aid=469&group_id=13&atid=134). DataURLConnection now uses the request encoding of SL < 1.2. application/x-www-form-urlencoded is now used as default encoding method. multipart/form-data is used only if transfer parameters are present in the request that require a Content-Type parameter. This can only be set with multipart/form-data. This is not in conformance with SL 1.2, however it should improve compatibility with applications. Therefore, removed the ability to configure the DataURLConnection implementation class. DataURLConnection now uses a streaming implementation for encoding of application/x-www-form-urlencoded requests. XWWWFormUrlImputDecoder now uses a streaming implementation for decoding of application/x-www-form-urlencoded requests. Fixed Bug in SLResultPart that caused a binary response to be provided as parameter "XMLResponse" in a multipart/form-data encoded request to DataURL. SLCommandFactory now supports unmarshalling of SL < 1.2 requests in order issue meaningful error messages. Therefore, the marshaling context for response marshaling had to be separated from the marshaling context for requests in order to avoid the marshaling of SL < 1.2 namespace prefixes in SL 1.2 responses. Target attribute in QualifiedProperties is now marshaled. (see Issue#470 https://egovlabs.gv.at/tracker/index.php?func=detail&aid=470&group_id=13&atid=134) Reporting of XML validation errors improved. git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@510 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- BKULocal/src/main/resources/log4j.properties | 2 +- BKULocal/src/main/webapp/errorresponse.css | 12 + BKUOnline/src/main/webapp/errorresponse.css | 12 + BKUWebStart/pom.xml | 14 +- .../java/at/gv/egiz/bku/webstart/Configurator.java | 26 +- .../java/at/gv/egiz/bku/webstart/Container.java | 11 +- .../java/at/gv/egiz/bku/webstart/Launcher.java | 22 +- .../gv/egiz/bku/webstart/LogSecurityManager.java | 9 +- .../java/at/gv/egiz/bku/webstart/TLSServerCA.java | 9 +- .../at/gv/egiz/bku/webstart/gui/AboutDialog.java | 7 +- .../bku/webstart/gui/PINManagementInvoker.java | 7 +- BKUWebStart/src/main/resources/log4j.properties | 20 +- .../at/gv/egiz/bku/webstart/ConfiguratorTest.java | 2 - BKUWebStartPackage/pom.xml | 3 +- .../main/java/at/gv/egiz/bku/binding/DataUrl.java | 9 +- .../at/gv/egiz/bku/binding/DataUrlConnection.java | 2 +- .../gv/egiz/bku/binding/DataUrlConnectionImpl.java | 342 ++++++- .../gv/egiz/bku/binding/HTTPBindingProcessor.java | 29 +- .../bku/binding/LegacyDataUrlConnectionImpl.java | 259 ----- .../egiz/bku/binding/XWWWFormUrlInputDecoder.java | 83 +- .../egiz/bku/binding/XWWWFormUrlInputIterator.java | 376 +++++++ .../egiz/bku/binding/multipart/SLResultPart.java | 41 +- .../at/gv/egiz/bku/conf/CertValidatorImpl.java | 24 + .../java/at/gv/egiz/bku/conf/IAIKCommonsLog.java | 144 +++ .../at/gv/egiz/bku/conf/IAIKCommonsLogFactory.java | 59 ++ .../gv/egiz/bku/slcommands/SLCommandFactory.java | 51 +- .../egiz/bku/slcommands/SLMarshallerFactory.java | 172 ++++ .../java/at/gv/egiz/bku/slcommands/SLResult.java | 8 +- .../slcommands/impl/AbstractAssocArrayInfobox.java | 13 +- .../impl/CreateXMLSignatureResultImpl.java | 15 +- .../egiz/bku/slcommands/impl/ErrorResultImpl.java | 6 +- .../bku/slcommands/impl/GetStatusCommandImpl.java | 2 - .../bku/slcommands/impl/GetStatusResultImpl.java | 4 +- .../slcommands/impl/IdentityLinkInfoboxImpl.java | 1 - .../slcommands/impl/InfoboxReadResultFileImpl.java | 15 +- .../bku/slcommands/impl/InfoboxReadResultImpl.java | 4 +- .../slcommands/impl/InfoboxUpdateResultImpl.java | 4 +- .../slcommands/impl/NullOperationResultImpl.java | 4 +- .../gv/egiz/bku/slcommands/impl/SLResultImpl.java | 94 +- .../egiz/bku/slcommands/impl/xsect/DataObject.java | 1 - .../egiz/bku/slcommands/impl/xsect/Signature.java | 18 +- .../egiz/bku/slexceptions/SLExceptionMessages.java | 6 + .../egiz/bku/slexceptions/SLVersionException.java | 28 + .../egiz/bku/slcommands/schema/Core.20020225.xsd | 33 + .../egiz/bku/slcommands/schema/Core.20020831.xsd | 10 + .../slexceptions/SLExceptionMessages.properties | 7 +- .../slexceptions/SLExceptionMessages_en.properties | 4 + .../bku/binding/XWWWFormUrlInputIteratorTest.java | 152 +++ .../egiz/bku/slcommands/SLCommandFactoryTest.java | 7 +- .../impl/CreateXMLSignatureComandImplTest.java | 9 +- .../bku/slcommands/impl/ErrorResultImplTest.java | 2 +- .../slcommands/impl/InfoboxReadComandImplTest.java | 9 +- .../impl/NullOperationResultImplTest.java | 2 +- .../impl/SVPersonendatenInfoboxImplTest.java | 15 +- .../securitylayer/_1/TransformsInfoType.java | 21 +- .../_20020225_/ErrorResponseType.java | 98 ++ .../securitylayer/_20020225_/ObjectFactory.java | 280 ++++++ .../securitylayer/_20020225_/package-info.java | 9 + .../securitylayer/_20020831_/ObjectFactory.java | 112 +++ .../gv/egiz/bku/utils/URLEncodingInputStream.java | 62 ++ .../gv/egiz/bku/utils/URLEncodingOutputStream.java | 134 +++ .../at/gv/egiz/bku/utils/URLEncodingWriter.java | 57 ++ .../java/at/gv/egiz/marshal/MarshallerFactory.java | 12 +- .../java/at/gv/egiz/marshal/NamespacePrefix.java | 34 - .../gv/egiz/marshal/NamespacePrefixMapperImpl.java | 54 +- .../ReportingValidationEventHandler.java | 64 ++ .../gv/egiz/validation/ValidationEventLogger.java | 55 - .../gv/egiz/xades/QualifyingPropertiesFactory.java | 8 +- .../bku/utils/URLEncodingOutputStreamTest.java | 147 +++ utils/src/test/resources/BigRequest.xml | 1060 ++++++++++++++++++++ 70 files changed, 3704 insertions(+), 723 deletions(-) create mode 100644 BKULocal/src/main/webapp/errorresponse.css create mode 100644 BKUOnline/src/main/webapp/errorresponse.css delete mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/binding/LegacyDataUrlConnectionImpl.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/binding/XWWWFormUrlInputIterator.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/conf/IAIKCommonsLog.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/conf/IAIKCommonsLogFactory.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLMarshallerFactory.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLVersionException.java create mode 100644 bkucommon/src/main/resources/at/gv/egiz/bku/slcommands/schema/Core.20020225.xsd create mode 100644 bkucommon/src/main/resources/at/gv/egiz/bku/slcommands/schema/Core.20020831.xsd create mode 100644 bkucommon/src/test/java/at/gv/egiz/bku/binding/XWWWFormUrlInputIteratorTest.java create mode 100644 utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020225_/ErrorResponseType.java create mode 100644 utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020225_/ObjectFactory.java create mode 100644 utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020225_/package-info.java create mode 100644 utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020831_/ObjectFactory.java create mode 100644 utils/src/main/java/at/gv/egiz/bku/utils/URLEncodingInputStream.java create mode 100644 utils/src/main/java/at/gv/egiz/bku/utils/URLEncodingOutputStream.java create mode 100644 utils/src/main/java/at/gv/egiz/bku/utils/URLEncodingWriter.java delete mode 100644 utils/src/main/java/at/gv/egiz/marshal/NamespacePrefix.java create mode 100644 utils/src/main/java/at/gv/egiz/validation/ReportingValidationEventHandler.java delete mode 100644 utils/src/main/java/at/gv/egiz/validation/ValidationEventLogger.java create mode 100644 utils/src/test/java/at/gv/egiz/bku/utils/URLEncodingOutputStreamTest.java create mode 100644 utils/src/test/resources/BigRequest.xml (limited to 'bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java') diff --git a/BKULocal/src/main/resources/log4j.properties b/BKULocal/src/main/resources/log4j.properties index 8dc8644c..86ddc7b4 100644 --- a/BKULocal/src/main/resources/log4j.properties +++ b/BKULocal/src/main/resources/log4j.properties @@ -15,7 +15,7 @@ # assume log4j to be configured by servlet container (java web start) # loglever DEBUG, appender STDOUT -#log4j.rootLogger=DEBUG, STDOUT +log4j.rootLogger=DEBUG, STDOUT # STDOUT appender log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender diff --git a/BKULocal/src/main/webapp/errorresponse.css b/BKULocal/src/main/webapp/errorresponse.css new file mode 100644 index 00000000..41402e71 --- /dev/null +++ b/BKULocal/src/main/webapp/errorresponse.css @@ -0,0 +1,12 @@ +@CHARSET "UTF-8"; +sl\:ErrorResponse {margin: 0.5em; display: block;} +sl\:ErrorCode {display: inline;} +sl\:Info {display: inline;} + +ErrorResponse:lang(de):before {content: "Bei der Verarbeitung der Anfrage durch die Bürgerkartenumgebung ist ein Fehler aufgetreten: "; font-weight: bolder;} +ErrorResponse:before {content: "An error has occoured upon request processing by the citizen card software: "; font-weight: bold;} +ErrorResponse {margin: 0.5em; display: block;} +ErrorCode:lang(de):before {content: "Fehler-Code: ";} +ErrorCode:before {content: "Error Code: ";} +ErrorCode {display: block;} +Info {display: block;} \ No newline at end of file diff --git a/BKUOnline/src/main/webapp/errorresponse.css b/BKUOnline/src/main/webapp/errorresponse.css new file mode 100644 index 00000000..41402e71 --- /dev/null +++ b/BKUOnline/src/main/webapp/errorresponse.css @@ -0,0 +1,12 @@ +@CHARSET "UTF-8"; +sl\:ErrorResponse {margin: 0.5em; display: block;} +sl\:ErrorCode {display: inline;} +sl\:Info {display: inline;} + +ErrorResponse:lang(de):before {content: "Bei der Verarbeitung der Anfrage durch die Bürgerkartenumgebung ist ein Fehler aufgetreten: "; font-weight: bolder;} +ErrorResponse:before {content: "An error has occoured upon request processing by the citizen card software: "; font-weight: bold;} +ErrorResponse {margin: 0.5em; display: block;} +ErrorCode:lang(de):before {content: "Fehler-Code: ";} +ErrorCode:before {content: "Error Code: ";} +ErrorCode {display: block;} +Info {display: block;} \ No newline at end of file diff --git a/BKUWebStart/pom.xml b/BKUWebStart/pom.xml index ca19a0b3..f51f1332 100644 --- a/BKUWebStart/pom.xml +++ b/BKUWebStart/pom.xml @@ -172,6 +172,12 @@ BKUCertificates 1.0 + + iaik + iaik_jce_full_signed + compile + + + @@ -215,6 +222,11 @@ slf4j-log4j12 1.5.8 + + log4j + log4j + compile + diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Configurator.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Configurator.java index 923a70d9..d8fe3e70 100644 --- a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Configurator.java +++ b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Configurator.java @@ -16,8 +16,9 @@ */ package at.gv.egiz.bku.webstart; -import at.gv.egiz.bku.utils.StreamUtil; import iaik.asn1.CodingException; +import iaik.utils.StreamCopier; + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; @@ -42,8 +43,10 @@ import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; + +import org.apache.log4j.PropertyConfigurator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -71,7 +74,7 @@ public class Configurator { public static final String KEYSTORE_FILE = "keystore.ks"; public static final String PASSWD_FILE = ".secret"; - private static final Log log = LogFactory.getLog(Configurator.class); + private static final Logger log = LoggerFactory.getLogger(Configurator.class); /** currently installed configuration version */ private String version; @@ -110,6 +113,11 @@ public class Configurator { } else { initConfig(configDir); } + // re-configure logging + // TODO: move to appropriate place + String log4jconfig = configDir.getPath() + File.separatorChar + "log4j.properties"; + log.debug("Reconfiguring logging with " + log4jconfig); + PropertyConfigurator.configureAndWatch(log4jconfig); } /** @@ -312,7 +320,7 @@ public class Configurator { ZipEntry entry = new ZipEntry(relativePath.toString()); zip.putNextEntry(entry); BufferedInputStream entryIS = new BufferedInputStream(new FileInputStream(dir)); - StreamUtil.copyStream(entryIS, zip); + new StreamCopier(entryIS, zip).copyStream(); entryIS.close(); zip.closeEntry(); dir.delete(); @@ -341,7 +349,7 @@ public class Configurator { File confTemplateFile = new File(configDir, CONF_TEMPLATE_FILE); InputStream is = Configurator.class.getClassLoader().getResourceAsStream(CONF_TEMPLATE_RESOURCE); OutputStream os = new BufferedOutputStream(new FileOutputStream(confTemplateFile)); - StreamUtil.copyStream(is, os); + new StreamCopier(is, os).copyStream(); os.close(); unzip(confTemplateFile, configDir); confTemplateFile.delete(); @@ -374,7 +382,7 @@ public class Configurator { new File(certsDir, f.substring(0, f.lastIndexOf('/'))).mkdirs(); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(certsDir, f))); log.debug(f); - StreamUtil.copyStream(Configurator.class.getClassLoader().getResourceAsStream(entry), bos); + new StreamCopier(Configurator.class.getClassLoader().getResourceAsStream(entry), bos).copyStream(); bos.close(); } else { log.trace("ignore " + entry); @@ -399,8 +407,8 @@ public class Configurator { } File f = new File(eF.getParent()); f.mkdirs(); - StreamUtil.copyStream(zipFile.getInputStream(entry), - new FileOutputStream(eF)); + new StreamCopier(zipFile.getInputStream(entry), + new FileOutputStream(eF)).copyStream(); } zipFile.close(); } diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Container.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Container.java index 2feae267..4d1fe658 100644 --- a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Container.java +++ b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Container.java @@ -1,6 +1,7 @@ package at.gv.egiz.bku.webstart; -import at.gv.egiz.bku.utils.StreamUtil; +import iaik.utils.StreamCopier; + import java.awt.AWTPermission; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -24,20 +25,20 @@ import java.security.SecurityPermission; import java.security.cert.Certificate; import java.util.PropertyPermission; import javax.smartcardio.CardPermission; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.mortbay.jetty.Connector; import org.mortbay.jetty.Server; import org.mortbay.jetty.nio.SelectChannelConnector; import org.mortbay.jetty.security.SslSocketConnector; import org.mortbay.jetty.webapp.WebAppContext; import org.mortbay.thread.QueuedThreadPool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Container { public static final String HTTP_PORT_PROPERTY = "mocca.http.port"; public static final String HTTPS_PORT_PROPERTY = "mocca.http.port"; - private static Log log = LogFactory.getLog(Container.class); + private static Logger log = LoggerFactory.getLogger(Container.class); static { if (log.isDebugEnabled()) { @@ -166,7 +167,7 @@ public class Container { log.debug("copying BKULocal classpath resource to " + webapp); InputStream is = getClass().getClassLoader().getResourceAsStream("BKULocal.war"); OutputStream os = new BufferedOutputStream(new FileOutputStream(webapp)); - StreamUtil.copyStream(is, os); + new StreamCopier(is, os).copyStream(); os.close(); return webapp.getPath(); } diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Launcher.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Launcher.java index 2bf42ccb..ef7edef1 100644 --- a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Launcher.java +++ b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Launcher.java @@ -10,8 +10,6 @@ import java.util.Locale; import java.util.ResourceBundle; import javax.jnlp.UnavailableServiceException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import com.sun.javaws.security.JavaWebStartSecurity; import java.awt.AWTException; @@ -37,6 +35,8 @@ import javax.jnlp.BasicService; import javax.jnlp.ServiceManager; import javax.swing.JFrame; import org.mortbay.util.MultiException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Launcher implements BKUControllerInterface, ActionListener { public static final String HELP_COMMAND = "help"; @@ -71,9 +71,10 @@ public class Launcher implements BKUControllerInterface, ActionListener { public static final String SHUTDOWN_COMMAND = "shutdown"; public static final String PIN_COMMAND = "pin"; public static final String ABOUT_COMMAND = "about"; + + private static Logger log = LoggerFactory.getLogger(Launcher.class); - private static Log log = LogFactory.getLog(Launcher.class); - + /** local bku uri */ public static final URL HTTP_SECURITY_LAYER_URL; public static final URL HTTPS_SECURITY_LAYER_URL; @@ -93,7 +94,7 @@ public class Launcher implements BKUControllerInterface, ActionListener { cert = new URL(http, "/installCertificate"); help = new URL(http, "/help"); } catch (MalformedURLException ex) { - log.error(ex); + log.error("Failed to create URL.", ex); } finally { HTTP_SECURITY_LAYER_URL = http; HTTPS_SECURITY_LAYER_URL = https; @@ -132,6 +133,7 @@ public class Launcher implements BKUControllerInterface, ActionListener { public Launcher() { + log.info("Initializing Launcher"); if (log.isTraceEnabled()) { SecurityManager sm = System.getSecurityManager(); if (sm instanceof JavaWebStartSecurity) { @@ -147,7 +149,7 @@ public class Launcher implements BKUControllerInterface, ActionListener { try { initConfig(); } catch (Exception ex) { - log.fatal("Failed to initialize configuration", ex); + log.error("Failed to initialize configuration", ex); trayIcon.displayMessage(messages.getString(CAPTION_ERROR), messages.getString(ERROR_CONFIG), TrayIcon.MessageType.ERROR); throw ex; @@ -156,12 +158,12 @@ public class Launcher implements BKUControllerInterface, ActionListener { startServer(); initFinished(); } catch (BindException ex) { - log.fatal("Failed to launch server, " + ex.getMessage(), ex); + log.error("Failed to launch server, " + ex.getMessage(), ex); trayIcon.displayMessage(messages.getString(CAPTION_ERROR), messages.getString(ERROR_BIND), TrayIcon.MessageType.ERROR); throw ex; } catch (MultiException ex) { - log.fatal("Failed to launch server, " + ex.getMessage(), ex); + log.error("Failed to launch server, " + ex.getMessage(), ex); if (ex.getThrowable(0) instanceof BindException) { trayIcon.displayMessage(messages.getString(CAPTION_ERROR), messages.getString(ERROR_BIND), TrayIcon.MessageType.ERROR); @@ -172,7 +174,7 @@ public class Launcher implements BKUControllerInterface, ActionListener { throw ex; } catch (Exception ex) { ex.printStackTrace(); - log.fatal("Failed to launch server, " + ex.getMessage(), ex); + log.error("Failed to launch server, " + ex.getMessage(), ex); trayIcon.displayMessage(messages.getString(CAPTION_ERROR), messages.getString(ERROR_START), TrayIcon.MessageType.ERROR); throw ex; @@ -379,7 +381,7 @@ public class Launcher implements BKUControllerInterface, ActionListener { launcher.launch(); } catch (Exception ex) { ex.printStackTrace(); - log.debug(ex); + log.debug("Caught exception " + ex.getMessage(), ex); log.info("waiting to shutdown..."); Thread.sleep(5000); log.info("exit"); diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/LogSecurityManager.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/LogSecurityManager.java index 99fd403b..d589812e 100644 --- a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/LogSecurityManager.java +++ b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/LogSecurityManager.java @@ -20,8 +20,9 @@ import com.sun.javaws.security.JavaWebStartSecurity; import java.io.FileDescriptor; import java.net.InetAddress; import java.security.Permission; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * JVM argument -Djava.security.debug=access,failure @@ -31,7 +32,7 @@ import org.apache.commons.logging.LogFactory; */ public class LogSecurityManager extends SecurityManager { - protected static final Log log = LogFactory.getLog(LogSecurityManager.class); + protected static final Logger log = LoggerFactory.getLogger(LogSecurityManager.class); JavaWebStartSecurity sm; public LogSecurityManager(JavaWebStartSecurity sm) { @@ -182,6 +183,7 @@ public class LogSecurityManager extends SecurityManager { } } + @SuppressWarnings("deprecation") @Override public void checkMulticast(InetAddress maddr, byte ttl) { try { @@ -399,6 +401,7 @@ public class LogSecurityManager extends SecurityManager { // protected Class[] getClassContext() { // log.info("getClassContext"); return sm.getClassContext(); // } + @SuppressWarnings("deprecation") @Override public boolean getInCheck() { log.info("getInCheck"); diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/TLSServerCA.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/TLSServerCA.java index 08a06570..745042f8 100644 --- a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/TLSServerCA.java +++ b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/TLSServerCA.java @@ -16,8 +16,6 @@ import iaik.x509.extensions.SubjectAltName; import iaik.x509.extensions.SubjectKeyIdentifier; import java.io.IOException; import java.math.BigInteger; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -27,14 +25,15 @@ import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Random; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class TLSServerCA { public static final int CA_VALIDITY_Y = 3; public static final String MOCCA_TLS_SERVER_ALIAS = "server"; public static final int SERVER_VALIDITY_Y = 3; - private final static Log log = LogFactory.getLog(TLSServerCA.class); + private final static Logger log = LoggerFactory.getLogger(TLSServerCA.class); private KeyPair caKeyPair; private X509Certificate caCert; diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/gui/AboutDialog.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/gui/AboutDialog.java index 1e35af58..ba2c007d 100644 --- a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/gui/AboutDialog.java +++ b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/gui/AboutDialog.java @@ -11,7 +11,6 @@ package at.gv.egiz.bku.webstart.gui; -import java.text.Format; import java.text.MessageFormat; import java.util.ResourceBundle; @@ -21,6 +20,11 @@ import java.util.ResourceBundle; */ public class AboutDialog extends javax.swing.JDialog { + /** + * + */ + private static final long serialVersionUID = 1L; + /** Creates new form AboutDialog */ public AboutDialog(java.awt.Frame parent, boolean modal, String version) { super(parent, modal); @@ -33,7 +37,6 @@ public class AboutDialog extends javax.swing.JDialog { * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ - @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/gui/PINManagementInvoker.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/gui/PINManagementInvoker.java index 55e26313..1f14d751 100644 --- a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/gui/PINManagementInvoker.java +++ b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/gui/PINManagementInvoker.java @@ -21,8 +21,9 @@ import java.awt.TrayIcon; import java.io.IOException; import java.net.HttpURLConnection; import java.util.ResourceBundle; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * GUI is painted using SwingUtilities.invokeLater, but TrayIcon ActionListener Thread (== webstart thread) joined Jetty Thread @@ -31,7 +32,7 @@ import org.apache.commons.logging.LogFactory; */ public class PINManagementInvoker implements Runnable { - private static final Log log = LogFactory.getLog(PINManagementInvoker.class); + private static final Logger log = LoggerFactory.getLogger(PINManagementInvoker.class); TrayIcon trayIcon; ResourceBundle messages; diff --git a/BKUWebStart/src/main/resources/log4j.properties b/BKUWebStart/src/main/resources/log4j.properties index 76562ccf..81832418 100644 --- a/BKUWebStart/src/main/resources/log4j.properties +++ b/BKUWebStart/src/main/resources/log4j.properties @@ -13,23 +13,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -# loglever DEBUG, appender STDOUT -log4j.rootLogger=DEBUG, file -log4j.logger.org.mortbay.log=INFO -log4j.logger.pki=INFO - -#log4j.additivity.pki=false +# root log level INFO, appender file +log4j.rootLogger=INFO, file -# STDOUT appender -log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender -log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout -#log4j.appender.STDOUT.layout.ConversionPattern=%5p | %d{dd HH:mm:ss,SSS} | %20c | %10t | %m%n -#log4j.appender.STDOUT.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n -log4j.appender.STDOUT.layout.ConversionPattern=%-5p |%d | %t | %c %x- %m%n +# jetty's log level +log4j.logger.org.mortbay.log=INFO -### FILE appender +# file appender log4j.appender.file=org.apache.log4j.DailyRollingFileAppender log4j.appender.file.datePattern='.'yyyy-MM-dd log4j.appender.file.File=${user.home}/.mocca/logs/webstart.log log4j.appender.file.layout=org.apache.log4j.PatternLayout -log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %-5p %c{1}:%L - %m%n \ No newline at end of file +log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %-5p %c{2} - %m%n \ No newline at end of file diff --git a/BKUWebStart/src/test/java/at/gv/egiz/bku/webstart/ConfiguratorTest.java b/BKUWebStart/src/test/java/at/gv/egiz/bku/webstart/ConfiguratorTest.java index 0ea126cb..4f5798d5 100644 --- a/BKUWebStart/src/test/java/at/gv/egiz/bku/webstart/ConfiguratorTest.java +++ b/BKUWebStart/src/test/java/at/gv/egiz/bku/webstart/ConfiguratorTest.java @@ -8,8 +8,6 @@ package at.gv.egiz.bku.webstart; import java.io.File; import java.net.URI; import java.util.zip.ZipOutputStream; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; diff --git a/BKUWebStartPackage/pom.xml b/BKUWebStartPackage/pom.xml index 63725fc3..0b226785 100644 --- a/BKUWebStartPackage/pom.xml +++ b/BKUWebStartPackage/pom.xml @@ -1,3 +1,4 @@ + 4.0.0 @@ -22,7 +23,7 @@ process-resources - jnlp-download-servlet + jnlp-single diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrl.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrl.java index 1db8c836..d3945253 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrl.java @@ -16,7 +16,6 @@ */ package at.gv.egiz.bku.binding; -import at.gv.egiz.bku.conf.Configuration; import at.gv.egiz.bku.conf.Configurator; import java.net.MalformedURLException; import java.net.URL; @@ -89,13 +88,7 @@ public class DataUrl { if (configuration != null) { String className = configuration.getProperty(Configurator.DATAURLCONNECTION_CONFIG_P); if (className != null) { - try { - log.info("set DataURLConnection class: " + className); - Class c = Class.forName(className); - connection = (DataUrlConnectionSPI) c.newInstance(); - } catch (Exception ex) { - log.error("failed to instantiate DataURL connection " + className, ex); - } + log.warn("Set DataURLConnection class not supported!"); } } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnection.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnection.java index f954a017..384cf71c 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnection.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnection.java @@ -62,7 +62,7 @@ public interface DataUrlConnection { * @param transferEncoding may be null */ public void setHTTPFormParameter(String name, InputStream data, String contentType, String charSet, String transferEncoding); - + /** * @pre httpHeaders != null * @throws java.net.SocketTimeoutException diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionImpl.java index 4f2d2e00..b092ba41 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionImpl.java @@ -18,10 +18,14 @@ package at.gv.egiz.bku.binding; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.SocketTimeoutException; import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.Charset; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.HashMap; @@ -34,6 +38,7 @@ import java.util.Set; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSocketFactory; +import javax.xml.transform.stream.StreamResult; import org.apache.commons.httpclient.methods.multipart.FilePart; import org.apache.commons.httpclient.methods.multipart.Part; @@ -47,32 +52,92 @@ import at.gv.egiz.bku.conf.Configurator; import at.gv.egiz.bku.slcommands.SLResult; import at.gv.egiz.bku.slcommands.SLResult.SLResultType; import at.gv.egiz.bku.slexceptions.SLRuntimeException; +import at.gv.egiz.bku.utils.URLEncodingWriter; import at.gv.egiz.bku.utils.binding.Protocol; /** - * not thread-safe thus newInsance always returns a new object + * An implementation of the DataUrlConnectionSPI that supports + * multipart/form-data encoding and + * application/x-www-form-urlencoded for compatibility with legacy + * systems. * */ public class DataUrlConnectionImpl implements DataUrlConnectionSPI { private final static Log log = LogFactory.getLog(DataUrlConnectionImpl.class); + + public static final byte[] B_DEFAULT_RESPONSETYPE = DEFAULT_RESPONSETYPE.getBytes(Charset.forName("UTF-8")); + /** + * Supported protocols are HTTP and HTTPS. + */ public final static Protocol[] SUPPORTED_PROTOCOLS = { Protocol.HTTP, Protocol.HTTPS }; + /** + * The X509 certificate of the DataURL server. + */ protected X509Certificate serverCertificate; + + /** + * The protocol of the DataURL. + */ protected Protocol protocol; + + /** + * Use application/x-www-form-urlencoded instead of + * standard conform application/x-www-form-urlencoded. + */ + protected boolean urlEncoded = true; + + /** + * The value of the DataURL. + */ protected URL url; + + /** + * The URLConnection used for communication with the DataURL server. + */ private HttpURLConnection connection; + + /** + * The HTTP request headers. + */ protected Map requestHttpHeaders; - protected ArrayList formParams; + + /** + * The HTTP form parameters. + */ + protected ArrayList httpFormParameter; + + /** + * The boundary for multipart/form-data requests. + */ protected String boundary; + + /** + * The configuration properties. + */ protected Properties config = null; + + /** + * The SSLSocketFactory for HTTPS connections. + */ protected SSLSocketFactory sslSocketFactory; + + /** + * The HostnameVerifier for HTTPS connections. + */ protected HostnameVerifier hostnameVerifier; + /** + * The response of the DataURL server. + */ protected DataUrlResponse result; + /* (non-Javadoc) + * @see at.gv.egiz.bku.binding.DataUrlConnection#getProtocol() + */ public String getProtocol() { if (protocol == null) { return null; @@ -80,13 +145,8 @@ public class DataUrlConnectionImpl implements DataUrlConnectionSPI { return protocol.toString(); } - /** - * opens a connection sets the headers gets the server certificate - * - * @throws java.net.SocketTimeoutException - * @throws java.io.IOException - * @pre url != null - * @pre httpHeaders != null + /* (non-Javadoc) + * @see at.gv.egiz.bku.binding.DataUrlConnection#connect() */ public void connect() throws SocketTimeoutException, IOException { connection = (HttpURLConnection) url.openConnection(); @@ -104,9 +164,26 @@ public class DataUrlConnectionImpl implements DataUrlConnectionSPI { https.setHostnameVerifier(hostnameVerifier); } } else { - log.trace("No secure connection with: "+url+ " class="+connection.getClass()); + log.trace("No secure connection with: " + url + " class=" + + connection.getClass()); } connection.setDoOutput(true); + // Transfer-Encoding: chunked is problematic ... + // e.g. https://issues.apache.org/bugzilla/show_bug.cgi?id=37794 + // ... therefore disabled. + // connection.setChunkedStreamingMode(5*1024); + if (urlEncoded) { + log.debug("Setting DataURL Content-Type to " + + HttpUtil.APPLICATION_URL_ENCODED); + connection.addRequestProperty(HttpUtil.HTTP_HEADER_CONTENT_TYPE, + HttpUtil.APPLICATION_URL_ENCODED); + } else { + log.debug("Setting DataURL Content-Type to " + + HttpUtil.MULTIPART_FOTMDATA_BOUNDARY); + connection.addRequestProperty(HttpUtil.HTTP_HEADER_CONTENT_TYPE, + HttpUtil.MULTIPART_FOTMDATA + HttpUtil.SEPERATOR[0] + + HttpUtil.MULTIPART_FOTMDATA_BOUNDARY + "=" + boundary); + } Set headers = requestHttpHeaders.keySet(); Iterator headerIt = headers.iterator(); while (headerIt.hasNext()) { @@ -125,51 +202,128 @@ public class DataUrlConnectionImpl implements DataUrlConnectionSPI { } } + /* (non-Javadoc) + * @see at.gv.egiz.bku.binding.DataUrlConnection#getServerCertificate() + */ public X509Certificate getServerCertificate() { return serverCertificate; } + /* (non-Javadoc) + * @see at.gv.egiz.bku.binding.DataUrlConnection#setHTTPHeader(java.lang.String, java.lang.String) + */ public void setHTTPHeader(String name, String value) { if (name != null && value != null) { requestHttpHeaders.put(name, value); } } + /* (non-Javadoc) + * @see at.gv.egiz.bku.binding.DataUrlConnection#setHTTPFormParameter(java.lang.String, java.io.InputStream, java.lang.String, java.lang.String, java.lang.String) + */ public void setHTTPFormParameter(String name, InputStream data, String contentType, String charSet, String transferEncoding) { - InputStreamPartSource source = new InputStreamPartSource(null, data); - FilePart formParam = new FilePart(name, source, contentType, charSet); - if (transferEncoding != null) { - formParam.setTransferEncoding(transferEncoding); - } else { - formParam.setTransferEncoding(null); + // if a content type is specified we have to switch to multipart/formdata encoding + if (contentType != null && contentType.length() > 0) { + urlEncoded = false; } - formParams.add(formParam); + httpFormParameter.add(new HTTPFormParameter(name, data, contentType, + charSet, transferEncoding)); } - /** - * send all formParameters - * - * @throws java.io.IOException + + + /* (non-Javadoc) + * @see at.gv.egiz.bku.binding.DataUrlConnection#transmit(at.gv.egiz.bku.slcommands.SLResult) */ public void transmit(SLResult slResult) throws IOException { - SLResultPart slResultPart = new SLResultPart(slResult, - XML_RESPONSE_ENCODING); - if (slResult.getResultType() == SLResultType.XML) { - slResultPart.setTransferEncoding(null); - slResultPart.setContentType(slResult.getMimeType()); - slResultPart.setCharSet(XML_RESPONSE_ENCODING); + log.trace("Sending data"); + if (urlEncoded) { + // + // application/x-www-form-urlencoded (legacy, SL < 1.2) + // + + OutputStream os = connection.getOutputStream(); + OutputStreamWriter streamWriter = new OutputStreamWriter(os, HttpUtil.DEFAULT_CHARSET); + + // ResponseType + streamWriter.write(FORMPARAM_RESPONSETYPE); + streamWriter.write("="); + streamWriter.write(URLEncoder.encode(DEFAULT_RESPONSETYPE, "UTF-8")); + streamWriter.write("&"); + + // XMLResponse / Binary Response + if (slResult.getResultType() == SLResultType.XML) { + streamWriter.write(DataUrlConnection.FORMPARAM_XMLRESPONSE); + } else { + streamWriter.write(DataUrlConnection.FORMPARAM_BINARYRESPONSE); + } + streamWriter.write("="); + streamWriter.flush(); + URLEncodingWriter urlEnc = new URLEncodingWriter(streamWriter); + slResult.writeTo(new StreamResult(urlEnc), false); + urlEnc.flush(); + + // transfer parameters + char[] cbuf = new char[512]; + int len; + for (HTTPFormParameter formParameter : httpFormParameter) { + streamWriter.write("&"); + streamWriter.write(URLEncoder.encode(formParameter.getName(), "UTF-8")); + streamWriter.write("="); + InputStreamReader reader = new InputStreamReader(formParameter.getData(), + (formParameter.getCharSet() != null) + ? formParameter.getCharSet() + : null); + while ((len = reader.read(cbuf)) != -1) { + urlEnc.write(cbuf, 0, len); + } + urlEnc.flush(); + } + streamWriter.close(); + } else { - slResultPart.setTransferEncoding(null); - slResultPart.setContentType(slResult.getMimeType()); - } - formParams.add(slResultPart); + // + // multipart/form-data (conforming to SL 1.2) + // - OutputStream os = connection.getOutputStream(); - log.trace("Sending data"); - Part[] parts = new Part[formParams.size()]; - Part.sendParts(os, formParams.toArray(parts), boundary.getBytes()); - os.close(); + ArrayList parts = new ArrayList(); + + // ResponseType + StringPart responseType = new StringPart(FORMPARAM_RESPONSETYPE, + DEFAULT_RESPONSETYPE, "UTF-8"); + responseType.setTransferEncoding(null); + parts.add(responseType); + + // XMLResponse / Binary Response + SLResultPart slResultPart = new SLResultPart(slResult, + XML_RESPONSE_ENCODING); + if (slResult.getResultType() == SLResultType.XML) { + slResultPart.setTransferEncoding(null); + slResultPart.setContentType(slResult.getMimeType()); + slResultPart.setCharSet(XML_RESPONSE_ENCODING); + } else { + slResultPart.setTransferEncoding(null); + slResultPart.setContentType(slResult.getMimeType()); + } + parts.add(slResultPart); + + // transfer parameters + for (HTTPFormParameter formParameter : httpFormParameter) { + InputStreamPartSource source = new InputStreamPartSource(null, + formParameter.getData()); + FilePart part = new FilePart(formParameter.getName(), source, + formParameter.getContentType(), formParameter.getCharSet()); + part.setTransferEncoding(formParameter.getTransferEncoding()); + parts.add(part); + } + + OutputStream os = connection.getOutputStream(); + Part.sendParts(os, parts.toArray(new Part[parts.size()]), boundary.getBytes()); + os.close(); + + } + // MultipartRequestEntity PostMethod InputStream is = null; try { @@ -241,16 +395,9 @@ public class DataUrlConnectionImpl implements DataUrlConnectionSPI { .put(HttpUtil.HTTP_HEADER_USER_AGENT, Configurator.USERAGENT_DEFAULT); } - requestHttpHeaders.put(HttpUtil.HTTP_HEADER_CONTENT_TYPE, - HttpUtil.MULTIPART_FOTMDATA + HttpUtil.SEPERATOR[0] - + HttpUtil.MULTIPART_FOTMDATA_BOUNDARY + "=" + boundary); - - formParams = new ArrayList(); - StringPart responseType = new StringPart(FORMPARAM_RESPONSETYPE, - DEFAULT_RESPONSETYPE); - responseType.setCharSet("UTF-8"); - responseType.setTransferEncoding(null); - formParams.add(responseType); + + httpFormParameter = new ArrayList(); + } @Override @@ -281,4 +428,107 @@ public class DataUrlConnectionImpl implements DataUrlConnectionSPI { public void setHostnameVerifier(HostnameVerifier hostnameVerifier) { this.hostnameVerifier = hostnameVerifier; } + + public class HTTPFormParameter { + + private String name; + + private InputStream data; + + private String contentType; + + private String charSet; + + private String transferEncoding; + + /** + * @param name + * @param data + * @param contentType + * @param charSet + * @param transferEncoding + */ + public HTTPFormParameter(String name, InputStream data, String contentType, + String charSet, String transferEncoding) { + super(); + this.name = name; + this.data = data; + this.contentType = contentType; + this.charSet = charSet; + this.transferEncoding = transferEncoding; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the data + */ + public InputStream getData() { + return data; + } + + /** + * @param data the data to set + */ + public void setData(InputStream data) { + this.data = data; + } + + /** + * @return the contentType + */ + public String getContentType() { + return contentType; + } + + /** + * @param contentType the contentType to set + */ + public void setContentType(String contentType) { + this.contentType = contentType; + } + + /** + * @return the charSet + */ + public String getCharSet() { + return charSet; + } + + /** + * @param charSet the charSet to set + */ + public void setCharSet(String charSet) { + this.charSet = charSet; + } + + /** + * @return the transferEncoding + */ + public String getTransferEncoding() { + return transferEncoding; + } + + /** + * @param transferEncoding the transferEncoding to set + */ + public void setTransferEncoding(String transferEncoding) { + this.transferEncoding = transferEncoding; + } + + + + } } \ No newline at end of file diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java index ef603fc7..a1c4d5fc 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java @@ -22,6 +22,7 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; +import java.io.Writer; import java.net.URL; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -46,6 +47,7 @@ import javax.xml.transform.stream.StreamSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import at.gv.egiz.bku.slcommands.ErrorResult; import at.gv.egiz.bku.slcommands.SLCommand; import at.gv.egiz.bku.slcommands.SLCommandContext; import at.gv.egiz.bku.slcommands.SLCommandFactory; @@ -635,7 +637,6 @@ public class HTTPBindingProcessor extends AbstractBindingProcessor implements throw new SLBindingException(2006); } InputDecoder id = InputDecoderFactory.getDecoder(cl, is); - id.setContentType(cl); if (id == null) { log.error("Cannot get inputdecoder for is"); throw new SLException(2006); @@ -730,9 +731,20 @@ public class HTTPBindingProcessor extends AbstractBindingProcessor implements Templates templates) throws IOException { log.debug("Writing error as result"); ErrorResultImpl error = new ErrorResultImpl(bindingProcessorError, locale); - error.writeTo(new StreamResult(new OutputStreamWriter(os, encoding)), templates); + Writer writer = writeXMLDeclarationAndProcessingInstruction(os, encoding); + error.writeTo(new StreamResult(writer), templates, true); } + protected Writer writeXMLDeclarationAndProcessingInstruction(OutputStream os, String encoding) throws IOException { + if (encoding == null) { + encoding = HttpUtil.DEFAULT_CHARSET; + } + OutputStreamWriter writer = new OutputStreamWriter(os, encoding); + writer.write("\n"); + writer.write("\n"); + return writer; + } + @Override public void writeResultTo(OutputStream os, String encoding) throws IOException { @@ -772,9 +784,16 @@ public class HTTPBindingProcessor extends AbstractBindingProcessor implements return; } else { log.debug("Getting result from invoker"); - OutputStreamWriter osw = new OutputStreamWriter(os, encoding); - slResult.writeTo(new StreamResult(osw), templates); - osw.flush(); + boolean fragment = false; + Writer writer; + if (slResult instanceof ErrorResult) { + writer = writeXMLDeclarationAndProcessingInstruction(os, encoding); + fragment = true; + } else { + writer = new OutputStreamWriter(os, encoding); + } + slResult.writeTo(new StreamResult(writer), templates, fragment); + writer.flush(); } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/LegacyDataUrlConnectionImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/LegacyDataUrlConnectionImpl.java deleted file mode 100644 index cfccb7f1..00000000 --- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/LegacyDataUrlConnectionImpl.java +++ /dev/null @@ -1,259 +0,0 @@ -package at.gv.egiz.bku.binding; - - -import at.gv.egiz.bku.conf.Configurator; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.StringWriter; -import java.net.HttpURLConnection; -import java.net.SocketTimeoutException; -import java.net.URL; -import java.net.URLEncoder; -import java.security.cert.X509Certificate; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSocketFactory; -import javax.xml.transform.stream.StreamResult; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import at.gv.egiz.bku.slcommands.SLResult; -import at.gv.egiz.bku.slcommands.SLResult.SLResultType; -import at.gv.egiz.bku.slexceptions.SLRuntimeException; -import at.gv.egiz.bku.utils.binding.Protocol; - -/** - * not thread-safe thus newInsance always returns a new object - * - */ -public class LegacyDataUrlConnectionImpl implements DataUrlConnectionSPI { - - private final static Log log = LogFactory.getLog(LegacyDataUrlConnectionImpl.class); - - public final static Protocol[] SUPPORTED_PROTOCOLS = { Protocol.HTTP, - Protocol.HTTPS }; - protected X509Certificate serverCertificate; - protected Protocol protocol; - protected URL url; - private HttpURLConnection connection; - protected Map requestHttpHeaders; - protected Map formParams; - protected String boundary; - protected Properties config = null; - protected SSLSocketFactory sslSocketFactory; - protected HostnameVerifier hostnameVerifier; - - protected DataUrlResponse result; - - public String getProtocol() { - if (protocol == null) { - return null; - } - return protocol.toString(); - } - - /** - * opens a connection sets the headers gets the server certificate - * - * @throws java.net.SocketTimeoutException - * @throws java.io.IOException - * @pre url != null - * @pre httpHeaders != null - */ - public void connect() throws SocketTimeoutException, IOException { - connection = (HttpURLConnection) url.openConnection(); - if (connection instanceof HttpsURLConnection) { - HttpsURLConnection https = (HttpsURLConnection) connection; - if (sslSocketFactory != null) { - log.debug("Setting custom ssl socket factory for ssl connection"); - https.setSSLSocketFactory(sslSocketFactory); - } - if (hostnameVerifier != null) { - log.debug("Setting custom hostname verifier"); - https.setHostnameVerifier(hostnameVerifier); - } - } - connection.setDoOutput(true); - Set headers = requestHttpHeaders.keySet(); - Iterator headerIt = headers.iterator(); - while (headerIt.hasNext()) { - String name = headerIt.next(); - connection.setRequestProperty(name, requestHttpHeaders.get(name)); - } - log.trace("Connecting to: "+url); - connection.connect(); - if (connection instanceof HttpsURLConnection) { - HttpsURLConnection ssl = (HttpsURLConnection) connection; - X509Certificate[] certs = (X509Certificate[]) ssl.getServerCertificates(); - if ((certs != null) && (certs.length >= 1)) { - log.trace("Server certificate: "+certs[0]); - serverCertificate = certs[0]; - } - } - } - - public X509Certificate getServerCertificate() { - return serverCertificate; - } - - public void setHTTPHeader(String name, String value) { - if (name != null && value != null) { - requestHttpHeaders.put(name, value); - } - } - - public void setHTTPFormParameter(String name, InputStream data, - String contentType, String charSet, String transferEncoding) { - StringBuilder sb = new StringBuilder(); - try { - InputStreamReader reader = new InputStreamReader(data, (charSet != null) ? charSet : "UTF-8"); - char[] c = new char[512]; - for (int l; (l = reader.read(c)) != -1;) { - sb.append(c, 0, l); - } - } catch (IOException e) { - throw new SLRuntimeException("Failed to set HTTP form parameter.", e); - } - formParams.put(name, sb.toString()); - } - - /** - * send all formParameters - * - * @throws java.io.IOException - */ - public void transmit(SLResult slResult) throws IOException { - StringWriter writer = new StringWriter(); - slResult.writeTo(new StreamResult(writer)); - formParams.put( - (slResult.getResultType() == SLResultType.XML) - ? DataUrlConnection.FORMPARAM_XMLRESPONSE - : DataUrlConnection.FORMPARAM_BINARYRESPONSE, - writer.toString()); - - OutputStream os = connection.getOutputStream(); - OutputStreamWriter streamWriter = new OutputStreamWriter(os, HttpUtil.DEFAULT_CHARSET); - - log.trace("Sending data"); - Iterator keys = formParams.keySet().iterator(); - while(keys.hasNext()) { - String key = keys.next(); - streamWriter.write(URLEncoder.encode(key, "UTF-8")); - streamWriter.write("="); - streamWriter.write(URLEncoder.encode(formParams.get(key), "UTF-8")); - if (keys.hasNext()) { - streamWriter.write("&"); - } - } - streamWriter.flush(); - os.close(); - - // MultipartRequestEntity PostMethod - InputStream is = null; - try { - is = connection.getInputStream(); - } catch (IOException iox) { - log.info(iox); - } - log.trace("Reading response"); - result = new DataUrlResponse(url.toString(), connection.getResponseCode(), is); - Map responseHttpHeaders = new HashMap(); - Map> httpHeaders = connection.getHeaderFields(); - for (Iterator keyIt = httpHeaders.keySet().iterator(); keyIt - .hasNext();) { - String key = keyIt.next(); - StringBuffer value = new StringBuffer(); - for (String val : httpHeaders.get(key)) { - value.append(val); - value.append(HttpUtil.SEPERATOR[0]); - } - String valString = value.substring(0, value.length() - 1); - if ((key != null) && (value.length() > 0)) { - responseHttpHeaders.put(key, valString); - } - } - result.setResponseHttpHeaders(responseHttpHeaders); - } - - @Override - public DataUrlResponse getResponse() throws IOException { - return result; - } - - /** - * inits protocol, url, httpHeaders, formParams - * - * @param url - * must not be null - */ - @Override - public void init(URL url) { - - for (int i = 0; i < SUPPORTED_PROTOCOLS.length; i++) { - if (SUPPORTED_PROTOCOLS[i].toString().equalsIgnoreCase(url.getProtocol())) { - protocol = SUPPORTED_PROTOCOLS[i]; - break; - } - } - if (protocol == null) { - throw new SLRuntimeException("Protocol " + url.getProtocol() - + " not supported for data url"); - } - this.url = url; - requestHttpHeaders = new HashMap(); - if ((config != null) - && (config.getProperty(Configurator.USERAGENT_CONFIG_P) != null)) { - log.debug("setting User-Agent header: " + config.getProperty(Configurator.USERAGENT_CONFIG_P)); - requestHttpHeaders.put(HttpUtil.HTTP_HEADER_USER_AGENT, config - .getProperty(Configurator.USERAGENT_CONFIG_P)); - } else { - requestHttpHeaders - .put(HttpUtil.HTTP_HEADER_USER_AGENT, Configurator.USERAGENT_DEFAULT); - - } - requestHttpHeaders.put(HttpUtil.HTTP_HEADER_CONTENT_TYPE, - HttpUtil.APPLICATION_URL_ENCODED); - - formParams = new HashMap(); - } - - @Override - public DataUrlConnectionSPI newInstance() { - DataUrlConnectionSPI uc = new LegacyDataUrlConnectionImpl(); - uc.setConfiguration(config); - uc.setSSLSocketFactory(sslSocketFactory); - uc.setHostnameVerifier(hostnameVerifier); - return uc; - } - - @Override - public URL getUrl() { - return url; - } - - @Override - public void setConfiguration(Properties config) { - this.config = config; - } - - @Override - public void setSSLSocketFactory(SSLSocketFactory socketFactory) { - this.sslSocketFactory = socketFactory; - } - - @Override - public void setHostnameVerifier(HostnameVerifier hostnameVerifier) { - this.hostnameVerifier = hostnameVerifier; - } -} \ No newline at end of file diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/XWWWFormUrlInputDecoder.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/XWWWFormUrlInputDecoder.java index f4ebe288..69c659e1 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/XWWWFormUrlInputDecoder.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/XWWWFormUrlInputDecoder.java @@ -16,86 +16,43 @@ */ package at.gv.egiz.bku.binding; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URLDecoder; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.io.InputStream; +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.fileupload.ParameterParser; -import org.apache.commons.fileupload.ParameterParser; - -import at.gv.egiz.bku.slexceptions.SLRuntimeException; -import at.gv.egiz.bku.utils.StreamUtil; - -/** - * Implementation based on Java's URLDecoder class - * - */ -// FIXME replace this code by a streaming variant public class XWWWFormUrlInputDecoder implements InputDecoder { - - public final static String CHAR_SET = "charset"; - public final static String NAME_VAL_SEP = "="; - public final static String SEP = "\\&"; - - private String contentType; - private InputStream dataStream; - private String charset = "UTF-8"; - - protected List decodeInput(InputStream is) throws IOException { - List result = new LinkedList(); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - StreamUtil.copyStream(is, bos); - String inputString = new String(bos.toByteArray()); - String[] nameValuePairs = inputString.split(SEP); - //inputString = URLDecoder.decode(inputString, charset); - for (int i = 0; i < nameValuePairs.length; i++) { - String[] fields = nameValuePairs[i].split(NAME_VAL_SEP, 2); - if (fields.length != 2) { - throw new SLRuntimeException("Invalid form encoding, missing value"); - } - String name = URLDecoder.decode(fields[0], charset); - String value =URLDecoder.decode(fields[1], charset); - ByteArrayInputStream bais = new ByteArrayInputStream(value - .getBytes(charset)); - FormParameterImpl fpi = new FormParameterImpl(contentType, name, bais, null); - result.add(fpi); - } - return result; - } - - @SuppressWarnings("unchecked") + + /** + * The MIME type 'application/x-www-form-urlencoded'. + */ + public static final String CONTENT_TYPE = "application/x-www-form-urlencoded"; + + /** + * The form parameter iterator. + */ + protected XWWWFormUrlInputIterator iterator; + + @SuppressWarnings("unchecked") @Override public void setContentType(String contentType) { ParameterParser pp = new ParameterParser(); pp.setLowerCaseNames(true); Map params = pp.parse(contentType, new char[] { ':', ';' }); - if (!params.containsKey("application/x-www-form-urlencoded")) { + if (!params.containsKey(CONTENT_TYPE)) { throw new IllegalArgumentException( "not a url encoded content type specification: " + contentType); } - String cs = params.get(CHAR_SET); - if (cs != null) { - charset = cs; - } - this.contentType = contentType; } @Override public Iterator getFormParameterIterator() { - try { - return decodeInput(dataStream).iterator(); - } catch (IOException e) { - throw new SLRuntimeException(e); - } + return iterator; } @Override public void setInputStream(InputStream is) { - dataStream = is; + iterator = new XWWWFormUrlInputIterator(is); } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/XWWWFormUrlInputIterator.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/XWWWFormUrlInputIterator.java new file mode 100644 index 00000000..f052ce05 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/XWWWFormUrlInputIterator.java @@ -0,0 +1,376 @@ +package at.gv.egiz.bku.binding; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +public class XWWWFormUrlInputIterator implements Iterator { + + public static final byte NAME_VALUE_SEP = '='; + + public static final byte PARAM_SEP = '&'; + + public static final Charset UTF_8 = Charset.forName("UTF-8"); + + /** + * The default buffer size. + */ + protected static final int DEFAULT_BUFFER_SIZE = 4096; + + /** + * Are we done with parsing the input. + */ + protected boolean done = false; + + /** + * The x-www-formdata-urlencoded input stream to be parsed. + */ + protected final InputStream in; + + /** + * The buffer size. + */ + protected int bufferSize = DEFAULT_BUFFER_SIZE; + + /** + * The read buffer. + */ + protected final byte[] buf = new byte[bufferSize]; + + /** + * The read position. + */ + protected int pos; + + /** + * The number of valid bytes in the buffer; + */ + protected int count; + + /** + * The parameter returned by the last call of {@link #next()}; + */ + protected XWWWFormUrlEncodedParameter currentParameter; + + /** + * An IOException that cannot be reported immediately. + */ + protected IOException deferredIOException; + + /** + * Creates a new instance of this x-www-formdata-urlencoded input iterator + * with the given InputStream in to be parsed. + * + * @param in the InputStream to be parsed + */ + public XWWWFormUrlInputIterator(InputStream in) { + this.in = in; + } + + /* (non-Javadoc) + * @see java.util.Iterator#hasNext() + */ + @Override + public boolean hasNext() { + if (done) { + return false; + } + if (currentParameter != null) { + // we have to disconnect the current parameter + // to look for further parameters + try { + currentParameter.formParameterValue.disconnect(); + // fill buffer if empty + if (pos >= count) { + if ((count = in.read(buf)) == -1) { + // done + done = true; + return false; + } + pos = 0; + } + } catch (IOException e) { + deferredIOException = e; + } + } + return true; + } + + @Override + public FormParameter next() { + if (hasNext()) { + // skip separator + pos++; + currentParameter = new XWWWFormUrlEncodedParameter(); + return currentParameter; + } else { + throw new NoSuchElementException(); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + public class XWWWFormUrlEncodedParameter implements FormParameter { + + /** + * The list of header names. + */ + // x-www-form-urlencoded parameters do not provide headers + protected final List headers = Collections.emptyList(); + + /** + * The name of the form parameter. + */ + protected String formParameterName; + + /** + * The value of the form parameter. + */ + protected URLDecodingInputStream formParameterValue; + + public XWWWFormUrlEncodedParameter() { + // parse parameter name + URLDecodingInputStream urldec = new URLDecodingInputStream(in, NAME_VALUE_SEP); + InputStreamReader reader = new InputStreamReader(urldec, UTF_8); + try { + StringBuilder sb = new StringBuilder(); + char[] b = new char[128]; + for (int l = 0; (l = reader.read(b)) != -1;) { + sb.append(b, 0, l); + } + formParameterName = sb.toString(); + // fill buffer if empty + if (pos >= count) { + if ((count = in.read(buf)) == -1) { + throw new IOException("Invalid URL encoding."); + } + pos = 0; + } + // skip separator + pos++; + } catch (IOException e) { + deferredIOException = e; + formParameterName = ""; + } + formParameterValue = new URLDecodingInputStream(in, PARAM_SEP); + } + + @Override + public String getFormParameterContentType() { + // x-www-form-urlencoded parameters do not specify a content type + return null; + } + + @Override + public String getFormParameterName() { + return formParameterName; + } + + @Override + public InputStream getFormParameterValue() { + if (deferredIOException != null) { + final IOException e = deferredIOException; + deferredIOException = null; + return new InputStream() { + @Override + public int read() throws IOException { + throw e; + } + }; + } else { + return formParameterValue; + } + } + + @Override + public Iterator getHeaderNames() { + return headers.iterator(); + } + + @Override + public String getHeaderValue(String headerName) { + return null; + } + + } + + public class URLDecodingInputStream extends FilterInputStream { + + /** + * Has this stream already been closed. + */ + private boolean closed = false; + + /** + * Has this stream been disconnected. + */ + private boolean disconnected = false; + + /** + * Read until this byte occurs. + */ + protected final byte term; + + /** + * Creates a new instance of this URLDecodingInputStream. + * + * @param in + * @param separator + */ + protected URLDecodingInputStream(InputStream in, byte separator) { + super(in); + this.term = separator; + } + + /* (non-Javadoc) + * @see java.io.FilterInputStream#read() + */ + @Override + public int read() throws IOException { + if (closed) { + throw new IOException("The stream has already been closed."); + } + if (disconnected) { + return in.read(); + } + + if (pos >= count) { + if ((count = in.read(buf)) == -1) { + return -1; + } + pos = 0; + } if (buf[pos] == term) { + return -1; + } else if (buf[pos] == '+') { + pos++; + return ' '; + } else if (buf[pos] == '%') { + if (++pos == count) { + if ((count = in.read(buf)) == -1) { + throw new IOException("Invalid URL encoding."); + } + pos = 0; + } + int c1 = Character.digit(buf[pos], 16); + if (++pos == count) { + if ((count = in.read(buf)) == -1) { + throw new IOException("Invalid URL encoding."); + } + pos = 0; + } + int c2 = Character.digit(buf[pos], 16); + return ((c1 << 4) | c2); + } else { + return buf[pos++]; + } + } + + /* (non-Javadoc) + * @see java.io.FilterInputStream#read(byte[], int, int) + */ + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (closed) { + throw new IOException("The stream has already been closed."); + } + if (disconnected) { + return in.read(b, off, len); + } + + if ((off | len | (off + len) | (b.length - (off + len))) < 0) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + + if (pos >= count) { + if ((count = in.read(buf)) == -1) { + return -1; + } + pos = 0; + } + if (buf[pos] == term) { + return -1; + } + + int l = 0; + for (;;) { + while (pos < count) { + if (l == len || buf[pos] == term) { + return l; + } else if (buf[pos] == '+') { + b[off] = ' '; + } else if (buf[pos] == '%') { + if (++pos == count && (count = in.read(buf)) == -1) { + throw new IOException("Invalid URL encoding."); + } + int c1 = Character.digit(buf[pos], 16); + if (++pos == count && (count = in.read(buf)) == -1) { + throw new IOException("Invalid URL encoding."); + } + int c2 = Character.digit(buf[pos], 16); + b[off] = (byte) ((c1 << 4) | c2); + } else { + b[off] = buf[pos]; + } + pos++; + off++; + l++; + } + if ((count = in.read(buf)) == -1) { + return l; + } + pos = 0; + } + } + + /** + * Disconnect from the InputStream and buffer all remaining data. + * + * @throws IOException + */ + public void disconnect() throws IOException { + if (!disconnected) { + // don't waste space for a buffer if end of stream has already been + // reached + byte[] b = new byte[1]; + if ((read(b)) != -1) { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + os.write(b); + b = new byte[1024]; + for (int l; (l = read(b, 0, b.length)) != -1;) { + os.write(b, 0, l); + } + super.in = new ByteArrayInputStream(os.toByteArray()); + } + disconnected = true; + } + } + + /* (non-Javadoc) + * @see java.io.FilterInputStream#close() + */ + @Override + public void close() throws IOException { + if (!hasNext()) { + // don't close the underlying stream until all parts are read + super.close(); + } + disconnect(); + closed = true; + } + + } + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/SLResultPart.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/SLResultPart.java index 5585f02e..d896ea9f 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/SLResultPart.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/SLResultPart.java @@ -16,37 +16,56 @@ */ package at.gv.egiz.bku.binding.multipart; +import at.gv.egiz.bku.binding.DataUrlConnection; import at.gv.egiz.bku.slcommands.SLResult; +import at.gv.egiz.bku.slcommands.SLResult.SLResultType; + import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import javax.xml.transform.stream.StreamResult; -import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource; import org.apache.commons.httpclient.methods.multipart.FilePart; +import org.apache.commons.httpclient.methods.multipart.PartSource; -/** - * - * @author clemens - */ public class SLResultPart extends FilePart { protected SLResult slResult; protected String encoding; public SLResultPart(SLResult slResult, String encoding) { - super("XMLResponse", - new ByteArrayPartSource(null, "dummySource".getBytes())); + super((slResult.getResultType() == SLResultType.XML) + ? DataUrlConnection.FORMPARAM_XMLRESPONSE + : DataUrlConnection.FORMPARAM_BINARYRESPONSE, + new PartSource() { + + @Override + public long getLength() { + // may return null, as sendData() is overridden + return 0; + } + + @Override + public String getFileName() { + // return null, to prevent content-disposition header + return null; + } + + @Override + public InputStream createInputStream() throws IOException { + // may return null, as sendData() is overridden below + return null; + } + } + ); this.slResult = slResult; this.encoding = encoding; } @Override protected void sendData(OutputStream out) throws IOException { - slResult.writeTo(new StreamResult(new OutputStreamWriter(out, encoding))); - // slResult.writeTo(new StreamResult(new OutputStreamWriter(System.out, - // encoding))); - // super.sendData(out); + slResult.writeTo(new StreamResult(new OutputStreamWriter(out, encoding)), false); } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/conf/CertValidatorImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/conf/CertValidatorImpl.java index 125233c1..3b2d1b99 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/conf/CertValidatorImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/conf/CertValidatorImpl.java @@ -1,7 +1,9 @@ package at.gv.egiz.bku.conf; +import iaik.logging.LogConfigurationException; import iaik.logging.TransactionId; import iaik.logging.impl.TransactionIdImpl; +import iaik.logging.LoggerConfig; import iaik.pki.DefaultPKIConfiguration; import iaik.pki.DefaultPKIProfile; import iaik.pki.PKIConfiguration; @@ -18,6 +20,7 @@ import iaik.x509.X509Certificate; import java.io.File; import java.util.Date; +import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -37,6 +40,27 @@ public class CertValidatorImpl implements CertValidator { * @see at.gv.egiz.bku.conf.CertValidator#init(java.io.File, java.io.File) */ public void init(File certDir, File caDir) { + // initialize IAIK logging for PKI module + log.debug("Configuring logging for IAIK PKI module"); + iaik.logging.LogFactory.configure(new LoggerConfig() { + + @Override + public Properties getProperties() throws LogConfigurationException { + return null; + } + + @Override + public String getNodeId() { + return "pki"; + } + + @Override + public String getFactory() { + return IAIKCommonsLogFactory.class.getName(); + } + }); + + // the parameters specifying the directory certstore CertStoreParameters[] certStoreParameters = { new DefaultDirectoryCertStoreParameters( "CS-001", certDir.getAbsolutePath(), true, false) }; diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/conf/IAIKCommonsLog.java b/bkucommon/src/main/java/at/gv/egiz/bku/conf/IAIKCommonsLog.java new file mode 100644 index 00000000..1b7dd189 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/conf/IAIKCommonsLog.java @@ -0,0 +1,144 @@ +/** + * + */ +package at.gv.egiz.bku.conf; + +import iaik.logging.Log; +import iaik.logging.TransactionId; + +/** + * @author mcentner + * + */ +public class IAIKCommonsLog implements Log { + + /** + * The id that will be written to the log if the transactionid == null + */ + public final static String NO_ID = "Null-ID"; + + protected org.apache.commons.logging.Log commonsLog; + + protected String nodeId; + + public IAIKCommonsLog(org.apache.commons.logging.Log log) { + this.commonsLog = log; + } + + /* (non-Javadoc) + * @see iaik.logging.Log#debug(iaik.logging.TransactionId, java.lang.Object, java.lang.Throwable) + */ + @Override + public void debug(TransactionId transactionId, Object message, Throwable t) { + if (commonsLog.isDebugEnabled()) { + commonsLog.debug(nodeId + ": " + + ((transactionId != null) ? transactionId.getLogID() : NO_ID) + ": " + + message, t); + } + } + + /* (non-Javadoc) + * @see iaik.logging.Log#info(iaik.logging.TransactionId, java.lang.Object, java.lang.Throwable) + */ + @Override + public void info(TransactionId transactionId, Object message, Throwable t) { + if (commonsLog.isInfoEnabled()) { + commonsLog.info(nodeId + ": " + + ((transactionId != null) ? transactionId.getLogID() : NO_ID) + ": " + + message, t); + } + } + + /* (non-Javadoc) + * @see iaik.logging.Log#warn(iaik.logging.TransactionId, java.lang.Object, java.lang.Throwable) + */ + @Override + public void warn(TransactionId transactionId, Object message, Throwable t) { + if (commonsLog.isWarnEnabled()) { + commonsLog.warn(nodeId + ": " + + ((transactionId != null) ? transactionId.getLogID() : NO_ID) + ": " + + message, t); + } + } + + /* (non-Javadoc) + * @see iaik.logging.Log#error(iaik.logging.TransactionId, java.lang.Object, java.lang.Throwable) + */ + @Override + public void error(TransactionId transactionId, Object message, Throwable t) { + if (commonsLog.isErrorEnabled()) { + commonsLog.error(nodeId + ": " + + ((transactionId != null) ? transactionId.getLogID() : NO_ID) + ": " + + message, t); + } + } + + /* (non-Javadoc) + * @see iaik.logging.Log#fatal(iaik.logging.TransactionId, java.lang.Object, java.lang.Throwable) + */ + @Override + public void fatal(TransactionId transactionId, Object message, Throwable t) { + if (commonsLog.isFatalEnabled()) { + commonsLog.fatal(nodeId + ": " + + ((transactionId != null) ? transactionId.getLogID() : NO_ID) + ": " + + message, t); + } + } + + /* (non-Javadoc) + * @see iaik.logging.Log#setNodeId(java.lang.String) + */ + @Override + public void setNodeId(String nodeId) { + this.nodeId = nodeId; + } + + /* (non-Javadoc) + * @see iaik.logging.Log#getNodeId() + */ + @Override + public String getNodeId() { + return nodeId; + } + + /* (non-Javadoc) + * @see iaik.logging.Log#isDebugEnabled() + */ + @Override + public boolean isDebugEnabled() { + return commonsLog.isDebugEnabled(); + } + + /* (non-Javadoc) + * @see iaik.logging.Log#isInfoEnabled() + */ + @Override + public boolean isInfoEnabled() { + return commonsLog.isInfoEnabled(); + } + + /* (non-Javadoc) + * @see iaik.logging.Log#isWarnEnabled() + */ + @Override + public boolean isWarnEnabled() { + return commonsLog.isWarnEnabled(); + } + + /* (non-Javadoc) + * @see iaik.logging.Log#isErrorEnabled() + */ + @Override + public boolean isErrorEnabled() { + return commonsLog.isErrorEnabled(); + } + + /* (non-Javadoc) + * @see iaik.logging.Log#isFatalEnabled() + */ + @Override + public boolean isFatalEnabled() { + return commonsLog.isFatalEnabled(); + } + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/conf/IAIKCommonsLogFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/conf/IAIKCommonsLogFactory.java new file mode 100644 index 00000000..14e2c757 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/conf/IAIKCommonsLogFactory.java @@ -0,0 +1,59 @@ +/** + * + */ +package at.gv.egiz.bku.conf; + +import org.apache.commons.logging.impl.WeakHashtable; + +import iaik.logging.Log; +import iaik.logging.LogConfigurationException; +import iaik.logging.LogFactory; + +/** + * @author mcentner + * + */ +public class IAIKCommonsLogFactory extends LogFactory { + + protected WeakHashtable instances = new WeakHashtable(); + + /* (non-Javadoc) + * @see iaik.logging.LogFactory#getInstance(java.lang.String) + */ + @Override + public Log getInstance(String name) throws LogConfigurationException { + org.apache.commons.logging.Log commonsLog = org.apache.commons.logging.LogFactory.getLog(name); + Log log = (Log) instances.get(commonsLog); + if (log == null) { + log = new IAIKCommonsLog(commonsLog); + log.setNodeId(node_id_); + instances.put(commonsLog, log); + } + return log; + } + + /* (non-Javadoc) + * @see iaik.logging.LogFactory#getInstance(java.lang.Class) + */ + @SuppressWarnings("unchecked") + @Override + public Log getInstance(Class clazz) throws LogConfigurationException { + org.apache.commons.logging.Log commonsLog = org.apache.commons.logging.LogFactory.getLog(clazz); + Log log = (Log) instances.get(commonsLog); + if (log == null) { + log = new IAIKCommonsLog(commonsLog); + log.setNodeId(node_id_); + instances.put(commonsLog, log); + } + return log; + } + + /* (non-Javadoc) + * @see iaik.logging.LogFactory#release() + */ + @Override + public void release() { + instances.clear(); + } + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandFactory.java index fe27bc54..8e3f6ece 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandFactory.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandFactory.java @@ -28,6 +28,7 @@ import javax.xml.bind.JAXBException; import javax.xml.bind.UnmarshalException; import javax.xml.bind.Unmarshaller; import javax.xml.bind.ValidationEvent; +import javax.xml.bind.ValidationEventLocator; import javax.xml.namespace.QName; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; @@ -46,11 +47,11 @@ import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.bku.slexceptions.SLExceptionMessages; import at.gv.egiz.bku.slexceptions.SLRequestException; import at.gv.egiz.bku.slexceptions.SLRuntimeException; +import at.gv.egiz.bku.slexceptions.SLVersionException; import at.gv.egiz.bku.utils.DebugReader; import at.gv.egiz.slbinding.RedirectEventFilter; import at.gv.egiz.slbinding.RedirectUnmarshallerListener; -import at.gv.egiz.validation.ValidationEventLogger; -import javax.xml.bind.ValidationEventHandler; +import at.gv.egiz.validation.ReportingValidationEventHandler; public class SLCommandFactory { @@ -60,7 +61,9 @@ public class SLCommandFactory { public static final String[] SCHEMA_FILES = new String[]{ "at/gv/egiz/bku/slcommands/schema/xml.xsd", "at/gv/egiz/bku/slcommands/schema/xmldsig-core-schema.xsd", - "at/gv/egiz/bku/slcommands/schema/Core-1.2.xsd" + "at/gv/egiz/bku/slcommands/schema/Core-1.2.xsd", + "at/gv/egiz/bku/slcommands/schema/Core.20020225.xsd", + "at/gv/egiz/bku/slcommands/schema/Core.20020831.xsd" }; /** * Logging facility. @@ -169,7 +172,10 @@ public class SLCommandFactory { String slPkg = at.buergerkarte.namespaces.securitylayer._1.ObjectFactory.class.getPackage().getName(); String xmldsigPkg = org.w3._2000._09.xmldsig_.ObjectFactory.class.getPackage().getName(); String cardChannelPkg = at.buergerkarte.namespaces.cardchannel.ObjectFactory.class.getPackage().getName(); - setJaxbContext(JAXBContext.newInstance(slPkg + ":" + xmldsigPkg + ":" + cardChannelPkg)); + String slPkgLegacy1_0 = at.buergerkarte.namespaces.securitylayer._20020225_.ObjectFactory.class.getPackage().getName(); + String slPkgLegacy1_1 = at.buergerkarte.namespaces.securitylayer._20020831_.ObjectFactory.class.getPackage().getName(); + setJaxbContext(JAXBContext.newInstance(slPkg + ":" + xmldsigPkg + ":" + cardChannelPkg + + ":" + slPkgLegacy1_0 + ":" + slPkgLegacy1_1)); } catch (JAXBException e) { log.error("Failed to setup JAXBContext security layer request.", e); throw new SLRuntimeException(e); @@ -248,26 +254,9 @@ public class SLCommandFactory { SLRequestException { Object object; + ReportingValidationEventHandler validationEventHandler = new ReportingValidationEventHandler(); try { -// ValidatorHandler validator = slSchema.newValidatorHandler(); -// validator.getContentHandler(); -// -// SAXParserFactory spf = SAXParserFactory.newInstance(); -// spf.setNamespaceAware(true); -// XMLReader saxReader = spf.newSAXParser().getXMLReader(); -// //TODO extend validator to implement redirectContentHandler (validate+redirect) -// saxReader.setContentHandler(validator); -// //TODO get a InputSource -// SAXSource saxSource = new SAXSource(saxReader, source); -// -// Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); -// //turn off duplicate jaxb validation -// unmarshaller.setSchema(null); -// unmarshaller.setListener(listener); -// unmarshaller.unmarshal(saxSource); - - XMLInputFactory inputFactory = XMLInputFactory.newInstance(); XMLEventReader eventReader = inputFactory.createXMLEventReader(source); RedirectEventFilter redirectEventFilter = new RedirectEventFilter(); @@ -279,7 +268,7 @@ public class SLCommandFactory { unmarshaller.setSchema(slSchema); } log.trace("Before unmarshal()."); - unmarshaller.setEventHandler(new ValidationEventLogger()); + unmarshaller.setEventHandler(validationEventHandler); object = unmarshaller.unmarshal(filteredReader); log.trace("After unmarshal()."); } catch (UnmarshalException e) { @@ -288,6 +277,13 @@ public class SLCommandFactory { } else { log.info("Failed to unmarshall security layer request." + e.getMessage()); } + if (validationEventHandler.getErrorEvent() != null) { + // Validation Error + ValidationEvent errorEvent = validationEventHandler.getErrorEvent(); + ValidationEventLocator locator = errorEvent.getLocator(); + throw new SLRequestException(3002, + SLExceptionMessages.EC3002_INVALID, new Object[]{errorEvent.getMessage()}); + } Throwable cause = e.getCause(); if (cause instanceof SAXParseException) { throw new SLRequestException(3000, @@ -328,10 +324,11 @@ public class SLCommandFactory { * if an unexpected error occurs configuring the unmarshaller, if * unmarshalling fails with an unexpected error or if the * corresponding SLCommand could not be instantiated + * @throws SLVersionException */ @SuppressWarnings("unchecked") public SLCommand createSLCommand(Source source, SLCommandContext context) - throws SLCommandException, SLRuntimeException, SLRequestException { + throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { DebugReader dr = null; if (log.isTraceEnabled() && source instanceof StreamSource) { @@ -361,6 +358,12 @@ public class SLCommandFactory { } QName qName = ((JAXBElement) object).getName(); + if (!SLCommand.NAMESPACE_URI.equals(qName.getNamespaceURI())) { + // security layer request version not supported + log.info("Unsupported security layer request version : " + qName.getNamespaceURI()); + throw new SLVersionException(qName.getNamespaceURI()); + } + Class implClass = getImplClass(qName); if (implClass == null) { // command not supported diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLMarshallerFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLMarshallerFactory.java new file mode 100644 index 00000000..e0a375cf --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLMarshallerFactory.java @@ -0,0 +1,172 @@ +/* +* Copyright 2009 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.slcommands; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.bku.slexceptions.SLRuntimeException; +import at.gv.egiz.marshal.MarshallerFactory; + +public class SLMarshallerFactory { + + static Log log = LogFactory.getLog(SLMarshallerFactory.class); + + /** + * The JAXBContext used for result marshaling. + *

+ * Note: Different contexts are used for marshaling and unmarshaling of + * security layer requests and responses to avoid propagation of namespace + * declarations of legacy namespaces into marshaled results. + *

+ * @see #jaxbContextLegacy + */ + protected static JAXBContext context; + + /** + * The JAXBContext used for marshaling of of results in the legacy namespace. + */ + protected static JAXBContext legacyContext; + + // ------------------- initialization on demand idiom ------------------- + // see http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom + // ---------------------------------------------------------------------- + + /** + * Private constructor called by {@link SLMarshallerFactoryInstanceHolder}. + */ + private SLMarshallerFactory() { + // context is initialized immediately while the legacy context is initialized only on demand + try { + String slPkg = at.buergerkarte.namespaces.securitylayer._1.ObjectFactory.class.getPackage().getName(); + String xmldsigPkg = org.w3._2000._09.xmldsig_.ObjectFactory.class.getPackage().getName(); + String cardChannelPkg = at.buergerkarte.namespaces.cardchannel.ObjectFactory.class.getPackage().getName(); + context = JAXBContext.newInstance(slPkg + ":" + xmldsigPkg + ":" + cardChannelPkg); + } catch (JAXBException e) { + log.error("Failed to setup JAXBContext security layer request.", e); + throw new SLRuntimeException(e); + } + } + + /** + * The lazy instance holder for this SLMarshallerFactory. + */ + private static class SLMarshallerFactoryInstanceHolder { + /** + * The instance returned by {@link SLMarshallerFactory#getInstance()} + */ + private static final SLMarshallerFactory instance = new SLMarshallerFactory(); + } + + /** + * Get an instance of the SLMarshallerFactory. + */ + public static SLMarshallerFactory getInstance() { + return SLMarshallerFactoryInstanceHolder.instance; + } + + // ---------------------------------------------------------------------- + + /** + * Initialize the JAXBContext for the legacy namespace. + */ + private static synchronized void ensureLegacyContext() { + // legacy marshaller is initialized only on demand + if (legacyContext == null) { + try { + String slPkgLegacy1_0 = at.buergerkarte.namespaces.securitylayer._20020225_.ObjectFactory.class.getPackage().getName(); + String slPkgLegacy1_1 = at.buergerkarte.namespaces.securitylayer._20020831_.ObjectFactory.class.getPackage().getName(); + String xmldsigPkg = org.w3._2000._09.xmldsig_.ObjectFactory.class.getPackage().getName(); + String cardChannelPkg = at.buergerkarte.namespaces.cardchannel.ObjectFactory.class.getPackage().getName(); + legacyContext = JAXBContext.newInstance(slPkgLegacy1_0 + ":" + slPkgLegacy1_1 + ":" + xmldsigPkg + ":" + cardChannelPkg); + } catch (JAXBException e) { + log.error("Failed to setup JAXBContext security layer request.", e); + throw new SLRuntimeException(e); + } + } + } + + /** + * Creates an SL marshaller. + * + * @param formattedOutput + * true if the marshaller should produce formated + * output, false otherwise + * @return an SL marshaller + */ + public Marshaller createMarshaller(boolean formattedOutput) { + return createMarshaller(formattedOutput, false); + } + + /** + * Creates an SL marshaller. + * + * @param formattedOutput + * true if the marshaller should produce formated + * output, false otherwise + * @param fragment + * true if the marshaller should produce a XML fragment + * (omit XML declaration), false otherwise + * @return an SL marshaller + */ + public Marshaller createMarshaller(boolean formattedOutput, boolean fragment) { + try { + return MarshallerFactory.createMarshaller(context, formattedOutput, fragment); + } catch (JAXBException e) { + log.fatal("Failed to marshall error response.", e); + throw new SLRuntimeException("Failed to marshall error response.", e); + } + } + + /** + * Creates a legacy SL marshaller. + * + * @param formattedOutput + * true if the marshaller should produce formated + * output, false otherwise + * @return a legacy SL marshaller + */ + public Marshaller createLegacyMarshaller(boolean formattedOutput) { + return createLegacyMarshaller(formattedOutput, false); + } + + /** + * Creates a legacy SL marshaller. + * + * @param formattedOutput + * true if the marshaller should produce formated + * output, false otherwise + * @param fragment + * true if the marshaller should produce a XML fragment + * (omit XML declaration), false otherwise + * @return a legacy SL marshaller + */ + public Marshaller createLegacyMarshaller(boolean formattedOutput, boolean fragment) { + try { + ensureLegacyContext(); + return MarshallerFactory.createMarshaller(legacyContext, formattedOutput, fragment); + } catch (JAXBException e) { + log.fatal("Failed to marshall error response.", e); + throw new SLRuntimeException("Failed to marshall error response.", e); + } + } + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLResult.java index 7989a771..e9e483c5 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLResult.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLResult.java @@ -32,12 +32,14 @@ public interface SLResult { */ public String getMimeType(); - public void writeTo(Result aResult); + public void writeTo(Result aResult, boolean fragment); /** * - * @param result + * @param result + * @param fragment TODO * @param transformer may be null. */ - public void writeTo(Result result, Templates templates); + public void writeTo(Result result, Templates templates, boolean fragment); + } \ No newline at end of file diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractAssocArrayInfobox.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractAssocArrayInfobox.java index ce03dcf9..9a4536e6 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractAssocArrayInfobox.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractAssocArrayInfobox.java @@ -16,7 +16,6 @@ */ package at.gv.egiz.bku.slcommands.impl; -import at.gv.egiz.marshal.NamespacePrefixMapperImpl; import java.io.ByteArrayOutputStream; import java.util.Arrays; import java.util.Collections; @@ -24,7 +23,6 @@ import java.util.List; import java.util.Map; import java.util.regex.Pattern; -import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; @@ -42,10 +40,8 @@ import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadParamsAssocArrayTy import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadParamsAssocArrayType.ReadValue; import at.gv.egiz.bku.slcommands.InfoboxReadResult; import at.gv.egiz.bku.slcommands.SLCommandContext; -import at.gv.egiz.bku.slcommands.SLCommandFactory; +import at.gv.egiz.bku.slcommands.SLMarshallerFactory; import at.gv.egiz.bku.slexceptions.SLCommandException; -import at.gv.egiz.marshal.MarshallerFactory; -import javax.xml.bind.PropertyException; /** * An abstract base class for {@link Infobox} implementations of type associative array. @@ -255,13 +251,10 @@ public abstract class AbstractAssocArrayInfobox extends AbstractInfoboxImpl } protected byte[] marshallValue(Object jaxbElement) throws SLCommandException { - SLCommandFactory commandFactory = SLCommandFactory.getInstance(); - JAXBContext jaxbContext = commandFactory.getJaxbContext(); - ByteArrayOutputStream result; + Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(false); + ByteArrayOutputStream result = new ByteArrayOutputStream(); try { - Marshaller marshaller = MarshallerFactory.createMarshaller(jaxbContext); - result = new ByteArrayOutputStream(); marshaller.marshal(jaxbElement, result); } catch (JAXBException e) { log.info("Failed to marshall infobox content.", e); diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureResultImpl.java index b352a51e..19df4334 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureResultImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureResultImpl.java @@ -16,8 +16,6 @@ */ package at.gv.egiz.bku.slcommands.impl; -import at.gv.egiz.marshal.NamespacePrefixMapperImpl; -import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; @@ -33,10 +31,8 @@ import org.w3c.dom.Node; import at.buergerkarte.namespaces.securitylayer._1.CreateXMLSignatureResponseType; import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory; -import at.gv.egiz.bku.slcommands.SLCommandFactory; +import at.gv.egiz.bku.slcommands.SLMarshallerFactory; import at.gv.egiz.bku.slexceptions.SLRuntimeException; -import at.gv.egiz.marshal.MarshallerFactory; -import javax.xml.bind.PropertyException; /** * This calls implements the result of the security layer command CreateXMLSignature. @@ -86,10 +82,9 @@ public class CreateXMLSignatureResultImpl extends SLResultImpl { JAXBElement createCreateXMLSignatureResponse = factory.createCreateXMLSignatureResponse(createCreateXMLSignatureResponseType); DocumentFragment fragment = doc.createDocumentFragment(); - - JAXBContext jaxbContext = SLCommandFactory.getInstance().getJaxbContext(); + + Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(false); try { - Marshaller marshaller = MarshallerFactory.createMarshaller(jaxbContext); marshaller.marshal(createCreateXMLSignatureResponse, fragment); } catch (JAXBException e) { log.error("Failed to marshall 'CreateXMLSignatureResponse'", e); @@ -105,8 +100,8 @@ public class CreateXMLSignatureResultImpl extends SLResultImpl { } @Override - public void writeTo(Result result, Templates templates) { - writeTo(doc, result, templates); + public void writeTo(Result result, Templates templates, boolean fragment) { + writeTo(doc, result, templates, fragment); } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImpl.java index 5d0f0de0..aedde238 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImpl.java @@ -56,11 +56,11 @@ public class ErrorResultImpl extends SLResultImpl implements ErrorResult { } @Override - public void writeTo(Result result, Templates templates) { + public void writeTo(Result result, Templates templates, boolean fragment) { if (locale == null) { - writeErrorTo(slException, result, templates); + writeErrorTo(slException, result, templates, fragment); } else { - writeErrorTo(slException, result, templates, locale); + writeErrorTo(slException, result, templates, locale, fragment); } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/GetStatusCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/GetStatusCommandImpl.java index 46bfe18b..0c2b96f9 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/GetStatusCommandImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/GetStatusCommandImpl.java @@ -19,10 +19,8 @@ package at.gv.egiz.bku.slcommands.impl; import at.buergerkarte.namespaces.securitylayer._1.GetStatusRequestType; import at.gv.egiz.bku.slcommands.GetStatusCommand; -import at.gv.egiz.bku.slcommands.SLCommandContext; import at.gv.egiz.bku.slcommands.SLResult; import at.gv.egiz.bku.slexceptions.SLCommandException; -import at.gv.egiz.bku.slexceptions.SLException; import at.gv.egiz.stal.ErrorResponse; import at.gv.egiz.stal.STAL; import at.gv.egiz.stal.STALResponse; diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/GetStatusResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/GetStatusResultImpl.java index fddd3b0b..fb1f627f 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/GetStatusResultImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/GetStatusResultImpl.java @@ -45,8 +45,8 @@ public class GetStatusResultImpl extends SLResultImpl implements GetStatusResult } @Override - public void writeTo(Result result, Templates templates) { + public void writeTo(Result result, Templates templates, boolean fragment) { JAXBElement response = of.createGetStatusResponse(responseType); - writeTo(response, result, templates); + writeTo(response, result, templates, fragment); } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/IdentityLinkInfoboxImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/IdentityLinkInfoboxImpl.java index 7a82e43f..160e9589 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/IdentityLinkInfoboxImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/IdentityLinkInfoboxImpl.java @@ -18,7 +18,6 @@ package at.gv.egiz.bku.slcommands.impl; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.OutputStream; import java.net.MalformedURLException; import java.security.cert.X509Certificate; import java.util.ArrayList; diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadResultFileImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadResultFileImpl.java index 75e44afa..422b424f 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadResultFileImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadResultFileImpl.java @@ -16,8 +16,6 @@ */ package at.gv.egiz.bku.slcommands.impl; -import at.gv.egiz.marshal.NamespacePrefixMapperImpl; -import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; @@ -39,10 +37,8 @@ import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory; import at.buergerkarte.namespaces.securitylayer._1.XMLContentType; import at.gv.egiz.bku.slcommands.InfoboxReadResult; import at.gv.egiz.bku.slcommands.SLCommand; -import at.gv.egiz.bku.slcommands.SLCommandFactory; +import at.gv.egiz.bku.slcommands.SLMarshallerFactory; import at.gv.egiz.bku.slexceptions.SLRuntimeException; -import at.gv.egiz.marshal.MarshallerFactory; -import javax.xml.bind.PropertyException; /** * This class implements the result of the security layer command InfoboxReadRequest. @@ -98,10 +94,9 @@ public class InfoboxReadResultFileImpl extends SLResultImpl implements infoboxReadResponseType.setBinaryFileData(base64XMLContentType); JAXBElement infoboxReadResponse = factory.createInfoboxReadResponse(infoboxReadResponseType); - - JAXBContext context = SLCommandFactory.getInstance().getJaxbContext(); + + Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(false); try { - Marshaller marshaller = MarshallerFactory.createMarshaller(context); marshaller.marshal(infoboxReadResponse, doc); } catch (JAXBException e) { log.error("Failed to marshal 'InfoboxReadResponse' document.", e); @@ -158,8 +153,8 @@ public class InfoboxReadResultFileImpl extends SLResultImpl implements } @Override - public void writeTo(Result result, Templates templates) { - writeTo(xmlDocument, result, templates); + public void writeTo(Result result, Templates templates, boolean fragment) { + writeTo(xmlDocument, result, templates, fragment); } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadResultImpl.java index e508941d..271ec955 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadResultImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadResultImpl.java @@ -55,10 +55,10 @@ public class InfoboxReadResultImpl extends SLResultImpl implements InfoboxReadRe } @Override - public void writeTo(Result result, Templates templates) { + public void writeTo(Result result, Templates templates, boolean fragment) { ObjectFactory objectFactory = new ObjectFactory(); JAXBElement response = objectFactory.createInfoboxReadResponse(infoboxReadResponse); - writeTo(response, result, templates); + writeTo(response, result, templates, fragment); } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxUpdateResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxUpdateResultImpl.java index 15064756..e12536ba 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxUpdateResultImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxUpdateResultImpl.java @@ -36,8 +36,8 @@ public class InfoboxUpdateResultImpl extends SLResultImpl implements } @Override - public void writeTo(Result result, Templates templates) { - writeTo(RESPONSE, result, templates); + public void writeTo(Result result, Templates templates, boolean fragment) { + writeTo(RESPONSE, result, templates, fragment); } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/NullOperationResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/NullOperationResultImpl.java index 05986f85..87733e39 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/NullOperationResultImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/NullOperationResultImpl.java @@ -41,8 +41,8 @@ public class NullOperationResultImpl extends SLResultImpl implements NullOperati } @Override - public void writeTo(Result result, Templates templates) { - writeTo(RESPONSE, result, templates); + public void writeTo(Result result, Templates templates, boolean fragment) { + super.writeTo(RESPONSE, result, templates, fragment); } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLResultImpl.java index 0452bddf..0077b7b2 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLResultImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLResultImpl.java @@ -17,12 +17,14 @@ package at.gv.egiz.bku.slcommands.impl; import java.io.UnsupportedEncodingException; +import java.math.BigInteger; import java.util.Locale; -import javax.xml.bind.JAXBContext; +import javax.xml.XMLConstants; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; +import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Templates; import javax.xml.transform.Transformer; @@ -41,17 +43,15 @@ import org.w3c.dom.Node; import at.buergerkarte.namespaces.securitylayer._1.ErrorResponseType; import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory; -import at.gv.egiz.marshal.NamespacePrefixMapperImpl; -import at.gv.egiz.bku.slcommands.SLCommandFactory; +import at.gv.egiz.bku.slcommands.SLMarshallerFactory; import at.gv.egiz.bku.slcommands.SLResult; import at.gv.egiz.bku.slexceptions.SLBindingException; import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.bku.slexceptions.SLException; import at.gv.egiz.bku.slexceptions.SLRuntimeException; +import at.gv.egiz.bku.slexceptions.SLVersionException; import at.gv.egiz.bku.utils.DebugOutputStream; import at.gv.egiz.bku.utils.DebugWriter; -import at.gv.egiz.marshal.MarshallerFactory; -import javax.xml.bind.PropertyException; /** * This class serves as an abstract base class for the implementation of a @@ -90,20 +90,18 @@ public abstract class SLResultImpl implements SLResult { return resultingMimeType; } - private Marshaller getMarshaller() { - try { - JAXBContext context = SLCommandFactory.getInstance().getJaxbContext(); - Marshaller marshaller = MarshallerFactory.createMarshaller(context, true); - return marshaller; - } catch (JAXBException e) { - log.fatal("Failed to marshall error response.", e); - throw new SLRuntimeException("Failed to marshall error response.", e); - } + @Override + public void writeTo(Result result, boolean fragment) { + writeTo(result, null, false); } + @Override + public abstract void writeTo(Result result, Templates templates, boolean fragment); + private TransformerHandler getTransformerHandler(Templates templates, Result result) throws SLException { try { SAXTransformerFactory transformerFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); + transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); TransformerHandler transformerHandler = transformerFactory.newTransformerHandler(templates); transformerHandler.setResult(result); return transformerHandler; @@ -119,12 +117,6 @@ public abstract class SLResultImpl implements SLResult { } } - @Override - public void writeTo(Result result) { - writeTo(result, null); - } - - /** * Writes the given response to the SAX result using * the given transform templates. @@ -133,7 +125,7 @@ public abstract class SLResultImpl implements SLResult { * @param result * @param templates */ - protected void writeTo(JAXBElement response, Result result, Templates templates) { + protected void writeTo(JAXBElement response, Result result, Templates templates, boolean fragment) { DebugWriter dw = null; DebugOutputStream ds = null; @@ -154,11 +146,11 @@ public abstract class SLResultImpl implements SLResult { try { transformerHandler = getTransformerHandler(templates, result); } catch (SLException e) { - writeErrorTo(e, result, templates); + writeErrorTo(e, result, templates, fragment); } } - Marshaller marshaller = getMarshaller(); + Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(true); try { if (transformerHandler != null) { marshaller.marshal(response, transformerHandler); @@ -168,7 +160,7 @@ public abstract class SLResultImpl implements SLResult { } catch (JAXBException e) { log.info("Failed to marshall " + response.getName() + " result." , e); SLCommandException commandException = new SLCommandException(4000); - writeErrorTo(commandException, result, templates); + writeErrorTo(commandException, result, templates, fragment); } if (ds != null) { @@ -185,7 +177,7 @@ public abstract class SLResultImpl implements SLResult { } - protected void writeTo(Node node, Result result, Templates templates) { + protected void writeTo(Node node, Result result, Templates templates, boolean fragment) { DebugWriter dw = null; DebugOutputStream ds = null; @@ -205,24 +197,30 @@ public abstract class SLResultImpl implements SLResult { try { TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); + if (fragment) { + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + } transformer.transform(new DOMSource(node), result); } catch (TransformerConfigurationException e) { log.error("Failed to create Transformer.", e); - writeErrorTo(new SLException(4000), result, null); + writeErrorTo(new SLException(4000), result, null, fragment); } catch (TransformerException e) { log.error("Failed to transform result.", e); - writeErrorTo(new SLException(4000), result, null); + writeErrorTo(new SLException(4000), result, null, fragment); } } else { try { Transformer transformer = templates.newTransformer(); + if (fragment) { + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + } transformer.transform(new DOMSource(node), result); } catch (TransformerConfigurationException e) { log.info("Failed to create transformer.", e); - writeErrorTo(new SLException(2008), result, templates); + writeErrorTo(new SLException(2008), result, templates, fragment); } catch (TransformerException e) { log.error("Failed to transform result.", e); - writeErrorTo(new SLException(2008), result, templates); + writeErrorTo(new SLException(2008), result, templates, fragment); } } @@ -240,11 +238,11 @@ public abstract class SLResultImpl implements SLResult { } - protected void writeErrorTo(SLException slException, Result result, Templates templates) { - writeErrorTo(slException, result, templates, Locale.getDefault()); + protected void writeErrorTo(SLException slException, Result result, Templates templates, boolean fragment) { + writeErrorTo(slException, result, templates, Locale.getDefault(), fragment); } - protected void writeErrorTo(SLException slException, Result result, Templates templates, Locale locale) { + protected void writeErrorTo(SLException slException, Result result, Templates templates, Locale locale, boolean fragment) { TransformerHandler transformerHandler = null; if (templates != null) { @@ -256,13 +254,33 @@ public abstract class SLResultImpl implements SLResult { } } - ObjectFactory factory = new ObjectFactory(); - ErrorResponseType responseType = factory.createErrorResponseType(); - responseType.setErrorCode(slException.getErrorCode()); - responseType.setInfo(slException.getLocalizedMessage(locale)); - JAXBElement response = factory.createErrorResponse(responseType); + Object response; + + Marshaller marshaller; + if (slException instanceof SLVersionException + && ("http://www.buergerkarte.at/namespaces/securitylayer/20020225#" + .equals(((SLVersionException) slException).getNamespaceURI()) || + "http://www.buergerkarte.at/namespaces/securitylayer/20020831#" + .equals(((SLVersionException) slException).getNamespaceURI()))) { + // issue ErrorResponse in the legacy namespace + at.buergerkarte.namespaces.securitylayer._20020225_.ObjectFactory factory + = new at.buergerkarte.namespaces.securitylayer._20020225_.ObjectFactory(); + at.buergerkarte.namespaces.securitylayer._20020225_.ErrorResponseType errorResponseType = factory + .createErrorResponseType(); + errorResponseType.setErrorCode(BigInteger.valueOf(slException + .getErrorCode())); + errorResponseType.setInfo(slException.getLocalizedMessage(locale)); + response = factory.createErrorResponse(errorResponseType); + marshaller = SLMarshallerFactory.getInstance().createLegacyMarshaller(true, fragment); + } else { + ObjectFactory factory = new ObjectFactory(); + ErrorResponseType responseType = factory.createErrorResponseType(); + responseType.setErrorCode(slException.getErrorCode()); + responseType.setInfo(slException.getLocalizedMessage(locale)); + response = factory.createErrorResponse(responseType); + marshaller = SLMarshallerFactory.getInstance().createMarshaller(true, fragment); + } - Marshaller marshaller = getMarshaller(); try { if (transformerHandler != null) { marshaller.marshal(response, transformerHandler); diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java index b64306aa..2088a684 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java @@ -81,7 +81,6 @@ import at.gv.egiz.bku.viewer.ValidationException; import at.gv.egiz.bku.viewer.Validator; import at.gv.egiz.bku.viewer.ValidatorFactory; import at.gv.egiz.dom.DOMUtils; -import at.gv.egiz.marshal.NamespacePrefix; import at.gv.egiz.marshal.NamespacePrefixMapperImpl; import at.gv.egiz.slbinding.impl.XMLContentType; import javax.xml.namespace.NamespaceContext; diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java index 9182e824..26ddb153 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java @@ -16,7 +16,6 @@ */ package at.gv.egiz.bku.slcommands.impl.xsect; -import at.gv.egiz.stal.HashDataInput; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -31,9 +30,7 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.Date; -import java.util.HashMap; import java.util.List; -import java.util.Map; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; @@ -87,8 +84,6 @@ import at.gv.egiz.bku.utils.urldereferencer.StreamData; import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerContext; import at.gv.egiz.dom.DOMUtils; -import at.gv.egiz.marshal.NamespacePrefix; -import at.gv.egiz.marshal.NamespacePrefixMapperImpl; import at.gv.egiz.slbinding.impl.XMLContentType; import at.gv.egiz.stal.STAL; import at.gv.egiz.xades.QualifyingPropertiesException; @@ -327,6 +322,8 @@ public class Signature { */ public void buildXMLSignature() throws SLCommandException { + String signatureId = ctx.getIdValueFactory().createIdValue("Signature"); + List objects = new ArrayList(); List references = new ArrayList(); @@ -340,7 +337,7 @@ public class Signature { } } - addXAdESObjectAndReference(objects, references); + addXAdESObjectAndReference(objects, references, signatureId); XMLSignatureFactory signatureFactory = ctx.getSignatureFactory(); AlgorithmMethodFactory algorithmMethodFactory = ctx.getAlgorithmMethodFactory(); @@ -369,7 +366,6 @@ public class Signature { ki = kif.newKeyInfo(Collections.singletonList(x509Data)); } - String signatureId = ctx.getIdValueFactory().createIdValue("Signature"); String signatureValueId = ctx.getIdValueFactory().createIdValue("SignatureValue"); xmlSignature = signatureFactory.newXMLSignature(si, ki, objects, signatureId, signatureValueId); @@ -588,7 +584,7 @@ public class Signature { * @param references * the list of ds:References to add the created * ds:Reference to - * + * @param signatureId TODO * @throws SLCommandException * if creating and adding the XAdES * QualifyingProperties fails @@ -596,7 +592,7 @@ public class Signature { * if objects or references is * null */ - private void addXAdESObjectAndReference(List objects, List references) throws SLCommandException { + private void addXAdESObjectAndReference(List objects, List references, String signatureId) throws SLCommandException { QualifyingPropertiesFactory factory = QualifyingPropertiesFactory.getInstance(); @@ -630,9 +626,11 @@ public class Signature { } } + String target = "#" + signatureId; + JAXBElement qualifyingProperties; try { - qualifyingProperties = factory.createQualifyingProperties111(date, signingCertificates, idValue, dataObjectFormats); + qualifyingProperties = factory.createQualifyingProperties111(target, date, signingCertificates, idValue, dataObjectFormats); } catch (QualifyingPropertiesException e) { log.error("Failed to create QualifyingProperties.", e); throw new SLCommandException(4000); diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLExceptionMessages.java b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLExceptionMessages.java index 5ce5cba1..73ac8d1b 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLExceptionMessages.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLExceptionMessages.java @@ -47,4 +47,10 @@ public final class SLExceptionMessages { public static final String EC4011_NOTIMPLEMENTED = "ec4011.notimplemented"; + // + // Legacy error codes + // + + public static final String LEC2901_NOTIMPLEMENTED = "lec2901.notimplemented"; + } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLVersionException.java b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLVersionException.java new file mode 100644 index 00000000..45501746 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLVersionException.java @@ -0,0 +1,28 @@ +package at.gv.egiz.bku.slexceptions; + +public class SLVersionException extends SLException { + + private static final long serialVersionUID = 1L; + + protected String namespaceURI; + + public SLVersionException(String namespaceURI) { + super(2901, SLExceptionMessages.LEC2901_NOTIMPLEMENTED, new Object[] {namespaceURI}); + this.namespaceURI = namespaceURI; + } + + public SLVersionException(int errorCode, String namespaceURI) { + super(errorCode); + this.namespaceURI = namespaceURI; + } + + public SLVersionException(int errorCode, String namespaceURI, String message, Object[] arguments) { + super(errorCode, message, arguments); + this.namespaceURI = namespaceURI; + } + + public String getNamespaceURI() { + return namespaceURI; + } + +} diff --git a/bkucommon/src/main/resources/at/gv/egiz/bku/slcommands/schema/Core.20020225.xsd b/bkucommon/src/main/resources/at/gv/egiz/bku/slcommands/schema/Core.20020225.xsd new file mode 100644 index 00000000..76d1d7cb --- /dev/null +++ b/bkucommon/src/main/resources/at/gv/egiz/bku/slcommands/schema/Core.20020225.xsd @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bkucommon/src/main/resources/at/gv/egiz/bku/slcommands/schema/Core.20020831.xsd b/bkucommon/src/main/resources/at/gv/egiz/bku/slcommands/schema/Core.20020831.xsd new file mode 100644 index 00000000..6759d791 --- /dev/null +++ b/bkucommon/src/main/resources/at/gv/egiz/bku/slcommands/schema/Core.20020831.xsd @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages.properties b/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages.properties index 73409c8b..db56184e 100644 --- a/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages.properties +++ b/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages.properties @@ -95,5 +95,10 @@ ec4000.infobox.invalid=Die Infobox '{0}' enth ec4000.idlink.transfomation.failed=Die komprimierte Personenbindung konnte mit dem Stylesheet {0} nicht transformiert werden. ec4002.infobox.unknown=Unbekannter Infoboxbezeichner {0}. ec4003.not.resolved=Zu signierendes Datum kann nicht aufgelöst werden (URI={0}). -ec4011.notimplemented=Befehl {0} ist nicht implementiert. +ec4011.notimplemented=Befehl {0} ist nicht implementiert. + +# Legacy error messages +# + +lec2901.notimplemented=Die in der Anfrage verwendete Version des Security-Layer Protokolls ({0}) wird nicht mehr unterstützt. diff --git a/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages_en.properties b/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages_en.properties index 91ca20e8..6c67ba87 100644 --- a/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages_en.properties +++ b/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages_en.properties @@ -96,3 +96,7 @@ ec4000.idlink.transfomation.failed=Failed to transform CompressedIdentityLink wi ec4002.infobox.unknown=Unknown info box identifier {0}. ec4003.not.resolved=Data to be signed cannot be resolved from URI={0}. ec4011.notimplemented=Command {0} not implemented. + +# Legacy error codes +# +lec2901.notimplemented=The version ({0}) of the security-layer protocol used in the request is not supported. diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/binding/XWWWFormUrlInputIteratorTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/binding/XWWWFormUrlInputIteratorTest.java new file mode 100644 index 00000000..703e4460 --- /dev/null +++ b/bkucommon/src/test/java/at/gv/egiz/bku/binding/XWWWFormUrlInputIteratorTest.java @@ -0,0 +1,152 @@ +package at.gv.egiz.bku.binding; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.URLEncoder; +import java.nio.charset.Charset; + +import org.junit.Ignore; +import org.junit.Test; +import static org.junit.Assert.*; + +public class XWWWFormUrlInputIteratorTest { + + @Test + public void testOneParam() throws IOException { + + final String name = "name"; + final String value = "value"; + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + OutputStreamWriter w = new OutputStreamWriter(os, Charset.forName("UTF-8")); + w.write(name); + w.write("="); + w.write(value); + w.flush(); + w.close(); + + ByteArrayInputStream in = new ByteArrayInputStream(os.toByteArray()); + XWWWFormUrlInputIterator decoder = new XWWWFormUrlInputIterator(in); + + assertTrue(decoder.hasNext()); + FormParameter param = decoder.next(); + assertNotNull(param); + assertEquals(name, param.getFormParameterName()); + InputStream vis = param.getFormParameterValue(); + assertNotNull(vis); + InputStreamReader r = new InputStreamReader(vis); + char[] buf = new char[value.length() + 1]; + int len = r.read(buf); + assertEquals(value.length(), len); + assertEquals(value, new String(buf, 0, len)); + assertFalse(decoder.hasNext()); + Exception ex = null; + try { + decoder.next(); + } catch (Exception e) { + ex = e; + } + assertNotNull(ex); + + } + + @Test + public void testTwoParam() throws IOException { + + final String name1 = "name"; + final String value1 = "value"; + final String name2 = "Name_2"; + final String value2 = "Value 2"; + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + OutputStreamWriter w = new OutputStreamWriter(os, Charset.forName("UTF-8")); + w.write(name1); + w.write("="); + w.write(value1); + w.write("&"); + w.write(URLEncoder.encode(name2, "UTF-8")); + w.write("="); + w.write(URLEncoder.encode(value2, "UTF-8")); + w.flush(); + w.close(); + + ByteArrayInputStream in = new ByteArrayInputStream(os.toByteArray()); + XWWWFormUrlInputIterator decoder = new XWWWFormUrlInputIterator(in); + + assertTrue(decoder.hasNext()); + FormParameter param = decoder.next(); + assertNotNull(param); + assertEquals(name1, param.getFormParameterName()); + InputStream vis = param.getFormParameterValue(); + assertNotNull(vis); + InputStreamReader r = new InputStreamReader(vis); + char[] buf = new char[value1.length() + 1]; + int len = r.read(buf); + assertEquals(value1.length(), len); + assertEquals(value1, new String(buf, 0, len)); + + assertTrue(decoder.hasNext()); + param = decoder.next(); + assertNotNull(param); + assertEquals(name2, param.getFormParameterName()); + vis = param.getFormParameterValue(); + assertNotNull(vis); + r = new InputStreamReader(vis); + buf = new char[value2.length() + 1]; + len = r.read(buf); + assertEquals(value2.length(), len); + assertEquals(value2, new String(buf, 0, len)); + + assertFalse(decoder.hasNext()); + } + + @Test + public void testURLEnc() throws IOException { + + String name = "name"; + byte[] value = new byte[128]; + for (int i = 0; i < value.length; i++) { + value[i] = (byte) i; + } + + String encValue = URLEncoder.encode(new String(value, "UTF-8"), "ASCII"); + System.out.println(encValue); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + OutputStreamWriter w = new OutputStreamWriter(os, Charset.forName("UTF-8")); + w.write(name); + w.write("="); + w.write(encValue); + w.flush(); + w.close(); + + ByteArrayInputStream in = new ByteArrayInputStream(os.toByteArray()); + XWWWFormUrlInputIterator decoder = new XWWWFormUrlInputIterator(in); + + assertTrue(decoder.hasNext()); + FormParameter param = decoder.next(); + assertNotNull(param); + assertEquals(name, param.getFormParameterName()); + InputStream vis = param.getFormParameterValue(); + assertNotNull(vis); + byte[] buf = new byte[value.length]; + int len = vis.read(buf); + assertArrayEquals(value, buf); + assertEquals(value.length, len); + assertFalse(decoder.hasNext()); + Exception ex = null; + try { + decoder.next(); + } catch (Exception e) { + ex = e; + } + assertNotNull(ex); + + } + + +} diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/SLCommandFactoryTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/SLCommandFactoryTest.java index cd931878..7a087b38 100644 --- a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/SLCommandFactoryTest.java +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/SLCommandFactoryTest.java @@ -33,6 +33,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.bku.slexceptions.SLRequestException; import at.gv.egiz.bku.slexceptions.SLRuntimeException; +import at.gv.egiz.bku.slexceptions.SLVersionException; import at.gv.egiz.stal.dummy.DummySTAL; public class SLCommandFactoryTest { @@ -54,7 +55,7 @@ public class SLCommandFactoryTest { } @Test - public void createNullOperationCommand() throws SLCommandException, SLRuntimeException, SLRequestException { + public void createNullOperationCommand() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { Reader requestReader = new StringReader( ""); Source source = new StreamSource(requestReader); @@ -65,7 +66,7 @@ public class SLCommandFactoryTest { } @Test(expected=SLCommandException.class) - public void createUnsupportedCommand() throws SLCommandException, SLRuntimeException, SLRequestException { + public void createUnsupportedCommand() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { Reader requestReader = new StringReader( ""); Source source = new StreamSource(requestReader); @@ -75,7 +76,7 @@ public class SLCommandFactoryTest { } @Test(expected=SLRequestException.class) - public void createMalformedCommand() throws SLCommandException, SLRuntimeException, SLRequestException { + public void createMalformedCommand() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { Reader requestReader = new StringReader( "" + "missplacedContent" + diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureComandImplTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureComandImplTest.java index 8fdec375..4e9b4cd7 100644 --- a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureComandImplTest.java +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureComandImplTest.java @@ -41,6 +41,7 @@ import at.gv.egiz.bku.slcommands.impl.xsect.STALProvider; import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.bku.slexceptions.SLRequestException; import at.gv.egiz.bku.slexceptions.SLRuntimeException; +import at.gv.egiz.bku.slexceptions.SLVersionException; import at.gv.egiz.stal.STAL; import at.gv.egiz.stal.dummy.DummySTAL; //@Ignore @@ -66,7 +67,7 @@ public class CreateXMLSignatureComandImplTest { } @Test - public void testCreateXMLSignatureRequest() throws SLCommandException, SLRuntimeException, SLRequestException { + public void testCreateXMLSignatureRequest() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/createxmlsignaturerequest/CreateXMLSignatureRequest.xml"); assertNotNull(inputStream); @@ -76,11 +77,11 @@ public class CreateXMLSignatureComandImplTest { assertTrue(command instanceof CreateXMLSignatureCommand); SLResult result = command.execute(); - result.writeTo(new StreamResult(System.out)); + result.writeTo(new StreamResult(System.out), false); } // @Test(expected=SLCommandException.class) - public void testInfboxReadRequestInvalid1() throws SLCommandException, SLRuntimeException, SLRequestException { + public void testInfboxReadRequestInvalid1() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/infoboxreadcommand/IdentityLink.Binary.Invalid-1.xml"); assertNotNull(inputStream); @@ -90,7 +91,7 @@ public class CreateXMLSignatureComandImplTest { } // @Test(expected=SLCommandException.class) - public void testInfboxReadRequestInvalid2() throws SLCommandException, SLRuntimeException, SLRequestException { + public void testInfboxReadRequestInvalid2() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/infoboxreadcommand/IdentityLink.Binary.Invalid-2.xml"); assertNotNull(inputStream); diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImplTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImplTest.java index f10ca520..aa2bcd62 100644 --- a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImplTest.java +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImplTest.java @@ -36,7 +36,7 @@ public class ErrorResultImplTest { ByteArrayOutputStream stream = new ByteArrayOutputStream(); StreamResult result = new StreamResult(stream); - errorResult.writeTo(result); + errorResult.writeTo(result, false); System.out.println(stream.toString()); diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadComandImplTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadComandImplTest.java index b0d11d47..bfc784f7 100644 --- a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadComandImplTest.java +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadComandImplTest.java @@ -39,6 +39,7 @@ import at.gv.egiz.bku.slcommands.SLResult; import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.bku.slexceptions.SLRequestException; import at.gv.egiz.bku.slexceptions.SLRuntimeException; +import at.gv.egiz.bku.slexceptions.SLVersionException; import at.gv.egiz.stal.STAL; import at.gv.egiz.stal.dummy.DummySTAL; @@ -63,7 +64,7 @@ public class InfoboxReadComandImplTest { } @Test - public void testInfboxReadRequest() throws SLCommandException, SLRuntimeException, SLRequestException { + public void testInfboxReadRequest() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/infoboxreadcommand/IdentityLink.Binary.xml"); assertNotNull(inputStream); @@ -73,11 +74,11 @@ public class InfoboxReadComandImplTest { assertTrue(command instanceof InfoboxReadCommand); SLResult result = command.execute(); - result.writeTo(new StreamResult(System.out)); + result.writeTo(new StreamResult(System.out), false); } @Test(expected=SLCommandException.class) - public void testInfboxReadRequestInvalid1() throws SLCommandException, SLRuntimeException, SLRequestException { + public void testInfboxReadRequestInvalid1() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/infoboxreadcommand/IdentityLink.Binary.Invalid-1.xml"); assertNotNull(inputStream); @@ -87,7 +88,7 @@ public class InfoboxReadComandImplTest { assertTrue(command instanceof InfoboxReadCommand); } - public void testInfboxReadRequestInvalid2() throws SLCommandException, SLRuntimeException, SLRequestException { + public void testInfboxReadRequestInvalid2() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/infoboxreadcommand/IdentityLink.Binary.Invalid-2.xml"); assertNotNull(inputStream); diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/NullOperationResultImplTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/NullOperationResultImplTest.java index 8632b67c..e9b0775f 100644 --- a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/NullOperationResultImplTest.java +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/NullOperationResultImplTest.java @@ -33,7 +33,7 @@ public class NullOperationResultImplTest { ByteArrayOutputStream stream = new ByteArrayOutputStream(); StreamResult result = new StreamResult(stream); - nullOperationResult.writeTo(result); + nullOperationResult.writeTo(result, false); System.out.println(stream.toString()); diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImplTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImplTest.java index f9c60b86..a17f0797 100644 --- a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImplTest.java +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImplTest.java @@ -23,7 +23,6 @@ import iaik.asn1.CodingException; import java.io.IOException; import java.io.InputStream; -import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; @@ -42,10 +41,12 @@ import at.gv.egiz.bku.slcommands.InfoboxReadCommand; import at.gv.egiz.bku.slcommands.SLCommand; import at.gv.egiz.bku.slcommands.SLCommandContext; import at.gv.egiz.bku.slcommands.SLCommandFactory; +import at.gv.egiz.bku.slcommands.SLMarshallerFactory; import at.gv.egiz.bku.slcommands.SLResult; import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.bku.slexceptions.SLRequestException; import at.gv.egiz.bku.slexceptions.SLRuntimeException; +import at.gv.egiz.bku.slexceptions.SLVersionException; import at.gv.egiz.stal.STAL; import at.gv.egiz.stal.dummy.DummySTAL; @@ -93,9 +94,7 @@ public class SVPersonendatenInfoboxImplTest { JAXBElement ehic = new ObjectFactory().createEHIC(attributeList); - JAXBContext jaxbContext = SLCommandFactory.getInstance().getJaxbContext(); - - Marshaller marshaller = jaxbContext.createMarshaller(); + Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(false); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); @@ -105,7 +104,7 @@ public class SVPersonendatenInfoboxImplTest { @Ignore @Test - public void testInfboxReadRequest() throws SLCommandException, SLRuntimeException, SLRequestException { + public void testInfboxReadRequest() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/infoboxreadcommand/IdentityLink.Binary.xml"); assertNotNull(inputStream); @@ -115,12 +114,12 @@ public class SVPersonendatenInfoboxImplTest { assertTrue(command instanceof InfoboxReadCommand); SLResult result = command.execute(); - result.writeTo(new StreamResult(System.out)); + result.writeTo(new StreamResult(System.out), false); } @Ignore @Test(expected=SLCommandException.class) - public void testInfboxReadRequestInvalid1() throws SLCommandException, SLRuntimeException, SLRequestException { + public void testInfboxReadRequestInvalid1() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/infoboxreadcommand/IdentityLink.Binary.Invalid-1.xml"); assertNotNull(inputStream); @@ -131,7 +130,7 @@ public class SVPersonendatenInfoboxImplTest { } @Ignore - public void testInfboxReadRequestInvalid2() throws SLCommandException, SLRuntimeException, SLRequestException { + public void testInfboxReadRequestInvalid2() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/infoboxreadcommand/IdentityLink.Binary.Invalid-2.xml"); assertNotNull(inputStream); diff --git a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1/TransformsInfoType.java b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1/TransformsInfoType.java index 5ee40b95..e4a8f48e 100644 --- a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1/TransformsInfoType.java +++ b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1/TransformsInfoType.java @@ -24,11 +24,15 @@ package at.buergerkarte.namespaces.securitylayer._1; +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.XmlElement; +import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlType; import org.w3._2000._09.xmldsig_.TransformsType; +import org.w3c.dom.Element; /** @@ -58,8 +62,9 @@ import org.w3._2000._09.xmldsig_.TransformsType; }) public class TransformsInfoType { - @XmlElement(name = "Transforms", namespace = "http://www.w3.org/2000/09/xmldsig#") - protected TransformsType transforms; + @XmlElementRef(name = "Transforms", namespace = "http://www.w3.org/2000/09/xmldsig#", type = JAXBElement.class) + @XmlAnyElement(lax = true) + protected Object transforms; @XmlElement(name = "FinalDataMetaInfo", required = true) protected MetaInfoType finalDataMetaInfo; @@ -68,10 +73,12 @@ public class TransformsInfoType { * * @return * possible object is - * {@link TransformsType } + * {@link JAXBElement }{@code <}{@link String }{@code >} + * {@link Object } + * {@link Element } * */ - public TransformsType getTransforms() { + public Object getTransforms() { return transforms; } @@ -80,10 +87,12 @@ public class TransformsInfoType { * * @param value * allowed object is - * {@link TransformsType } + * {@link JAXBElement }{@code <}{@link String }{@code >} + * {@link Object } + * {@link Element } * */ - public void setTransforms(TransformsType value) { + public void setTransforms(Object value) { this.transforms = value; } diff --git a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020225_/ErrorResponseType.java b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020225_/ErrorResponseType.java new file mode 100644 index 00000000..69b5cd9d --- /dev/null +++ b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020225_/ErrorResponseType.java @@ -0,0 +1,98 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.2-b01-fcs +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2009.09.07 at 09:47:31 AM CEST +// + + +package at.buergerkarte.namespaces.securitylayer._20020225_; + +import java.math.BigInteger; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for ErrorResponseType complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="ErrorResponseType">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="ErrorCode" type="{http://www.w3.org/2001/XMLSchema}integer"/>
+ *         <element name="Info" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "ErrorResponseType", propOrder = { + "errorCode", + "info" +}) +public class ErrorResponseType { + + @XmlElement(name = "ErrorCode", required = true) + protected BigInteger errorCode; + @XmlElement(name = "Info", required = true) + protected String info; + + /** + * Gets the value of the errorCode property. + * + * @return + * possible object is + * {@link BigInteger } + * + */ + public BigInteger getErrorCode() { + return errorCode; + } + + /** + * Sets the value of the errorCode property. + * + * @param value + * allowed object is + * {@link BigInteger } + * + */ + public void setErrorCode(BigInteger value) { + this.errorCode = value; + } + + /** + * Gets the value of the info property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getInfo() { + return info; + } + + /** + * Sets the value of the info property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setInfo(String value) { + this.info = value; + } + +} diff --git a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020225_/ObjectFactory.java b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020225_/ObjectFactory.java new file mode 100644 index 00000000..a02f9ca1 --- /dev/null +++ b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020225_/ObjectFactory.java @@ -0,0 +1,280 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.2-b01-fcs +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2009.09.07 at 09:47:31 AM CEST +// + + +package at.buergerkarte.namespaces.securitylayer._20020225_; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlElementDecl; +import javax.xml.bind.annotation.XmlRegistry; +import javax.xml.namespace.QName; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the at.buergerkarte.namespaces.securitylayer._20020225_ package. + *

An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + private final static QName _CreateXMLSignatureRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "CreateXMLSignatureRequest"); + private final static QName _InfoboxUpdateRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "InfoboxUpdateRequest"); + private final static QName _ErrorResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "ErrorResponse"); + private final static QName _VerifyXMLSignatureResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "VerifyXMLSignatureResponse"); + private final static QName _CreateSessionKeyResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "CreateSessionKeyResponse"); + private final static QName _GetPropertiesRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "GetPropertiesRequest"); + private final static QName _GetPropertiesResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "GetPropertiesResponse"); + private final static QName _InfoboxAvailableResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "InfoboxAvailableResponse"); + private final static QName _InfoboxAvailableRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "InfoboxAvailableRequest"); + private final static QName _CreateSessionKeyRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "CreateSessionKeyRequest"); + private final static QName _InfoboxUpdateResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "InfoboxUpdateResponse"); + private final static QName _CreateXMLSignatureResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "CreateXMLSignatureResponse"); + private final static QName _GetStatusResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "GetStatusResponse"); + private final static QName _CreateCMSSignatureRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "CreateCMSSignatureRequest"); + private final static QName _CreateSymmetricSecretRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "CreateSymmetricSecretRequest"); + private final static QName _VerifyXMLSignatureRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "VerifyXMLSignatureRequest"); + private final static QName _CreateSymmetricSecretResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "CreateSymmetricSecretResponse"); + private final static QName _CreateCMSSignatureResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "CreateCMSSignatureResponse"); + private final static QName _VerifyCMSSignatureResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "VerifyCMSSignatureResponse"); + private final static QName _InfoboxReadResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "InfoboxReadResponse"); + private final static QName _VerifyCMSSignatureRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "VerifyCMSSignatureRequest"); + private final static QName _InfoboxReadRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "InfoboxReadRequest"); + private final static QName _GetStatusRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "GetStatusRequest"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: at.buergerkarte.namespaces.securitylayer._20020225_ + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link ErrorResponseType } + * + */ + public ErrorResponseType createErrorResponseType() { + return new ErrorResponseType(); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "CreateXMLSignatureRequest") + public JAXBElement createCreateXMLSignatureRequest(Object value) { + return new JAXBElement(_CreateXMLSignatureRequest_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "InfoboxUpdateRequest") + public JAXBElement createInfoboxUpdateRequest(Object value) { + return new JAXBElement(_InfoboxUpdateRequest_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link ErrorResponseType }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "ErrorResponse") + public JAXBElement createErrorResponse(ErrorResponseType value) { + return new JAXBElement(_ErrorResponse_QNAME, ErrorResponseType.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "VerifyXMLSignatureResponse") + public JAXBElement createVerifyXMLSignatureResponse(Object value) { + return new JAXBElement(_VerifyXMLSignatureResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "CreateSessionKeyResponse") + public JAXBElement createCreateSessionKeyResponse(Object value) { + return new JAXBElement(_CreateSessionKeyResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "GetPropertiesRequest") + public JAXBElement createGetPropertiesRequest(Object value) { + return new JAXBElement(_GetPropertiesRequest_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "GetPropertiesResponse") + public JAXBElement createGetPropertiesResponse(Object value) { + return new JAXBElement(_GetPropertiesResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "InfoboxAvailableResponse") + public JAXBElement createInfoboxAvailableResponse(Object value) { + return new JAXBElement(_InfoboxAvailableResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "InfoboxAvailableRequest") + public JAXBElement createInfoboxAvailableRequest(Object value) { + return new JAXBElement(_InfoboxAvailableRequest_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "CreateSessionKeyRequest") + public JAXBElement createCreateSessionKeyRequest(Object value) { + return new JAXBElement(_CreateSessionKeyRequest_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "InfoboxUpdateResponse") + public JAXBElement createInfoboxUpdateResponse(Object value) { + return new JAXBElement(_InfoboxUpdateResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "CreateXMLSignatureResponse") + public JAXBElement createCreateXMLSignatureResponse(Object value) { + return new JAXBElement(_CreateXMLSignatureResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "GetStatusResponse") + public JAXBElement createGetStatusResponse(Object value) { + return new JAXBElement(_GetStatusResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "CreateCMSSignatureRequest") + public JAXBElement createCreateCMSSignatureRequest(Object value) { + return new JAXBElement(_CreateCMSSignatureRequest_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "CreateSymmetricSecretRequest") + public JAXBElement createCreateSymmetricSecretRequest(Object value) { + return new JAXBElement(_CreateSymmetricSecretRequest_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "VerifyXMLSignatureRequest") + public JAXBElement createVerifyXMLSignatureRequest(Object value) { + return new JAXBElement(_VerifyXMLSignatureRequest_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "CreateSymmetricSecretResponse") + public JAXBElement createCreateSymmetricSecretResponse(Object value) { + return new JAXBElement(_CreateSymmetricSecretResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "CreateCMSSignatureResponse") + public JAXBElement createCreateCMSSignatureResponse(Object value) { + return new JAXBElement(_CreateCMSSignatureResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "VerifyCMSSignatureResponse") + public JAXBElement createVerifyCMSSignatureResponse(Object value) { + return new JAXBElement(_VerifyCMSSignatureResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "InfoboxReadResponse") + public JAXBElement createInfoboxReadResponse(Object value) { + return new JAXBElement(_InfoboxReadResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "VerifyCMSSignatureRequest") + public JAXBElement createVerifyCMSSignatureRequest(Object value) { + return new JAXBElement(_VerifyCMSSignatureRequest_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "InfoboxReadRequest") + public JAXBElement createInfoboxReadRequest(Object value) { + return new JAXBElement(_InfoboxReadRequest_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", name = "GetStatusRequest") + public JAXBElement createGetStatusRequest(Object value) { + return new JAXBElement(_GetStatusRequest_QNAME, Object.class, null, value); + } + +} diff --git a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020225_/package-info.java b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020225_/package-info.java new file mode 100644 index 00000000..084f6b11 --- /dev/null +++ b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020225_/package-info.java @@ -0,0 +1,9 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.2-b01-fcs +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2009.09.07 at 09:47:31 AM CEST +// + +@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020225#", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) +package at.buergerkarte.namespaces.securitylayer._20020225_; diff --git a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020831_/ObjectFactory.java b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020831_/ObjectFactory.java new file mode 100644 index 00000000..17f6d4b4 --- /dev/null +++ b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_20020831_/ObjectFactory.java @@ -0,0 +1,112 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.2-b01-fcs +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2009.09.07 at 09:47:31 AM CEST +// + + +package at.buergerkarte.namespaces.securitylayer._20020831_; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlElementDecl; +import javax.xml.bind.annotation.XmlRegistry; +import javax.xml.namespace.QName; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the at.buergerkarte.namespaces.securitylayer._20020831_ package. + *

An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + private final static QName _CreateXMLSignatureRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020831#", "CreateXMLSignatureRequest"); + private final static QName _GetPropertiesResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020831#", "GetPropertiesResponse"); + private final static QName _VerifyXMLSignatureResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020831#", "VerifyXMLSignatureResponse"); + private final static QName _VerifyXMLSignatureRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020831#", "VerifyXMLSignatureRequest"); + private final static QName _VerifyCMSSignatureResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020831#", "VerifyCMSSignatureResponse"); + private final static QName _CreateXMLSignatureResponse_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020831#", "CreateXMLSignatureResponse"); + private final static QName _VerifyCMSSignatureRequest_QNAME = new QName("http://www.buergerkarte.at/namespaces/securitylayer/20020831#", "VerifyCMSSignatureRequest"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: at.buergerkarte.namespaces.securitylayer._20020831_ + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020831#", name = "CreateXMLSignatureRequest") + public JAXBElement createCreateXMLSignatureRequest(Object value) { + return new JAXBElement(_CreateXMLSignatureRequest_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020831#", name = "GetPropertiesResponse") + public JAXBElement createGetPropertiesResponse(Object value) { + return new JAXBElement(_GetPropertiesResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020831#", name = "VerifyXMLSignatureResponse") + public JAXBElement createVerifyXMLSignatureResponse(Object value) { + return new JAXBElement(_VerifyXMLSignatureResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020831#", name = "VerifyXMLSignatureRequest") + public JAXBElement createVerifyXMLSignatureRequest(Object value) { + return new JAXBElement(_VerifyXMLSignatureRequest_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020831#", name = "VerifyCMSSignatureResponse") + public JAXBElement createVerifyCMSSignatureResponse(Object value) { + return new JAXBElement(_VerifyCMSSignatureResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020831#", name = "CreateXMLSignatureResponse") + public JAXBElement createCreateXMLSignatureResponse(Object value) { + return new JAXBElement(_CreateXMLSignatureResponse_QNAME, Object.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Object }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.buergerkarte.at/namespaces/securitylayer/20020831#", name = "VerifyCMSSignatureRequest") + public JAXBElement createVerifyCMSSignatureRequest(Object value) { + return new JAXBElement(_VerifyCMSSignatureRequest_QNAME, Object.class, null, value); + } + +} diff --git a/utils/src/main/java/at/gv/egiz/bku/utils/URLEncodingInputStream.java b/utils/src/main/java/at/gv/egiz/bku/utils/URLEncodingInputStream.java new file mode 100644 index 00000000..28ef6b88 --- /dev/null +++ b/utils/src/main/java/at/gv/egiz/bku/utils/URLEncodingInputStream.java @@ -0,0 +1,62 @@ +/** + * + */ +package at.gv.egiz.bku.utils; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.CharBuffer; + +/** + * @author mcentner + * + */ +public class URLEncodingInputStream extends InputStream { + + private char[] buffer = new char[1]; + + private CharBuffer charBuffer = CharBuffer.wrap(buffer); + + protected Readable in; + + /** + * @param in + */ + public URLEncodingInputStream(Readable in) { + this.in = in; + } + + /* (non-Javadoc) + * @see java.io.InputStream#read() + */ + @Override + public int read() throws IOException { + charBuffer.rewind(); + if (in.read(charBuffer) == -1) { + return -1; + } + if (buffer[0] == '+') { + return ' '; + } else if (buffer[0] == '%') { + charBuffer.rewind(); + if (in.read(charBuffer) == -1) { + throw new IOException("Invalid URL encoding."); + } + int c1 = Character.digit(buffer[0], 16); + charBuffer.rewind(); + if (in.read(charBuffer) == -1) { + throw new IOException("Invalid URL encoding."); + } + int c2 = Character.digit(buffer[0], 16); + if (c1 == -1 || c2 == -1) { + throw new IOException("Invalid URL encoding."); + } + return ((c1 << 4) | c2); + } else { + return buffer[0]; + } + } + + + +} diff --git a/utils/src/main/java/at/gv/egiz/bku/utils/URLEncodingOutputStream.java b/utils/src/main/java/at/gv/egiz/bku/utils/URLEncodingOutputStream.java new file mode 100644 index 00000000..df42df6d --- /dev/null +++ b/utils/src/main/java/at/gv/egiz/bku/utils/URLEncodingOutputStream.java @@ -0,0 +1,134 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.utils; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.CharBuffer; +import java.util.BitSet; + +/** + * An URLEncoding RFC3986, Section 2.1 + * OutputStream. + * + * @author mcentner + */ +public class URLEncodingOutputStream extends OutputStream { + + private static final int MAX_BUFFER_SIZE = 512; + + private static final BitSet UNRESERVED = new BitSet(256); + + static { + for (int i = '0'; i <= '9'; i++) { + UNRESERVED.set(i); + } + for (int i = 'a'; i <= 'z'; i++) { + UNRESERVED.set(i); + } + for (int i = 'A'; i <= 'Z'; i++) { + UNRESERVED.set(i); + } + UNRESERVED.set('-'); + UNRESERVED.set('_'); + UNRESERVED.set('.'); + UNRESERVED.set('*'); + UNRESERVED.set(' '); + } + + private static final char[] HEX = new char[] { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + + private char[] buf; + + protected Appendable out; + + /** + * Creates a new instance of this URLEncodingOutputStream that writes to the + * given Appendable. + *

+ * Note: According to + * http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars the input + * for the {@link #write()} methods should be the UTF-8. + *

+ * + * @param out + */ + public URLEncodingOutputStream(Appendable out) { + this.out = out; + } + + /* (non-Javadoc) + * @see java.io.OutputStream#write(int) + */ + @Override + public void write(int b) throws IOException { + b &= 0xFF; + if (UNRESERVED.get(b)) { + if (b == ' ') { + out.append('+'); + } else { + out.append((char) b); + } + } else { + out.append('%').append(HEX[b >>> 4]).append(HEX[b & 0xF]); + } + + } + + /* (non-Javadoc) + * @see java.io.OutputStream#write(byte[], int, int) + */ + @Override + public void write(byte[] b, int off, int len) throws IOException { + + // ensure a buffer at least double the size of end - start + 1 + // but max + int sz = Math.min(len + 1, MAX_BUFFER_SIZE); + if (buf == null || buf.length < sz) { + buf = new char[sz]; + } + + int bPos = 0; + for (int i = 0; i < len; i++) { + if (bPos + 3 > buf.length) { + // flush buffer + out.append(CharBuffer.wrap(buf, 0, bPos)); + bPos = 0; + } + int c = 0xFF & b[off + i]; + if (UNRESERVED.get(c)) { + if (c == ' ') { + buf[bPos++] = '+'; + } else { + buf[bPos++] = (char) c; + } + } else { + buf[bPos++] = '%'; + buf[bPos++] = HEX[c >>> 4]; + buf[bPos++] = HEX[c & 0xF]; + } + } + out.append(CharBuffer.wrap(buf, 0, bPos)); + + } + + +} diff --git a/utils/src/main/java/at/gv/egiz/bku/utils/URLEncodingWriter.java b/utils/src/main/java/at/gv/egiz/bku/utils/URLEncodingWriter.java new file mode 100644 index 00000000..3ba90265 --- /dev/null +++ b/utils/src/main/java/at/gv/egiz/bku/utils/URLEncodingWriter.java @@ -0,0 +1,57 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + * + * 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 at.gv.egiz.bku.utils; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.Charset; + +/** + * An URLEncoding RFC3986, Section + * 2.1 Writer, that uses an UTF-8 encoding according to http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars for + * writing non-ASCII characters. + * + * @author mcentner + */ +public class URLEncodingWriter extends Writer { + + protected OutputStreamWriter osw; + + public URLEncodingWriter(Appendable out) { + URLEncodingOutputStream urlEnc = new URLEncodingOutputStream(out); + osw = new OutputStreamWriter(urlEnc, Charset.forName("UTF-8")); + } + + @Override + public void close() throws IOException { + osw.close(); + } + + @Override + public void flush() throws IOException { + osw.flush(); + } + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + osw.write(cbuf, off, len); + } + +} diff --git a/utils/src/main/java/at/gv/egiz/marshal/MarshallerFactory.java b/utils/src/main/java/at/gv/egiz/marshal/MarshallerFactory.java index ccebcc81..3ac0a86e 100644 --- a/utils/src/main/java/at/gv/egiz/marshal/MarshallerFactory.java +++ b/utils/src/main/java/at/gv/egiz/marshal/MarshallerFactory.java @@ -31,13 +31,17 @@ public class MarshallerFactory { private static final Log log = LogFactory.getLog(MarshallerFactory.class); - public static Marshaller createMarshaller(JAXBContext ctx, boolean formattedOutput) throws JAXBException { + public static Marshaller createMarshaller(JAXBContext ctx, boolean formattedOutput, boolean fragment) throws JAXBException { Marshaller m = ctx.createMarshaller(); try { if (formattedOutput) { log.trace("setting marshaller property FORMATTED_OUTPUT"); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); } + if (fragment) { + log.trace("setting marshaller property FRAGMENT"); + m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); + } log.trace("setting marshaller property NamespacePrefixMapper"); m.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapperImpl()); } catch (PropertyException ex) { @@ -45,8 +49,12 @@ public class MarshallerFactory { } return m; } + + public static Marshaller createMarshaller(JAXBContext ctx, boolean formattedOutput) throws JAXBException { + return createMarshaller(ctx, formattedOutput, false); + } public static Marshaller createMarshaller(JAXBContext ctx) throws JAXBException { - return createMarshaller(ctx, false); + return createMarshaller(ctx, false, false); } } diff --git a/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefix.java b/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefix.java deleted file mode 100644 index 3ae1d0ff..00000000 --- a/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefix.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology - * - * 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 at.gv.egiz.marshal; - -/** - * - * @author Clemens Orthacker - */ -public interface NamespacePrefix { - String CARDCHANNEL_PREFIX = "cc"; - String ECDSA_PREFIX = "ecdsa"; - String PERSONDATA_PREFIX = "pr"; - String SAML10_PREFIX = "saml"; - String SL_PREFIX = "sl"; - String XADES_PREFIX = "xades"; - String XMLDSIG_PREFIX = "dsig"; - String XSI_PREFIX = "xsi"; - -} diff --git a/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefixMapperImpl.java b/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefixMapperImpl.java index 519f6b1f..e0698977 100644 --- a/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefixMapperImpl.java +++ b/utils/src/main/java/at/gv/egiz/marshal/NamespacePrefixMapperImpl.java @@ -17,6 +17,9 @@ package at.gv.egiz.marshal; //import com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper; +import java.util.HashMap; +import java.util.Map; + import com.sun.xml.bind.marshaller.NamespacePrefixMapper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -29,45 +32,32 @@ public class NamespacePrefixMapperImpl extends NamespacePrefixMapper { private static final Log log = LogFactory.getLog(NamespacePrefixMapperImpl.class); + protected static final Map prefixMap = new HashMap(); + + static { + prefixMap.put("http://www.w3.org/2001/XMLSchema-instance", "xsi"); + prefixMap.put("http://www.w3.org/2000/09/xmldsig#", "dsig"); + prefixMap.put("http://www.buergerkarte.at/namespaces/securitylayer/1.2#", "sl"); + prefixMap.put("http://www.buergerkarte.at/cardchannel", "cc"); + prefixMap.put("http://www.w3.org/2001/04/xmldsig-more#", "ecdsa"); + prefixMap.put("http://reference.e-government.gv.at/namespace/persondata/20020228#", "pr"); + prefixMap.put("urn:oasis:names:tc:SAML:1.0:assertion", "saml"); + prefixMap.put("http://uri.etsi.org/01903/v1.1.1#", "xades"); + prefixMap.put("http://www.buergerkarte.at/namespaces/securitylayer/20020225#", "sl10"); + prefixMap.put("http://www.buergerkarte.at/namespaces/securitylayer/20020831#", "sl11"); + } + + @Override public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) { if (log.isTraceEnabled()) { log.trace("prefix for namespace " + namespaceUri + " requested"); } - if ("http://www.w3.org/2001/XMLSchema-instance".equals(namespaceUri)) { - return NamespacePrefix.XSI_PREFIX; - } - - if ("http://www.w3.org/2000/09/xmldsig#".equals(namespaceUri)) { - return NamespacePrefix.XMLDSIG_PREFIX; - } - - if ("http://www.buergerkarte.at/namespaces/securitylayer/1.2#".equals(namespaceUri)) { - return NamespacePrefix.SL_PREFIX; - } - - if ("http://www.buergerkarte.at/cardchannel".equals(namespaceUri)) { - return NamespacePrefix.CARDCHANNEL_PREFIX; - } - - if ("http://www.w3.org/2001/04/xmldsig-more#".equals(namespaceUri)) { - return NamespacePrefix.ECDSA_PREFIX; - } - - if ("http://reference.e-government.gv.at/namespace/persondata/20020228#".equals(namespaceUri)) { - return NamespacePrefix.PERSONDATA_PREFIX; - } - - if ("urn:oasis:names:tc:SAML:1.0:assertion".equals(namespaceUri)) { - return NamespacePrefix.SAML10_PREFIX; - } - - if ("http://uri.etsi.org/01903/v1.1.1#".equals(namespaceUri)) { - return NamespacePrefix.XADES_PREFIX; - } - return suggestion; + String prefix = prefixMap.get(namespaceUri); + + return (prefix != null) ? prefix : suggestion; } /** diff --git a/utils/src/main/java/at/gv/egiz/validation/ReportingValidationEventHandler.java b/utils/src/main/java/at/gv/egiz/validation/ReportingValidationEventHandler.java new file mode 100644 index 00000000..6543c333 --- /dev/null +++ b/utils/src/main/java/at/gv/egiz/validation/ReportingValidationEventHandler.java @@ -0,0 +1,64 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + * + * 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 at.gv.egiz.validation; + +import javax.xml.bind.ValidationEvent; +import javax.xml.bind.ValidationEventHandler; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author Clemens Orthacker + */ +public class ReportingValidationEventHandler implements ValidationEventHandler { + + protected static final Log log = LogFactory.getLog(ReportingValidationEventHandler.class); + + protected ValidationEvent errorEvent; + + /** + * + * @param event + * @return false, terminate the current unmarshal, validate, or marshal operation after handling this warning/error + * (except for WARNING validation events) + */ + @Override + public boolean handleEvent(ValidationEvent event) { + switch (event.getSeverity()) { + case ValidationEvent.WARNING: + log.info(event.getMessage()); + return true; + case ValidationEvent.ERROR: + log.warn(event.getMessage()); + errorEvent = event; + return false; + case ValidationEvent.FATAL_ERROR: + log.error(event.getMessage()); + errorEvent = event; + return false; + default: + log.debug(event.getMessage()); + return false; + } + } + + public ValidationEvent getErrorEvent() { + return errorEvent; + } + +} diff --git a/utils/src/main/java/at/gv/egiz/validation/ValidationEventLogger.java b/utils/src/main/java/at/gv/egiz/validation/ValidationEventLogger.java deleted file mode 100644 index 0fafdd7f..00000000 --- a/utils/src/main/java/at/gv/egiz/validation/ValidationEventLogger.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2008 Federal Chancellery Austria and - * Graz University of Technology - * - * 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 at.gv.egiz.validation; - -import javax.xml.bind.ValidationEvent; -import javax.xml.bind.ValidationEventHandler; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * - * @author Clemens Orthacker - */ -public class ValidationEventLogger implements ValidationEventHandler { - - protected static final Log log = LogFactory.getLog(ValidationEventLogger.class); - - /** - * - * @param event - * @return false, terminate the current unmarshal, validate, or marshal operation after handling this warning/error - * (except for WARNING validation events) - */ - @Override - public boolean handleEvent(ValidationEvent event) { - switch (event.getSeverity()) { - case ValidationEvent.WARNING: - log.info(event.getMessage()); - return true; - case ValidationEvent.ERROR: - log.warn(event.getMessage()); - return false; - case ValidationEvent.FATAL_ERROR: - log.error(event.getMessage()); - return false; - default: - log.debug(event.getMessage()); - return false; - } - } -} diff --git a/utils/src/main/java/at/gv/egiz/xades/QualifyingPropertiesFactory.java b/utils/src/main/java/at/gv/egiz/xades/QualifyingPropertiesFactory.java index 71ca1db9..82cba624 100644 --- a/utils/src/main/java/at/gv/egiz/xades/QualifyingPropertiesFactory.java +++ b/utils/src/main/java/at/gv/egiz/xades/QualifyingPropertiesFactory.java @@ -16,8 +16,6 @@ */ package at.gv.egiz.xades; -import at.gv.egiz.marshal.MarshallerFactory; -import at.gv.egiz.marshal.NamespacePrefixMapperImpl; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -51,6 +49,8 @@ import org.w3._2000._09.xmldsig_.DigestMethodType; import org.w3._2000._09.xmldsig_.X509IssuerSerialType; import org.w3c.dom.Node; +import at.gv.egiz.marshal.MarshallerFactory; + public class QualifyingPropertiesFactory { public static String NS_URI_V1_1_1 = "http://uri.etsi.org/01903/v1.1.1#"; @@ -155,7 +155,7 @@ public class QualifyingPropertiesFactory { return dataObjectFormatType; } - public JAXBElement createQualifyingProperties111(Date signingTime, List certificates, String idValue, List dataObjectFormats) throws QualifyingPropertiesException { + public JAXBElement createQualifyingProperties111(String target, Date signingTime, List certificates, String idValue, List dataObjectFormats) throws QualifyingPropertiesException { GregorianCalendar gregorianCalendar = new GregorianCalendar(); gregorianCalendar.setTimeZone(TimeZone.getTimeZone("UTC")); @@ -206,6 +206,8 @@ public class QualifyingPropertiesFactory { QualifyingPropertiesType qualifyingPropertiesType = qpFactory.createQualifyingPropertiesType(); qualifyingPropertiesType.setSignedProperties(signedPropertiesType); + qualifyingPropertiesType.setTarget(target); + return qpFactory.createQualifyingProperties(qualifyingPropertiesType); } diff --git a/utils/src/test/java/at/gv/egiz/bku/utils/URLEncodingOutputStreamTest.java b/utils/src/test/java/at/gv/egiz/bku/utils/URLEncodingOutputStreamTest.java new file mode 100644 index 00000000..e92b9584 --- /dev/null +++ b/utils/src/test/java/at/gv/egiz/bku/utils/URLEncodingOutputStreamTest.java @@ -0,0 +1,147 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.utils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URLEncoder; +import java.nio.charset.Charset; + +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class URLEncodingOutputStreamTest { + + private static String buf; + + private static Charset UTF_8 = Charset.forName("UTF-8"); + + @BeforeClass + public static void setUpClass() throws IOException { + + ClassLoader cl = URLEncodingOutputStreamTest.class.getClassLoader(); + InputStream is = cl.getResourceAsStream("BigRequest.xml"); + + assertNotNull(is); + + InputStreamReader reader = new InputStreamReader(is, UTF_8); + + StringBuilder sb = new StringBuilder(); + + char[] b = new char[512]; + for (int l; (l = reader.read(b)) != -1;) { + sb.append(b, 0, l); + } + + buf = sb.toString(); + + } + + @Test + public void testCompareResults() throws IOException { + + String out1; + String out2; + + // new + StringWriter writer = new StringWriter(); + URLEncodingOutputStream urlEnc = new URLEncodingOutputStream(writer); + OutputStreamWriter streamWriter = new OutputStreamWriter(urlEnc, UTF_8); + streamWriter.append(buf); + streamWriter.flush(); + out1 = writer.toString(); + + // URLEncoder + out2 = URLEncoder.encode(buf, UTF_8.name()); + + for (int i = 0; i < out1.length(); i++) { + if (out1.charAt(i) != out2.charAt(i)) { + System.out.println(i + ": " + out1.substring(i)); + System.out.println(i + ": " + out2.substring(i)); + } + } + + assertEquals(out1, out2); + + } + + @Ignore + @Test + public void testURLEncodingOutputStream() throws IOException { + + NullWriter writer = new NullWriter(); + + URLEncodingOutputStream urlEnc = new URLEncodingOutputStream(writer); + OutputStreamWriter streamWriter = new OutputStreamWriter(urlEnc, UTF_8); + + long t0, t1, dt = 0; + for (int run = 0; run < 1000; run++) { + t0 = System.currentTimeMillis(); + streamWriter.append(buf); + t1 = System.currentTimeMillis(); + if (run > 1) { + dt += t1 - t0; + } + } + System.out.println("Time " + dt + "ms"); + + } + + @Ignore + @Test + public void testURLEncodingNaive() throws IOException { + + String in = new String(buf); + + long t0, t1, dt = 0; + for (int run = 0; run < 1000; run++) { + t0 = System.currentTimeMillis(); + URLEncoder.encode(in, "UTF-8"); + t1 = System.currentTimeMillis(); + if (run > 1) { + dt += t1 - t0; + } + } + System.out.println("Time (naive) " + dt + "ms"); + + } + + public class NullWriter extends Writer { + + @Override + public void close() throws IOException { + } + + @Override + public void flush() throws IOException { + } + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + } + + } + +} diff --git a/utils/src/test/resources/BigRequest.xml b/utils/src/test/resources/BigRequest.xml new file mode 100644 index 00000000..90eb1eb8 --- /dev/null +++ b/utils/src/test/resources/BigRequest.xml @@ -0,0 +1,1060 @@ + + +SecureSignatureKeypair + + + TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Np +bmcgZWxpdC4gTnVsbGFtIHZ1bHB1dGF0ZSwgcmlzdXMgaW1wZXJkaWV0IGNvbnNl +cXVhdCB2YXJpdXMsIHJpc3VzIGR1aSB0ZW1wdXMgbGVvLCBub24gbGFjaW5pYSBl +bmltIG51bmMgYSBzZW0uIERvbmVjIHBvcnRhLCBpcHN1bSB0aW5jaWR1bnQgdWx0 +cmljZXMgaW50ZXJkdW0sIGZlbGlzIGF1Z3VlIHNvZGFsZXMgYW50ZSwgdmVsIG9y +bmFyZSBsaWJlcm8gbnVsbGEgZXQgcHVydXMuIENyYXMgdGVtcHVzIHZhcml1cyBw +b3J0YS4gRG9uZWMgaWQgcHVydXMgdXQgdmVsaXQgYmliZW5kdW0gbHVjdHVzIGJs +YW5kaXQgc2l0IGFtZXQgbmVxdWUuIENsYXNzIGFwdGVudCB0YWNpdGkgc29jaW9z +cXUgYWQgbGl0b3JhIHRvcnF1ZW50IHBlciBjb251YmlhIG5vc3RyYSwgcGVyIGlu +Y2VwdG9zIGhpbWVuYWVvcy4gQ3JhcyBmYWNpbGlzaXMgdGVtcHVzIGZlcm1lbnR1 +bS4gRG9uZWMgZmVybWVudHVtIG1hc3NhIGV0IHNhcGllbiBwb3N1ZXJlIHZlbmVu +YXRpcy4gSW4gcXVpcyB1cm5hIG9yY2kuIER1aXMgYSBsaWJlcm8gb3JjaS4gTnVs +bGEgcG9ydHRpdG9yIGF1Z3VlIHZpdGFlIGxpZ3VsYSB0ZW1wb3Igc2VkIHJ1dHJ1 +bSBtaSBjdXJzdXMuIEFlbmVhbiBpYWN1bGlzIG5pc2kgYXQgaXBzdW0gY29uc2Vj +dGV0dXIgZWdldCB2YXJpdXMgbWFnbmEgc29sbGljaXR1ZGluLiBVdCBmYWNpbGlz +aXMgdGVsbHVzIGEgbmVxdWUgZWdlc3RhcyBwbGFjZXJhdC4gRG9uZWMgdG9ydG9y +IHZlbGl0LCB0aW5jaWR1bnQgYSBtb2xsaXMgY3Vyc3VzLCBsdWN0dXMgYWxpcXVh +bSBsaWJlcm8uIER1aXMgbm9uIHRlbGx1cyBwcmV0aXVtIHRlbGx1cyB2YXJpdXMg +ZWxlaWZlbmQgaW4gc2VkIHNlbS4gU3VzcGVuZGlzc2UgZmVybWVudHVtIHRlbGx1 +cyBpZCBmZWxpcyB0ZW1wdXMgdml2ZXJyYS4gRG9uZWMgcG9ydHRpdG9yIHRpbmNp +ZHVudCBtYXVyaXMgbmVjIGV1aXNtb2QuCgpQcmFlc2VudCB1bGxhbWNvcnBlciB0 +cmlzdGlxdWUgbG9yZW0sIGV0IHBsYWNlcmF0IG51bmMgZWxlbWVudHVtIHV0LiBN +b3JiaSBldCBhZGlwaXNjaW5nIHNlbS4gTmFtIHZlbCBuaWJoIGV1IGxlbyBjb25k +aW1lbnR1bSByaG9uY3VzIHF1aXMgc2VkIHVybmEuIFBoYXNlbGx1cyBpZCBqdXN0 +byB1dCBvcmNpIHZlc3RpYnVsdW0gc2NlbGVyaXNxdWUuIE5hbSBtb2xsaXMgdG9y +dG9yIHB1cnVzLiBQZWxsZW50ZXNxdWUgaWFjdWxpcyBzZW1wZXIgbWFsZXN1YWRh +LiBJbnRlZ2VyIGJsYW5kaXQgZmVsaXMgYXQgbG9yZW0gZXVpc21vZCB2ZW5lbmF0 +aXMuIE1hZWNlbmFzIG5lYyBlbGVpZmVuZCBsZW8uIERvbmVjIGxvYm9ydGlzLCBy +aXN1cyBuZWMgdGVtcHVzIHZvbHV0cGF0LCBudWxsYSBlbGl0IGx1Y3R1cyBhcmN1 +LCBhYyBwb3N1ZXJlIGxhY3VzIG1hc3NhIGluIG1pLiBNYWVjZW5hcyBzaXQgYW1l +dCBudW5jIG5lYyB0ZWxsdXMgZWdlc3RhcyB2ZXN0aWJ1bHVtIHZpdGFlIGV0IGVs +aXQuIE51bGxhbSBjb25zZWN0ZXR1ciBydXRydW0gdGVsbHVzIGFjIGFjY3Vtc2Fu +LiBDdXJhYml0dXIgZ3JhdmlkYSBhdWd1ZSBldCBtZXR1cyBjdXJzdXMgZWxlaWZl +bmQuIENyYXMgb2RpbyBhcmN1LCB0aW5jaWR1bnQgdXQgZWdlc3RhcyB2ZWwsIGdy +YXZpZGEgaW4gZXJvcy4gTnVuYyBldCBtYWxlc3VhZGEgcXVhbS4gTWF1cmlzIGFj +IHRlbGx1cyBhcmN1LgoKQ3JhcyBuaXNsIHNhcGllbiwgdGluY2lkdW50IGVnZXQg +ZWxlaWZlbmQgdmVsLCBwcmV0aXVtIGlkIGxlY3R1cy4gQWxpcXVhbSB0b3J0b3Ig +dXJuYSwgcG9zdWVyZSBpZCBydXRydW0gbHVjdHVzLCBhdWN0b3Igc2VkIGFudGUu +IFByb2luIGZlcm1lbnR1bSwgbmliaCBhIHZvbHV0cGF0IHZvbHV0cGF0LCBlcm9z +IGRvbG9yIHNjZWxlcmlzcXVlIG1hZ25hLCB0ZW1wdXMgc29sbGljaXR1ZGluIGxp +YmVybyBkb2xvciBydXRydW0gZXN0LiBNYXVyaXMgcXVpcyBqdXN0byBhcmN1LiBQ +cm9pbiB2ZWhpY3VsYSBhZGlwaXNjaW5nIGVyb3Mgbm9uIGNvbmRpbWVudHVtLiBO +dW5jIHN1c2NpcGl0LCBsZWN0dXMgZXUgaWFjdWxpcyBtb2xlc3RpZSwgbWkgZG9s +b3IgcG9ydGEgZG9sb3IsIGV1IHNhZ2l0dGlzIG1hc3NhIGlwc3VtIGluIG1pLiBO +dW5jIHNlbXBlciBzY2VsZXJpc3F1ZSBsb3JlbSwgYSBzb2RhbGVzIHRvcnRvciBw +b3J0dGl0b3IgaWQuIE51bGxhIG1hdHRpcywgdG9ydG9yIG5lYyBpYWN1bGlzIHBy +ZXRpdW0sIGVyYXQgbGFjdXMgdnVscHV0YXRlIGR1aSwgdnVscHV0YXRlIGZhY2ls +aXNpcyBkb2xvciB0dXJwaXMgdXQgZmVsaXMuIE1hZWNlbmFzIHZpdGFlIHNlbSBl +dCBuaWJoIHNhZ2l0dGlzIHRpbmNpZHVudCBxdWlzIGluIHRvcnRvci4gQWxpcXVh +bSBpZCBzb2RhbGVzIHJpc3VzLiBJbnRlZ2VyIGZhY2lsaXNpcywgc2FwaWVuIHV0 +IHNhZ2l0dGlzIGNvbnNlY3RldHVyLCBkaWFtIGxvcmVtIHZpdmVycmEgZG9sb3Is +IHF1aXMgY29tbW9kbyBuaWJoIGVyYXQgcXVpcyBtZXR1cy4gUHJvaW4gZGljdHVt +IHJpc3VzIG1hdXJpcy4gTnVuYyBldSB1cm5hIHNpdCBhbWV0IHZlbGl0IHBsYWNl +cmF0IGVsZWlmZW5kLiBBZW5lYW4gc2l0IGFtZXQgcHVydXMgbnVuYy4gUHJvaW4g +bm9uIG5lcXVlIGEgdGVsbHVzIG1hdHRpcyBlZ2VzdGFzIGF0IHV0IG51bmMuIERv +bmVjIG5vbiBhbnRlIHZpdGFlIG9yY2kgcGVsbGVudGVzcXVlIHNjZWxlcmlzcXVl +LiBNYWVjZW5hcyBhYyBpYWN1bGlzIGZlbGlzLiBVdCBhZGlwaXNjaW5nIHN1c2Np +cGl0IGRpYW0gdXQgcG9ydGEuIERvbmVjIHZlc3RpYnVsdW0gbGFjaW5pYSBtYWdu +YSwgaWQgcnV0cnVtIG5pc2kgdmVuZW5hdGlzIHNlZC4KCk51bGxhIHNhZ2l0dGlz +IHBoYXJldHJhIGFudGUgZXUgb3JuYXJlLiBBbGlxdWFtIGV1IGRvbG9yIHV0IHVy +bmEgY29uZGltZW50dW0gcnV0cnVtLiBJbnRlZ2VyIHN1c2NpcGl0LCB2ZWxpdCBu +ZWMgc29sbGljaXR1ZGluIGN1cnN1cywgbGVjdHVzIHF1YW0gc2NlbGVyaXNxdWUg +bWksIGlkIGF1Y3RvciBzYXBpZW4gdG9ydG9yIHNlZCB0ZWxsdXMuIERvbmVjIHRp +bmNpZHVudCB0aW5jaWR1bnQgbGVjdHVzLCBxdWlzIHNvZGFsZXMgcHVydXMgaW1w +ZXJkaWV0IGV0LiBOdWxsYSBmYWNpbGlzaS4gTnVsbGFtIGlhY3VsaXMgZWxlbWVu +dHVtIGZlbGlzLCBlZ2V0IG1hdHRpcyBkb2xvciB0cmlzdGlxdWUgYWMuIFNlZCBl +Z2V0IHNlbSBuZXF1ZS4gVXQgZmVybWVudHVtLCBtaSBxdWlzIHZvbHV0cGF0IHZl +bmVuYXRpcywgbGFjdXMgbmVxdWUgY29udmFsbGlzIGVzdCwgdml0YWUgc3VzY2lw +aXQgdHVycGlzIGFudGUgYXQgcmlzdXMuIE51bmMgZmVybWVudHVtLCBtYWduYSBx +dWlzIHZlbmVuYXRpcyBldWlzbW9kLCBlbGl0IHZlbGl0IGZlcm1lbnR1bSBqdXN0 +bywgYSBkaWN0dW0gbGlndWxhIGp1c3RvIGFjIGxvcmVtLiBTZWQgZWdldCB0b3J0 +b3IgbWFnbmEsIHZpdmVycmEgaW50ZXJkdW0gbGVvLiBRdWlzcXVlIGluIGxhY3Vz +IGV0IGxlY3R1cyBhZGlwaXNjaW5nIGNvbnNlY3RldHVyIGluIHF1aXMgZXN0LiBN +YXVyaXMgZXQgZG9sb3IgZXQgbmVxdWUgbW9sZXN0aWUgY29uc2VjdGV0dXIgZXVp +c21vZCBldSBlbGl0LiBOdWxsYSBmYWNpbGlzaS4gUHJvaW4gYWMgdmVsaXQgaXBz +dW0sIHV0IHRyaXN0aXF1ZSBtYWduYS4gVmVzdGlidWx1bSBwb3N1ZXJlIG1hbGVz +dWFkYSBuaXNsIHNpdCBhbWV0IGFsaXF1YW0uIFN1c3BlbmRpc3NlIHNlZCBpcHN1 +bSBpZCB0ZWxsdXMgcG9ydGEgcG9zdWVyZSBlZ2V0IHNpdCBhbWV0IHR1cnBpcy4g +TnVuYyBhYyBkb2xvciB2ZWwgdXJuYSBkYXBpYnVzIGZlcm1lbnR1bSBuZWMgdmVo +aWN1bGEgdXJuYS4gRnVzY2UgdGluY2lkdW50IG1ldHVzIGV1IGlwc3VtIG1hdHRp +cyB0cmlzdGlxdWUuIFNlZCBmYXVjaWJ1cyBmcmluZ2lsbGEgYWRpcGlzY2luZy4g +Q3JhcyBwaGFyZXRyYSwgYW50ZSBzZWQgYWNjdW1zYW4gcmhvbmN1cywgZWxpdCBk +b2xvciBsYWNpbmlhIG1hdXJpcywgYXQgbGFvcmVldCBsaWJlcm8gYXVndWUgYXQg +bmlzbC4KClByb2luIGEgbGVvIHV0IHRvcnRvciBwb3J0YSBsdWN0dXMuIFZlc3Rp +YnVsdW0gYW50ZSBpcHN1bSBwcmltaXMgaW4gZmF1Y2lidXMgb3JjaSBsdWN0dXMg +ZXQgdWx0cmljZXMgcG9zdWVyZSBjdWJpbGlhIEN1cmFlOyBVdCBzZWQgbnVuYyB2 +ZWwgbWV0dXMgc3VzY2lwaXQgY29uZ3VlIGF0IGEgZG9sb3IuIE51bmMgZXUgdG9y +dG9yIGxvcmVtLCBuZWMgY29uZ3VlIGxpYmVyby4gTW9yYmkgbGFvcmVldCBsZWN0 +dXMgbmlzbCwgdml0YWUgcmhvbmN1cyBlbGl0LiBTdXNwZW5kaXNzZSBldCBxdWFt +IHF1aXMgZHVpIGxhY2luaWEgc29kYWxlcyBuZWMgZXUgbGlndWxhLiBQZWxsZW50 +ZXNxdWUgbm9uIGlwc3VtIGxlbywgc2l0IGFtZXQgbW9sZXN0aWUgZHVpLiBTZWQg +YSBhdWd1ZSBlZ2V0IG1hdXJpcyBncmF2aWRhIG1hbGVzdWFkYSBldCBxdWlzIGlw +c3VtLiBBbGlxdWFtIGFjIG5pYmggbGlndWxhLCBpbiBwb3J0dGl0b3IgZWxpdC4g +TWF1cmlzIHR1cnBpcyBvcmNpLCBhY2N1bXNhbiBpbiBpbnRlcmR1bSBhdCwgZmFj +aWxpc2lzIHZpdGFlIHR1cnBpcy4gUXVpc3F1ZSBtYXR0aXMgcGVsbGVudGVzcXVl +IGVyb3MgdmVsIHZpdmVycmEuIFZlc3RpYnVsdW0gbGFvcmVldCBjb25ndWUgYWxp +cXVhbS4gRG9uZWMgcG9zdWVyZSBtYXVyaXMgbmVjIGxpYmVybyBvcm5hcmUgZXQg +ZWdlc3RhcyBhbnRlIHB1bHZpbmFyLiBDdXJhYml0dXIgYW50ZSBhbnRlLCBtb2xl +c3RpZSB1dCBiaWJlbmR1bSB2aXRhZSwgcnV0cnVtIHZlbCByaXN1cy4gRG9uZWMg +ZXQgbmVxdWUgcHVydXMsIHNpdCBhbWV0IGFkaXBpc2NpbmcgZmVsaXMuIFBlbGxl +bnRlc3F1ZSBkaWduaXNzaW0gdmVzdGlidWx1bSBzYXBpZW4gbmVjIGZyaW5naWxs +YS4gUHJvaW4gbmVjIHB1cnVzIGV0IGVzdCBldWlzbW9kIHBoYXJldHJhLiBQZWxs +ZW50ZXNxdWUgZGFwaWJ1cyBkYXBpYnVzIG1ldHVzIHZlbCBmYWNpbGlzaXMuIFZp +dmFtdXMgdmVsIGVsaXQgbnVuYy4KCkV0aWFtIGFjIGVuaW0gZWdldCBtYXVyaXMg +ZmF1Y2lidXMgZGFwaWJ1cy4gTW9yYmkgdml0YWUgbGVjdHVzIG5lcXVlLiBNYXVy +aXMgc2FwaWVuIG1ldHVzLCBzdXNjaXBpdCBzaXQgYW1ldCBlZ2VzdGFzIHZpdGFl +LCBwaGFyZXRyYSBhIG1hc3NhLiBVdCB2YXJpdXMsIHRvcnRvciBzZWQgZnJpbmdp +bGxhIHBsYWNlcmF0LCBuZXF1ZSBkaWFtIGNvbmd1ZSBudW5jLCBpZCBhbGlxdWV0 +IG5pc2kgcmlzdXMgdXQgdXJuYS4gVml2YW11cyBwbGFjZXJhdCBwb3J0YSBhcmN1 +IHZpdGFlIGFjY3Vtc2FuLiBNYXVyaXMgaGVuZHJlcml0LCBlbmltIHZpdGFlIGFs +aXF1YW0gcG9ydHRpdG9yLCBwdXJ1cyBuZXF1ZSBncmF2aWRhIG1hZ25hLCBub24g +cHJldGl1bSBuZXF1ZSBsZWN0dXMgc2l0IGFtZXQgdG9ydG9yLiBEdWlzIHN1c2Np +cGl0IG9ybmFyZSBvZGlvIHZpdGFlIHBoYXJldHJhLiBEb25lYyBlbGVpZmVuZCwg +ZHVpIG5vbiBncmF2aWRhIGNvbnZhbGxpcywgb2RpbyBhcmN1IGJsYW5kaXQgbWFn +bmEsIG5vbiBwb3J0YSBsZW8gbGliZXJvIHBvcnRhIG1hZ25hLiBEdWlzIGVzdCB1 +cm5hLCBsdWN0dXMgZXUgaW50ZXJkdW0gbmVjLCBpYWN1bGlzIG5lYyBlbGl0LiBD +dXJhYml0dXIgZmFjaWxpc2lzIHRlbXB1cyB0ZW1wdXMuIFNlZCBzZW0gdXJuYSwg +dml2ZXJyYSBldSBpbXBlcmRpZXQgc2l0IGFtZXQsIGludGVyZHVtIGV0IGp1c3Rv +LiBJbiBoYWMgaGFiaXRhc3NlIHBsYXRlYSBkaWN0dW1zdC4gRG9uZWMgdGluY2lk +dW50IG1hc3NhIHV0IGR1aSBmZXJtZW50dW0gcG9zdWVyZSBldCBuZWMgdHVycGlz +LiBFdGlhbSBmZXJtZW50dW0gcG9ydGEgbWF1cmlzLiBTdXNwZW5kaXNzZSBsYWN1 +cyBsaWJlcm8sIHByZXRpdW0gaW4gZWdlc3RhcyB2ZWwsIHNhZ2l0dGlzIGV0IG1h +c3NhLiBOdWxsYSBhbGlxdWFtIGxhb3JlZXQgc2FwaWVuLCBhdCBwZWxsZW50ZXNx +dWUgZXJvcyB2ZW5lbmF0aXMgcXVpcy4gSW50ZWdlciBhY2N1bXNhbiwgbGFjdXMg +dXQgZGFwaWJ1cyBlZ2VzdGFzLCByaXN1cyBuaXNsIHNlbXBlciB0dXJwaXMsIHNp +dCBhbWV0IHZpdmVycmEgZmVsaXMgdHVycGlzIHNlZCB2ZWxpdC4KCkRvbmVjIHZl +aGljdWxhLCB0ZWxsdXMgcXVpcyBtb2xlc3RpZSBiaWJlbmR1bSwgYXVndWUgbmlz +bCB0ZW1wdXMgbG9yZW0sIHNpdCBhbWV0IGNvbmRpbWVudHVtIGp1c3RvIGF1Z3Vl +IHNpdCBhbWV0IGFudGUuIE51bGxhbSB0b3J0b3Igc2VtLCBtYXR0aXMgYWMgcG9y +dHRpdG9yIHZpdGFlLCBpYWN1bGlzIHNlZCBkdWkuIEN1bSBzb2NpaXMgbmF0b3F1 +ZSBwZW5hdGlidXMgZXQgbWFnbmlzIGRpcyBwYXJ0dXJpZW50IG1vbnRlcywgbmFz +Y2V0dXIgcmlkaWN1bHVzIG11cy4gRXRpYW0gaW4gc2VtIGlwc3VtLiBJbiBldSBt +b2xlc3RpZSBtZXR1cy4gVml2YW11cyBsYW9yZWV0IGZhdWNpYnVzIG5pYmgsIGEg +c2VtcGVyIG5pYmggZnJpbmdpbGxhIHV0LiBNYWVjZW5hcyBsYW9yZWV0LCBwdXJ1 +cyBldSBzb2xsaWNpdHVkaW4gcGhhcmV0cmEsIGp1c3RvIHRlbGx1cyBjb21tb2Rv +IGF1Z3VlLCBpbiBmYXVjaWJ1cyBsZW8ganVzdG8gbmVjIG5pc2wuIE5hbSBldSBw +cmV0aXVtIGVzdC4gRnVzY2Ugc2l0IGFtZXQgcXVhbSBsb3JlbSwgdXQgc29kYWxl +cyB0ZWxsdXMuIE51bmMgZWxlbWVudHVtLCBzZW0gc2NlbGVyaXNxdWUgaWFjdWxp +cyBpbnRlcmR1bSwgZXJvcyBkdWkgb3JuYXJlIG9yY2ksIHNlZCBwbGFjZXJhdCBy +aXN1cyBlcmF0IGVnZXQgYXJjdS4gTW9yYmkgYWMgbWV0dXMgaWQgbGlndWxhIHBv +cnRhIGdyYXZpZGEuIE51bmMgY29udmFsbGlzIGRpYW0gaW4gbmlzaSBncmF2aWRh +IGFjIGNvbW1vZG8gbGFjdXMgZGlnbmlzc2ltLiBDdW0gc29jaWlzIG5hdG9xdWUg +cGVuYXRpYnVzIGV0IG1hZ25pcyBkaXMgcGFydHVyaWVudCBtb250ZXMsIG5hc2Nl +dHVyIHJpZGljdWx1cyBtdXMuIEV0aWFtIHF1aXMgdmVsaXQgZXUgZmVsaXMgbHVj +dHVzIHBlbGxlbnRlc3F1ZSBub24gZWdlc3RhcyBuZXF1ZS4gTnVuYyBuaWJoIHRl +bGx1cywgcGxhY2VyYXQgbm9uIGZlcm1lbnR1bSBhdCwgb3JuYXJlIHF1aXMgZGlh +bS4gU3VzcGVuZGlzc2Ugc2l0IGFtZXQgcHVydXMgcXVpcyBkdWkgY29uc2VxdWF0 +IHByZXRpdW0uIEZ1c2NlIGV0IG1hZ25hIG5pc2ksIHZlbCB2ZXN0aWJ1bHVtIGVy +b3MuIEluIGZhdWNpYnVzLCBsYWN1cyBlZ2V0IGZhdWNpYnVzIGZldWdpYXQsIGxp +Z3VsYSBlbmltIHZlc3RpYnVsdW0gbG9yZW0sIGEgdml2ZXJyYSBsb3JlbSBlc3Qg +dml0YWUgcXVhbS4gTnVuYyBwdXJ1cyBuaXNsLCB2YXJpdXMgZXQgdGVtcG9yIHVs +dHJpY2llcywgaWFjdWxpcyBhIGxpYmVyby4gQ2xhc3MgYXB0ZW50IHRhY2l0aSBz +b2Npb3NxdSBhZCBsaXRvcmEgdG9ycXVlbnQgcGVyIGNvbnViaWEgbm9zdHJhLCBw +ZXIgaW5jZXB0b3MgaGltZW5hZW9zLgoKRnVzY2UgdmVsIGp1c3RvIHNpdCBhbWV0 +IHF1YW0gbWFsZXN1YWRhIG9ybmFyZSBzaXQgYW1ldCBldCBhbnRlLiBOdWxsYW0g +cmhvbmN1cyBwb3J0YSBzZW0gcXVpcyBtYWxlc3VhZGEuIENsYXNzIGFwdGVudCB0 +YWNpdGkgc29jaW9zcXUgYWQgbGl0b3JhIHRvcnF1ZW50IHBlciBjb251YmlhIG5v +c3RyYSwgcGVyIGluY2VwdG9zIGhpbWVuYWVvcy4gRG9uZWMgYW50ZSBvZGlvLCB0 +aW5jaWR1bnQgYWMgbW9sbGlzIGluLCB1bHRyaWNlcyBuZWMgZHVpLiBOdW5jIGN1 +cnN1cyBtYWduYSBuZWMgcHVydXMgZnJpbmdpbGxhIGEgbW9sZXN0aWUgcHVydXMg +bG9ib3J0aXMuIEZ1c2NlIHJ1dHJ1bSwgbG9yZW0gZWdldCB1bGxhbWNvcnBlciBm +cmluZ2lsbGEsIGR1aSBsaWd1bGEgc29sbGljaXR1ZGluIHJpc3VzLCB2aXRhZSBw +b3N1ZXJlIG5lcXVlIGZlbGlzIHZpdGFlIHF1YW0uIEN1cmFiaXR1ciBjb25kaW1l +bnR1bSBsaWJlcm8gYXQgb3JjaSBhdWN0b3IgZXUgY29tbW9kbyBsaWJlcm8gc29s +bGljaXR1ZGluLiBDcmFzIHNlZCBwdXJ1cyBtaSwgc2VkIGNvbnZhbGxpcyBuaWJo +LiBOdWxsYW0gYWMgbG9yZW0gYSBpcHN1bSBsYWNpbmlhIHVsbGFtY29ycGVyIGlk +IHF1aXMgdG9ydG9yLiBNb3JiaSBlbGVpZmVuZCwgbnVsbGEgdmVsIHZlbmVuYXRp +cyBjb25kaW1lbnR1bSwgbGVjdHVzIHRvcnRvciB2ZW5lbmF0aXMgcmlzdXMsIGEg +bHVjdHVzIGxhY3VzIGlwc3VtIHV0IHNhcGllbi4KCk1hdXJpcyBsYW9yZWV0IG51 +bmMgc2l0IGFtZXQgZW5pbSBkaWN0dW0gbG9ib3J0aXMuIE1hdXJpcyBydXRydW0s +IGVsaXQgdXQgbW9sZXN0aWUgb3JuYXJlLCB0b3J0b3IgZXJvcyB2YXJpdXMgbnVu +YywgdHJpc3RpcXVlIHBlbGxlbnRlc3F1ZSB0dXJwaXMgYXVndWUgaW4gYW50ZS4g +QWVuZWFuIGZlbGlzIGR1aSwgZnJpbmdpbGxhIGluIGFsaXF1YW0gYXQsIG9ybmFy +ZSB1dCBudWxsYS4gSW4gbWkgbnVuYywgc2VtcGVyIGluIGNvbmRpbWVudHVtIG5v +biwgY29uZ3VlIGFjIG1hdXJpcy4gQ3VyYWJpdHVyIGltcGVyZGlldCByaG9uY3Vz +IHNlbSwgbW9sZXN0aWUgYWRpcGlzY2luZyBpcHN1bSBzb2xsaWNpdHVkaW4gYS4g +Vml2YW11cyB1dCBpcHN1bSBxdWlzIHR1cnBpcyBhbGlxdWV0IHRpbmNpZHVudCBh +Y2N1bXNhbiBhYyBxdWFtLiBDdXJhYml0dXIgcG9ydHRpdG9yLCBtYXVyaXMgYWMg +bHVjdHVzIHZpdmVycmEsIHB1cnVzIGVzdCBhZGlwaXNjaW5nIHNhcGllbiwgc2l0 +IGFtZXQgYWxpcXVhbSBxdWFtIG51bGxhIGF0IGVyYXQuIFZpdmFtdXMgdGVtcHVz +LCBqdXN0byBhIHByZXRpdW0gZGljdHVtLCBpcHN1bSBudW5jIGxhb3JlZXQgdGVs +bHVzLCBuZWMgdGVtcHVzIHNlbSBuaXNpIGFjIHF1YW0uIFZpdmFtdXMgaW4gbWFz +c2EgZW5pbS4gUXVpc3F1ZSBuZWMgdG9ydG9yIHZpdGFlIG51bGxhIHVsdHJpY2Vz +IGNvbnZhbGxpcy4gTnVsbGFtIHRvcnRvciBtYXVyaXMsIGF1Y3RvciB2aXRhZSB0 +ZW1wb3IgZXQsIGF1Y3RvciBuZWMgc2FwaWVuLiBRdWlzcXVlIHVsbGFtY29ycGVy +IHZpdmVycmEgdmVuZW5hdGlzLiBNYWVjZW5hcyBxdWlzIGdyYXZpZGEgbWFzc2Eu +IEludGVnZXIgdml0YWUganVzdG8gbGVjdHVzLCBhYyBtYWxlc3VhZGEgcXVhbS4g +TWFlY2VuYXMgc2l0IGFtZXQgbmVxdWUgbnVsbGEsIG5lYyBpbXBlcmRpZXQgaXBz +dW0uIFNlZCB0ZW1wdXMgYmliZW5kdW0gc2FwaWVuLCBub24gZnJpbmdpbGxhIG51 +bmMgZWxlbWVudHVtIGV1LiBOdW5jIGF1Y3RvciBhbGlxdWV0IGxlbywgYmliZW5k +dW0gcHJldGl1bSBkaWFtIHBsYWNlcmF0IGFjLiBOYW0gaW4gZW5pbSBkdWkuIFNl +ZCBldCBuaWJoIG5vbiBudW5jIHBsYWNlcmF0IHBoYXJldHJhLiBTZWQgb2RpbyBs +ZW8sIGNvbmRpbWVudHVtIGV1IHN1c2NpcGl0IGV1LCBtb2xsaXMgZWdldCBuaXNp +LgoKUHJvaW4gb3JuYXJlLCBpcHN1bSB2aXRhZSBsYW9yZWV0IHZhcml1cywgbGFj +dXMgbGVvIHBoYXJldHJhIG1hdXJpcywgc2VkIGNvbnZhbGxpcyBsaWJlcm8gbWV0 +dXMgcmhvbmN1cyBvcmNpLiBNYXVyaXMgcnV0cnVtIGxlbyB2ZWwgYW50ZSBlZ2Vz +dGFzIGEgYWRpcGlzY2luZyBlc3QgdmVuZW5hdGlzLiBJbiBldSBtaSB1dCBlbGl0 +IHRyaXN0aXF1ZSB2ZWhpY3VsYS4gTnVuYyBwb3N1ZXJlLCBlbmltIHF1aXMgc3Vz +Y2lwaXQgYWNjdW1zYW4sIGVsaXQgbGVvIHNlbXBlciBudW5jLCBub24gbGFvcmVl +dCBhbnRlIG5pYmggc2l0IGFtZXQgbWF1cmlzLiBBbGlxdWFtIGFjIHF1YW0gcXVp +cyBuaXNsIHNvbGxpY2l0dWRpbiBtb2xlc3RpZSBpZCBhYyBudWxsYS4gSW50ZWdl +ciBldSBkb2xvciBpcHN1bS4gUGhhc2VsbHVzIGludGVyZHVtIHZlaGljdWxhIHNl +bXBlci4gU3VzcGVuZGlzc2UgbmVjIGFyY3UgYWMgZXN0IGlhY3VsaXMgdmVoaWN1 +bGEuIE1hZWNlbmFzIHNlbXBlciBsaWJlcm8gaWFjdWxpcyBsb3JlbSBmZXVnaWF0 +IGF1Y3Rvci4gQWxpcXVhbSBibGFuZGl0IHNlbXBlciBibGFuZGl0LiBVdCBlZ2Vz +dGFzIGVyb3Mgc2VkIG5pc2kgZGFwaWJ1cyBhIHNlbXBlciBtZXR1cyBkYXBpYnVz +LiBNb3JiaSB2dWxwdXRhdGUgbGFvcmVldCB2ZWxpdCwgZXUgYmliZW5kdW0gYXJj +dSBjb21tb2RvIG5vbi4gTWFlY2VuYXMgZmVsaXMgbnVuYywgdm9sdXRwYXQgaWQg +dmVzdGlidWx1bSB2aXRhZSwgdmVzdGlidWx1bSB2aXRhZSBhbnRlLgoKU2VkIG51 +bmMgaXBzdW0sIGF1Y3RvciB2ZWwgZmV1Z2lhdCBzaXQgYW1ldCwgaW50ZXJkdW0g +YXQgbGlndWxhLiBNYXVyaXMgcXVpcyBuaXNpIGVnZXQgbGVjdHVzIGdyYXZpZGEg +c2VtcGVyIGluIHF1aXMgZW5pbS4gTnVsbGEgYXVjdG9yIGVsZW1lbnR1bSBqdXN0 +bywgbm9uIGJpYmVuZHVtIGR1aSBmZXJtZW50dW0gYWMuIEZ1c2NlIGxvcmVtIGF1 +Z3VlLCBjb21tb2RvIG5vbiB0aW5jaWR1bnQgc2l0IGFtZXQsIGFjY3Vtc2FuIHNl +ZCBtZXR1cy4gTmFtIHNhcGllbiBlbmltLCBkaWduaXNzaW0gZXQgdmFyaXVzIGV1 +LCBsdWN0dXMgYXQgb3JjaS4gTnVsbGFtIGxpYmVybyBvcmNpLCBiaWJlbmR1bSBh +IGxhY2luaWEgYWMsIHZ1bHB1dGF0ZSBmYXVjaWJ1cyBtaS4gTW9yYmkgY29uZGlt +ZW50dW0gZmVybWVudHVtIGRpZ25pc3NpbS4gTG9yZW0gaXBzdW0gZG9sb3Igc2l0 +IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4gUXVpc3F1ZSBldCBu +ZXF1ZSBlcmF0LCB1dCB2b2x1dHBhdCBsZW8uIFZlc3RpYnVsdW0gdmVsIGxpZ3Vs +YSBuZXF1ZS4gTnVuYyBwaGFyZXRyYSBsaWJlcm8gaW4gbWF1cmlzIGRhcGlidXMg +aW4gbGFvcmVldCBkdWkgbHVjdHVzLiBQaGFzZWxsdXMgdmVsaXQgbmlzaSwgZGlj +dHVtIGF0IHZvbHV0cGF0IG5lYywgaGVuZHJlcml0IGZhY2lsaXNpcyBlc3QuIFN1 +c3BlbmRpc3NlIG1hdXJpcyBwdXJ1cywgZGlnbmlzc2ltIHNpdCBhbWV0IHRpbmNp +ZHVudCBhYywgaWFjdWxpcyBpZCBzZW0uIER1aXMgcmlzdXMganVzdG8sIGZyaW5n +aWxsYSBhdCB2dWxwdXRhdGUgYXQsIGxvYm9ydGlzIG5vbiBhcmN1LiBBbGlxdWFt +IGVyYXQgdm9sdXRwYXQuCgpWaXZhbXVzIGxlY3R1cyBtaSwgdWxsYW1jb3JwZXIg +ZXQgZmV1Z2lhdCBzaXQgYW1ldCwgZ3JhdmlkYSBxdWlzIHZlbGl0LiBDcmFzIHRp +bmNpZHVudCBtZXR1cyByaXN1cywgZWdldCB0cmlzdGlxdWUgYXJjdS4gTnVuYyBl +Z2V0IGxlbyBhIGVsaXQgdGVtcG9yIHBvcnR0aXRvci4gQ3VtIHNvY2lpcyBuYXRv +cXVlIHBlbmF0aWJ1cyBldCBtYWduaXMgZGlzIHBhcnR1cmllbnQgbW9udGVzLCBu +YXNjZXR1ciByaWRpY3VsdXMgbXVzLiBQcmFlc2VudCB0ZW1wdXMgbnVuYyBlZ2V0 +IG5pYmggY29uc2VjdGV0dXIgYWMgY29udmFsbGlzIGVuaW0gc2FnaXR0aXMuIEFs +aXF1YW0gaXBzdW0gdXJuYSwgZmF1Y2lidXMgYWMgdHJpc3RpcXVlIHZlbCwgbGFv +cmVldCBhIGxlby4gUGhhc2VsbHVzIGNvbmRpbWVudHVtIGVuaW0gZWdldCBpcHN1 +bSB2b2x1dHBhdCB1dCBhY2N1bXNhbiBuaWJoIHBlbGxlbnRlc3F1ZS4gTnVsbGFt +IGxhb3JlZXQsIHRvcnRvciBpbiB1bGxhbWNvcnBlciBmcmluZ2lsbGEsIGR1aSBv +ZGlvIHNjZWxlcmlzcXVlIHB1cnVzLCB1dCBpYWN1bGlzIGVyYXQgcmlzdXMgYWMg +bnVsbGEuIEFsaXF1YW0gZWdlc3RhcyBsYWNpbmlhIGFsaXF1YW0uIE1hdXJpcyBi +bGFuZGl0LCB0b3J0b3IgcXVpcyBtb2xsaXMgcGVsbGVudGVzcXVlLCBudWxsYSBt +YWduYSB2ZXN0aWJ1bHVtIGVyYXQsIGV0IHRyaXN0aXF1ZSBsaWd1bGEgc2VtIGVn +ZXQgdGVsbHVzLiBWZXN0aWJ1bHVtIGZlbGlzIHRvcnRvciwgc2VtcGVyIGluIHN1 +c2NpcGl0IGVnZXQsIHRpbmNpZHVudCB2ZWwgdmVsaXQuCgpNYWVjZW5hcyBzZW0g +dGVsbHVzLCBiaWJlbmR1bSBhYyBjdXJzdXMgdXQsIGZldWdpYXQgdmVsIHRvcnRv +ci4gU2VkIHZlbmVuYXRpcyBmZWxpcyBhIGF1Z3VlIHByZXRpdW0gZXUgbGFvcmVl +dCBkdWkgbWF0dGlzLiBNYWVjZW5hcyByaG9uY3VzIHZlc3RpYnVsdW0gbWFnbmEg +ZWdldCBjb252YWxsaXMuIE51bGxhIGZhY2lsaXNpLiBGdXNjZSBpbnRlcmR1bSBk +aWN0dW0gbGVvIG5lYyBhZGlwaXNjaW5nLiBOdW5jIHZpdGFlIGxvcmVtIHF1YW0u +IEluIHVsdHJpY2llcyBzZW0gZXUgbGlndWxhIGVsZWlmZW5kIGluIHNhZ2l0dGlz +IGFyY3UgcnV0cnVtLiBOdWxsYW0gZGlhbSBqdXN0bywgZmVybWVudHVtIG5lYyBs +dWN0dXMgZXUsIGltcGVyZGlldCBuZWMgbGliZXJvLiBJbnRlZ2VyIGhlbmRyZXJp +dCB0ZW1wb3IgZGFwaWJ1cy4gU3VzcGVuZGlzc2UgcG90ZW50aS4gRG9uZWMgdXQg +YXJjdSBuZWMgbG9yZW0gbHVjdHVzIHZhcml1cyB2aXRhZSBhIG51bmMuIEZ1c2Nl +IGEgc2FwaWVuIGxhb3JlZXQgdGVsbHVzIGFkaXBpc2NpbmcgdmVzdGlidWx1bS4g +QWxpcXVhbSB2YXJpdXMgZGljdHVtIG1pIGVnZXQgZmV1Z2lhdC4gRXRpYW0gc2Vk +IGxlbyBldCBtYXVyaXMgZmV1Z2lhdCBldWlzbW9kLiBTdXNwZW5kaXNzZSBxdWlz +IG1hZ25hIG1hZ25hLCBhIHRpbmNpZHVudCBvcmNpLiBMb3JlbSBpcHN1bSBkb2xv +ciBzaXQgYW1ldCwgY29uc2VjdGV0dXIgYWRpcGlzY2luZyBlbGl0LiBEb25lYyBu +aXNpIHR1cnBpcywgYWxpcXVldCBldSBzb2xsaWNpdHVkaW4gdml0YWUsIGxhb3Jl +ZXQgbmVjIG5pc2kuIFZlc3RpYnVsdW0gdHJpc3RpcXVlLCB2ZWxpdCB2aXRhZSB1 +bGxhbWNvcnBlciBjb25kaW1lbnR1bSwgbGVjdHVzIG9yY2kgcG9ydHRpdG9yIGFy +Y3UsIGV1IHBsYWNlcmF0IGZlbGlzIHB1cnVzIG5lYyBvcmNpLiBOYW0gaXBzdW0g +YXVndWUsIHNjZWxlcmlzcXVlIGF0IGxhY2luaWEgc2l0IGFtZXQsIG1hdHRpcyBh +IGVyYXQuIFBoYXNlbGx1cyBhIG1hZ25hIHF1aXMgbGFjdXMgdmFyaXVzIHBsYWNl +cmF0LgoKUHJvaW4gb3JuYXJlIHZpdmVycmEgcGxhY2VyYXQuIFNlZCBpYWN1bGlz +IHVsdHJpY2VzIG1hZ25hLCBjb252YWxsaXMgYXVjdG9yIG1pIHRyaXN0aXF1ZSB2 +ZWwuIFBlbGxlbnRlc3F1ZSBhYyBuaXNpIHNpdCBhbWV0IG5pc2kgYWxpcXVhbSB0 +aW5jaWR1bnQgYWMgdXQgaXBzdW0uIFByYWVzZW50IGEgdGVsbHVzIG5vbiBudW5j +IGlhY3VsaXMgYWRpcGlzY2luZy4gUXVpc3F1ZSBmYWNpbGlzaXMganVzdG8gZWdl +dCBtZXR1cyBncmF2aWRhIHVsbGFtY29ycGVyLiBEb25lYyBzYWdpdHRpcywgdG9y +dG9yIGV1aXNtb2QgYWxpcXVhbSBpbnRlcmR1bSwgYXVndWUgYXVndWUgbGFvcmVl +dCBlbGl0LCBpbiBjb21tb2RvIHVybmEgbGFjdXMgdmVsIGVzdC4gVmVzdGlidWx1 +bSBkdWkgbmliaCwgdmFyaXVzIGEgaW50ZXJkdW0gYSwgcG9ydGEgdXQgbWV0dXMu +IFV0IGxlY3R1cyB1cm5hLCBwb3N1ZXJlIGluIGx1Y3R1cyBldCwgcnV0cnVtIGEg +ZXJhdC4gU3VzcGVuZGlzc2UgY3Vyc3VzLCB0b3J0b3Igdml0YWUgc2NlbGVyaXNx +dWUgdHJpc3RpcXVlLCBkb2xvciBlcmF0IGRpZ25pc3NpbSBsZWN0dXMsIG5lYyBz +b2RhbGVzIG1hdXJpcyB0ZWxsdXMgdmVsIHB1cnVzLiBEdWlzIGVsaXQgbWF1cmlz +LCBhY2N1bXNhbiB1dCBwb3N1ZXJlIHZ1bHB1dGF0ZSwgbWFsZXN1YWRhIGV0IGFu +dGUuIE1vcmJpIGJsYW5kaXQgbGFjdXMgYXQgbWF1cmlzIHNhZ2l0dGlzIHJ1dHJ1 +bS4gUGhhc2VsbHVzIGRvbG9yIG1hdXJpcywgY29uc2VxdWF0IHZlbCBmYXVjaWJ1 +cyB2ZWwsIHB1bHZpbmFyIG5lYyBhcmN1LiBOYW0gY29tbW9kbywgcHVydXMgdml0 +YWUgbW9sbGlzIHNjZWxlcmlzcXVlLCBzYXBpZW4gdHVycGlzIGJpYmVuZHVtIGFu +dGUsIGV1IGZhY2lsaXNpcyBpcHN1bSBpcHN1bSBuZWMgbmVxdWUuIENsYXNzIGFw +dGVudCB0YWNpdGkgc29jaW9zcXUgYWQgbGl0b3JhIHRvcnF1ZW50IHBlciBjb251 +YmlhIG5vc3RyYSwgcGVyIGluY2VwdG9zIGhpbWVuYWVvcy4gUGVsbGVudGVzcXVl +IGNvbnZhbGxpcyBkaWduaXNzaW0gbWFnbmEgc2l0IGFtZXQgdnVscHV0YXRlLiBT +ZWQgY29uZGltZW50dW0gdmVoaWN1bGEgbWF0dGlzLiBWaXZhbXVzIHRpbmNpZHVu +dCBmYWNpbGlzaXMgaXBzdW0sIGV0IHBvcnRhIHJpc3VzIHVsdHJpY2VzIHZpdGFl +LiBRdWlzcXVlIG5vbiBjb25zZXF1YXQgbmlzbC4gQ3VyYWJpdHVyIGp1c3RvIG51 +bGxhLCBiaWJlbmR1bSBpbiB2ZW5lbmF0aXMgZWdldCwgcG9zdWVyZSBlZ2V0IHNl +bS4KClBlbGxlbnRlc3F1ZSBzaXQgYW1ldCByaXN1cyB2ZWwgbGliZXJvIGV1aXNt +b2Qgc3VzY2lwaXQgdmVsIHNpdCBhbWV0IG1ldHVzLiBEb25lYyBncmF2aWRhLCBs +ZW8gcXVpcyBpbnRlcmR1bSBjb25ndWUsIHF1YW0gbGVjdHVzIHRyaXN0aXF1ZSBu +aXNpLCBldSB1bHRyaWNlcyBzZW0gdHVycGlzIHRpbmNpZHVudCBlc3QuIFByYWVz +ZW50IHB1bHZpbmFyIGNvbnZhbGxpcyB1cm5hIHZpdGFlIGlhY3VsaXMuIFV0IGNv +bnZhbGxpcyBwdWx2aW5hciBmYWNpbGlzaXMuIEN1bSBzb2NpaXMgbmF0b3F1ZSBw +ZW5hdGlidXMgZXQgbWFnbmlzIGRpcyBwYXJ0dXJpZW50IG1vbnRlcywgbmFzY2V0 +dXIgcmlkaWN1bHVzIG11cy4gQWVuZWFuIGV0IGVyYXQgZG9sb3IsIGFjIHBvc3Vl +cmUgbWV0dXMuIFNlZCBjb25kaW1lbnR1bSBhZGlwaXNjaW5nIGlwc3VtLCBlZ2V0 +IHVsdHJpY2llcyBqdXN0byBmZXJtZW50dW0gc2l0IGFtZXQuIE5hbSBmZXJtZW50 +dW0gbGVvIHZpdGFlIGxlY3R1cyBtYXR0aXMgaW1wZXJkaWV0LiBFdGlhbSBkb2xv +ciBsYWN1cywgbWF0dGlzIGF0IHRlbXB1cyBldSwgY29uZ3VlIHZlbCB2ZWxpdC4g +UHJhZXNlbnQgYmxhbmRpdCB2aXZlcnJhIHJob25jdXMuIFBlbGxlbnRlc3F1ZSB2 +aXRhZSBsYWN1cyBsZW8uCgpRdWlzcXVlIGlkIGxvcmVtIHF1aXMgdHVycGlzIGx1 +Y3R1cyBjb25zZXF1YXQgaW4gc2l0IGFtZXQgZXN0LiBDdXJhYml0dXIgdHJpc3Rp +cXVlLCBhcmN1IGEgY3Vyc3VzIHZvbHV0cGF0LCBudWxsYSBlc3QgYXVjdG9yIHRl +bGx1cywgbmVjIGZhY2lsaXNpcyBuaWJoIGF1Z3VlIG5lYyBvcmNpLiBNYXVyaXMg +ZmV1Z2lhdCwgZXN0IGFjIGF1Y3RvciBldWlzbW9kLCBvZGlvIG5pYmggYWNjdW1z +YW4gbmVxdWUsIGluIGZlcm1lbnR1bSBvcmNpIG1hc3NhIHZpdGFlIGF1Z3VlLiBQ +ZWxsZW50ZXNxdWUgcXVpcyBtaSBhcmN1LCBub24gaW1wZXJkaWV0IGlwc3VtLiBO +dWxsYW0gZGFwaWJ1cyBoZW5kcmVyaXQgZmVsaXMsIGFjIHVsbGFtY29ycGVyIHRv +cnRvciBwaGFyZXRyYSBldC4gTnVsbGEgYWNjdW1zYW4sIGxhY3VzIHNlZCBlbGVt +ZW50dW0gaW50ZXJkdW0sIG1pIGFyY3UgdmVzdGlidWx1bSBuZXF1ZSwgZWdldCBm +YWNpbGlzaXMgZXJvcyBudW5jIGF0IGVsaXQuIFN1c3BlbmRpc3NlIGV1IG1hdXJp +cyBzdXNjaXBpdCBwdXJ1cyBkaWN0dW0gaWFjdWxpcy4gUHJhZXNlbnQgc2l0IGFt +ZXQgbnVuYyBuZWMgbGFjdXMgZmFjaWxpc2lzIHBvcnRhLiBNYXVyaXMgbnVuYyBp +cHN1bSwgc29sbGljaXR1ZGluIHNlZCBwb3N1ZXJlIGluLCBmZXJtZW50dW0gYWMg +dGVsbHVzLiBOdWxsYSBmcmluZ2lsbGEgc2NlbGVyaXNxdWUgZXJhdCBpZCBwbGFj +ZXJhdC4KCkludGVnZXIgZnJpbmdpbGxhIGZlcm1lbnR1bSB0dXJwaXMgZWdldCBs +YW9yZWV0LiBTdXNwZW5kaXNzZSBwb3N1ZXJlIGVzdCBhYyBlcm9zIGNvbnNlcXVh +dCBub24gZGlnbmlzc2ltIHB1cnVzIGFsaXF1ZXQuIE1hdXJpcyBwcmV0aXVtIHZl +bmVuYXRpcyBwdWx2aW5hci4gVXQgbmVxdWUgbWV0dXMsIGN1cnN1cyBpZCBkaWdu +aXNzaW0gc2l0IGFtZXQsIGNvbmRpbWVudHVtIGVnZXQgZXJvcy4gQWxpcXVhbSBl +cmF0IHZvbHV0cGF0LiBFdGlhbSBwb3J0YSBhbGlxdWFtIG5pc2ksIHNpdCBhbWV0 +IGNvbnNlY3RldHVyIHB1cnVzIGxvYm9ydGlzIG5lYy4gVmVzdGlidWx1bSB0aW5j +aWR1bnQgcGxhY2VyYXQgcXVhbSBhYyBjdXJzdXMuIFByYWVzZW50IGxhb3JlZXQg +ZXJvcyBub24gbmVxdWUgcmhvbmN1cyBhYyBoZW5kcmVyaXQgZHVpIHRlbXBvci4g +Q3JhcyBzb2RhbGVzIGVsaXQgdml0YWUgdXJuYSBpbnRlcmR1bSBhY2N1bXNhbi4g +TnVsbGFtIG5lYyBsYW9yZWV0IGFyY3UuIERvbmVjIGZyaW5naWxsYSBzY2VsZXJp +c3F1ZSByaXN1cywgbmVjIHNhZ2l0dGlzIG9kaW8gYWNjdW1zYW4gbm9uLiBRdWlz +cXVlIHJ1dHJ1bSBzb2RhbGVzIG9kaW8uIE1hdXJpcyBmYWNpbGlzaXMsIG5pYmgg +cXVpcyBlbGVpZmVuZCBzb2xsaWNpdHVkaW4sIGR1aSBvZGlvIGF1Y3RvciBvcmNp +LCBldSBwb3J0dGl0b3IgYXJjdSBudW5jIGFjIGxpZ3VsYS4gSW4gc2VkIG1pIG5l +cXVlLiBNYXVyaXMgZWdlc3RhcywgdGVsbHVzIHNlZCBldWlzbW9kIGVnZXN0YXMs +IGVyb3MgbGlndWxhIGdyYXZpZGEgcmlzdXMsIGF0IGFsaXF1YW0gbGVvIGxpZ3Vs +YSB1dCBvZGlvLiBBbGlxdWFtIHZlbCB2YXJpdXMgc2FwaWVuLiBFdGlhbSBldSBs +ZW8gZXJvcywgcXVpcyBjb25zZXF1YXQgbWkuIE51bGxhbSBzb2RhbGVzIHBlbGxl +bnRlc3F1ZSBvZGlvIG5vbiB0cmlzdGlxdWUuCgpBbGlxdWFtIGVyYXQgdm9sdXRw +YXQuIEFlbmVhbiBsYW9yZWV0LCBudW5jIGVnZXQgbW9sbGlzIGF1Y3RvciwgbWkg +bGlndWxhIGxvYm9ydGlzIGR1aSwgYSB1bHRyaWNpZXMgcXVhbSB2ZWxpdCB1dCBz +YXBpZW4uIFV0IHZlbCBpYWN1bGlzIG5pYmguIEV0aWFtIHV0IHJpc3VzIGR1aS4g +TWF1cmlzIGF0IGp1c3RvIGZlbGlzLiBNYXVyaXMgaWFjdWxpcyBiaWJlbmR1bSB2 +ZWxpdCBlZ2V0IGRhcGlidXMuIEFsaXF1YW0gZXJhdCB2b2x1dHBhdC4gTnVsbGEg +c2l0IGFtZXQgb3JjaSBhbnRlLCBhIGVnZXN0YXMgc2FwaWVuLiBNb3JiaSB1bGxh +bWNvcnBlciBsZWN0dXMgdmVsIG1hdXJpcyB2ZXN0aWJ1bHVtIG1hbGVzdWFkYS4g +Q3JhcyB2ZWwgbGVjdHVzIGlwc3VtLiBEdWlzIGVnZXN0YXMgdmVuZW5hdGlzIHBy +ZXRpdW0uIE1vcmJpIHNlZCB0b3J0b3IgZXUgb2RpbyBzdXNjaXBpdCBydXRydW0u +IFNlZCB1bHRyaWNlcyBtYXNzYSBmZXJtZW50dW0gbGFjdXMgdGVtcHVzIHBoYXJl +dHJhLiBJbiBldCBtYXVyaXMgcXVhbSwgaWQgZnJpbmdpbGxhIG1ldHVzLgoKQWVu +ZWFuIG5lYyB2ZWxpdCBkdWkuIE51bGxhbSBlZ2VzdGFzIG1pIGV1IGlwc3VtIHVs +dHJpY2VzIGVnZXQgdmVuZW5hdGlzIHZlbGl0IGxhY2luaWEuIFZpdmFtdXMgbmVj +IGxpZ3VsYSBzaXQgYW1ldCBqdXN0byBhZGlwaXNjaW5nIHZhcml1cyB1dCB1dCBw +dXJ1cy4gQWVuZWFuIGx1Y3R1cyBuaXNsIGVnZXQgbmlzbCB1bHRyaWNlcyBpbXBl +cmRpZXQuIFZpdmFtdXMgYSBuaWJoIGF0IGVsaXQgc29kYWxlcyBldWlzbW9kLiBB +ZW5lYW4gaGVuZHJlcml0IG5pc2kgdmVsIG1ldHVzIGNvbnZhbGxpcyB2dWxwdXRh +dGUuIE1vcmJpIHVybmEgdHVycGlzLCB0ZW1wb3IgYXQgcHVsdmluYXIgdmVsLCBj +b25zZWN0ZXR1ciBldSBtZXR1cy4gTmFtIGZyaW5naWxsYSBtYXVyaXMgc2VkIG9y +Y2kgcG9ydGEgYWMgbW9sbGlzIG51bGxhIGJsYW5kaXQuIEluIHVsdHJpY2llcyB2 +ZWxpdCBhdWN0b3IgYXJjdSBncmF2aWRhIGZlcm1lbnR1bS4gVXQgdmVsIG5lcXVl +IGV0IHZlbGl0IHByZXRpdW0gYmxhbmRpdCBldSBpbiBhbnRlLiBWZXN0aWJ1bHVt +IHV0IGR1aSBtYWduYS4gTmFtIGV0IGxhY3VzIGlwc3VtLCBzZWQgdGluY2lkdW50 +IHRlbGx1cy4gRG9uZWMgZWxlbWVudHVtIGVsZWlmZW5kIHRvcnRvciB1dCB2ZXN0 +aWJ1bHVtLgoKRXRpYW0gdm9sdXRwYXQgbWV0dXMgc2VkIGxvcmVtIGRhcGlidXMg +bGFjaW5pYS4gQ2xhc3MgYXB0ZW50IHRhY2l0aSBzb2Npb3NxdSBhZCBsaXRvcmEg +dG9ycXVlbnQgcGVyIGNvbnViaWEgbm9zdHJhLCBwZXIgaW5jZXB0b3MgaGltZW5h +ZW9zLiBWZXN0aWJ1bHVtIGEgYmxhbmRpdCBuaWJoLiBQaGFzZWxsdXMgZXQgbG9y +ZW0gdmVsIGVyb3MgaWFjdWxpcyB1bHRyaWNpZXMuIFNlZCBzaXQgYW1ldCBtYWdu +YSBzaXQgYW1ldCBlc3QgbW9sZXN0aWUgcHJldGl1bSBzZWQgbmVjIG9yY2kuIFN1 +c3BlbmRpc3NlIHBvdGVudGkuIE51bGxhIGNvbnZhbGxpcyBhbnRlIHZpdGFlIGRv +bG9yIGNvbnZhbGxpcyBub24gdmFyaXVzIG5lcXVlIHBlbGxlbnRlc3F1ZS4gQ3Jh +cyBldWlzbW9kIG1hc3NhIGEgZXJvcyBhbGlxdWFtIHVsdHJpY2VzLiBTZWQgdml0 +YWUgcHVydXMgdXQgbmlzaSBmYXVjaWJ1cyBmZXVnaWF0LiBQcmFlc2VudCBhIGxl +Y3R1cyBldCB2ZWxpdCBlZ2VzdGFzIHBoYXJldHJhIGV0IHNpdCBhbWV0IGRvbG9y +LiBEdWlzIHF1aXMgbGFjaW5pYSBvZGlvLiBTZWQgc2VkIGVuaW0gbGVvLiBEb25l +YyBwdWx2aW5hciBzb2xsaWNpdHVkaW4gbmVxdWUgdXQgZnJpbmdpbGxhLiBFdGlh +bSBtYWxlc3VhZGEgbmlzbCBkaWN0dW0gZXJhdCBkaWN0dW0gZGFwaWJ1cy4gRnVz +Y2UgZmFjaWxpc2lzLCBtaSB2ZWwgdmFyaXVzIG9ybmFyZSwgdG9ydG9yIG51bGxh +IG9ybmFyZSBlcm9zLCBhdCBldWlzbW9kIG5pYmggbmlzaSBldCBhdWd1ZS4gTWFl +Y2VuYXMgZWdldCBzYXBpZW4gbWkuIFNlZCBzZWQgbnVsbGEgbGVjdHVzLiBOdW5j +IGRpZ25pc3NpbSBsdWN0dXMgbGVjdHVzLCBhdCBhbGlxdWV0IGRvbG9yIHZlbmVu +YXRpcyBxdWlzLiBVdCBwdWx2aW5hciwgdG9ydG9yIHNpdCBhbWV0IHNjZWxlcmlz +cXVlIHBoYXJldHJhLCBmZWxpcyBsZW8gcHJldGl1bSBmZWxpcywgZXQgbWF0dGlz +IHNhcGllbiBtYXVyaXMgbWF0dGlzIG51bGxhLgoKU3VzcGVuZGlzc2UgcG90ZW50 +aS4gTnVuYyBxdWlzIHB1bHZpbmFyIHF1YW0uIER1aXMgZGFwaWJ1cyBiaWJlbmR1 +bSBmYWNpbGlzaXMuIE51bGxhbSBsb2JvcnRpcyBlcmF0IHNpdCBhbWV0IHF1YW0g +YWRpcGlzY2luZyBldSBtb2xlc3RpZSB0b3J0b3IgYWNjdW1zYW4uIFByYWVzZW50 +IHB1bHZpbmFyIGVuaW0gZXUganVzdG8gZGFwaWJ1cyBpbiB2aXZlcnJhIG1hdXJp +cyBjb21tb2RvLiBFdGlhbSBtb2xsaXMgY29uc2VxdWF0IHZlbGl0LCBub24gbW9s +ZXN0aWUgZXJvcyBjb25kaW1lbnR1bSBhYy4gRXRpYW0gdml0YWUgZXJhdCBuZWMg +ZWxpdCBjb25ndWUgY29uZGltZW50dW0gYSB1bGxhbWNvcnBlciB0dXJwaXMuIFZl +c3RpYnVsdW0gYW50ZSBpcHN1bSBwcmltaXMgaW4gZmF1Y2lidXMgb3JjaSBsdWN0 +dXMgZXQgdWx0cmljZXMgcG9zdWVyZSBjdWJpbGlhIEN1cmFlOyBWZXN0aWJ1bHVt +IHZpdGFlIGxvcmVtIGV0IGxlY3R1cyBjb252YWxsaXMgY29uc2VjdGV0dXIuIFN1 +c3BlbmRpc3NlIHNpdCBhbWV0IGZlbGlzIG5vbiBtZXR1cyBtYXR0aXMgbG9ib3J0 +aXMuIE1vcmJpIGV1IG51bGxhIHRvcnRvci4gTWFlY2VuYXMgaGVuZHJlcml0IG9y +Y2kgc2l0IGFtZXQgbGlndWxhIGludGVyZHVtIGV0IGlhY3VsaXMgbnVsbGEgcGxh +Y2VyYXQuIE5hbSBkaWN0dW0gbGFjdXMgYXQgYXJjdSByaG9uY3VzIGVsZWlmZW5k +LiBJbiBoYWMgaGFiaXRhc3NlIHBsYXRlYSBkaWN0dW1zdC4KCkN1cmFiaXR1ciBh +YyB2ZW5lbmF0aXMgZHVpLiBDbGFzcyBhcHRlbnQgdGFjaXRpIHNvY2lvc3F1IGFk +IGxpdG9yYSB0b3JxdWVudCBwZXIgY29udWJpYSBub3N0cmEsIHBlciBpbmNlcHRv +cyBoaW1lbmFlb3MuIEludGVnZXIgYXVjdG9yIHBvcnRhIG5lcXVlIHZlbCBwZWxs +ZW50ZXNxdWUuIEFlbmVhbiBhYyBwdXJ1cyBxdWlzIHZlbGl0IGlhY3VsaXMgcG9y +dHRpdG9yIGluIGluIHNlbS4gRHVpcyB0aW5jaWR1bnQgcmlzdXMgaW4gcmlzdXMg +ZmF1Y2lidXMgYSBhbGlxdWFtIGRpYW0gYXVjdG9yLiBOdWxsYW0gc2VtIGF1Z3Vl +LCBhZGlwaXNjaW5nIHNlZCB0aW5jaWR1bnQgcXVpcywgbW9sZXN0aWUgc2VkIGxp +YmVyby4gVmVzdGlidWx1bSBjb21tb2RvIG9kaW8gdGVtcG9yIG51bGxhIG9ybmFy +ZSBwbGFjZXJhdC4gTW9yYmkgZG9sb3IgbWFzc2EsIGJpYmVuZHVtIGluIGVsZWlm +ZW5kIGlkLCBtb2xlc3RpZSB1dCBqdXN0by4gUXVpc3F1ZSB2YXJpdXMgbnVuYyBz +aXQgYW1ldCBuaXNsIGRhcGlidXMgZmFjaWxpc2lzLiBEb25lYyB1dCBlcmF0IG1p +LiBEdWlzIGVnZXQgY29uc2VjdGV0dXIgbWFnbmEuIE1hdXJpcyBlZ2VzdGFzIHNl +bXBlciBlZ2VzdGFzLiBTZWQgZXQganVzdG8gc2VkIG51bGxhIGJsYW5kaXQgYWNj +dW1zYW4gYXQgbm9uIGxlby4gSW4gZWdldCBlc3QgaXBzdW0uIE51bGxhIHRlbGx1 +cyBsaWd1bGEsIGFsaXF1ZXQgc2l0IGFtZXQgdnVscHV0YXRlIHZpdGFlLCBtb2xs +aXMgZXUgZXJhdC4KCkFlbmVhbiBhYyBhdWd1ZSBvZGlvLiBQcm9pbiBtb2xsaXMs +IGRvbG9yIHV0IGZldWdpYXQgc3VzY2lwaXQsIGR1aSBhbnRlIGNvbnNlY3RldHVy +IG9kaW8sIHZpdGFlIGNvbmRpbWVudHVtIHRlbGx1cyBudWxsYSBhYyBmZWxpcy4g +UGVsbGVudGVzcXVlIGVnZXN0YXMgdWx0cmljZXMgbnVuYywgZXUgc2FnaXR0aXMg +c2FwaWVuIGV1aXNtb2Qgdml0YWUuIEludGVnZXIgc29sbGljaXR1ZGluIGZldWdp +YXQgbGVvIG5lYyBjb25zZWN0ZXR1ci4gUHJhZXNlbnQgc2l0IGFtZXQgc2VtIGVy +YXQsIG5lYyB2b2x1dHBhdCBsYWN1cy4gRXRpYW0gYSBsYWN1cyBudWxsYSwgbm9u +IGludGVyZHVtIGVyYXQuIE1hZWNlbmFzIHF1aXMgZGljdHVtIGxlY3R1cy4gUGVs +bGVudGVzcXVlIGFjIGxpYmVybyB2ZWwgZWxpdCB0cmlzdGlxdWUgc2VtcGVyLiBR +dWlzcXVlIGV1IHN1c2NpcGl0IGR1aS4gSW4gaGFjIGhhYml0YXNzZSBwbGF0ZWEg +ZGljdHVtc3QuIENyYXMgZXUgcG9ydGEgcXVhbS4gQ3VyYWJpdHVyIHBoYXJldHJh +LCBmZWxpcyB1dCByaG9uY3VzIHRpbmNpZHVudCwgbnVsbGEgYXVndWUgcGxhY2Vy +YXQgc2FwaWVuLCBpZCB2ZXN0aWJ1bHVtIG5pc2wgbmVxdWUgYXQgZGlhbS4KClF1 +aXNxdWUgbGFvcmVldCBkYXBpYnVzIGx1Y3R1cy4gTW9yYmkgZXJhdCBvZGlvLCBt +YXR0aXMgc2l0IGFtZXQgdWx0cmljaWVzIGV1LCBpbnRlcmR1bSBldCBudWxsYS4g +TmFtIHZ1bHB1dGF0ZSwgbWV0dXMgbm9uIGVsZW1lbnR1bSBoZW5kcmVyaXQsIHVy +bmEgcHVydXMgcGhhcmV0cmEgZWxpdCwgdml0YWUgc29kYWxlcyBwdXJ1cyBsaWd1 +bGEgbm9uIHF1YW0uIEV0aWFtIGlkIGxpZ3VsYSB0aW5jaWR1bnQgbGVvIHBlbGxl +bnRlc3F1ZSBibGFuZGl0LiBVdCBhbnRlIHVybmEsIHZlc3RpYnVsdW0gc2VkIGVs +ZW1lbnR1bSBhYywgcGVsbGVudGVzcXVlIHNpdCBhbWV0IHRvcnRvci4gRnVzY2Ug +dmVuZW5hdGlzIGNvbW1vZG8gYW50ZSBhdCB0ZW1wb3IuIE51bGxhIGluIG9kaW8g +bGVjdHVzLiBEb25lYyBsYWNpbmlhIGRhcGlidXMgdmVoaWN1bGEuIFN1c3BlbmRp +c3NlIHNjZWxlcmlzcXVlIG9kaW8gdXQgbG9yZW0gZGlnbmlzc2ltIGlkIHByZXRp +dW0gdG9ydG9yIHN1c2NpcGl0LiBOdWxsYW0gZmVsaXMgYW50ZSwgZmVybWVudHVt +IGVnZXQgc29sbGljaXR1ZGluIHNpdCBhbWV0LCBjb21tb2RvIGF0IGVuaW0uIERv +bmVjIGFsaXF1ZXQgbWF1cmlzIGluIGVsaXQgYXVjdG9yIGF0IGNvbnZhbGxpcyBx +dWFtIHVsbGFtY29ycGVyLiBEdWlzIGVuaW0gbmliaCwgdnVscHV0YXRlIGluIGZh +Y2lsaXNpcyBpZCwgYWRpcGlzY2luZyBpbnRlcmR1bSBsYWN1cy4gQWVuZWFuIHNv +bGxpY2l0dWRpbiBjb25ndWUgY29uc2VjdGV0dXIuIFByYWVzZW50IGxvYm9ydGlz +IG5pc2wgZXQgbWV0dXMgZXVpc21vZCBjb25ndWUuIFN1c3BlbmRpc3NlIGlkIHRl +bXB1cyBpcHN1bS4KCkRvbmVjIGV1IGF1Y3RvciBzYXBpZW4uIEluIHBsYWNlcmF0 +IGF1Y3RvciBtYXNzYSB1dCBwbGFjZXJhdC4gVml2YW11cyBhdCB0dXJwaXMgZWxp +dC4gRG9uZWMgY29uZ3VlIHJob25jdXMgZXN0IGEgdml2ZXJyYS4gTnVuYyBub24g +b2RpbyBlbmltLiBDdW0gc29jaWlzIG5hdG9xdWUgcGVuYXRpYnVzIGV0IG1hZ25p +cyBkaXMgcGFydHVyaWVudCBtb250ZXMsIG5hc2NldHVyIHJpZGljdWx1cyBtdXMu +IE1hZWNlbmFzIHF1aXMgbWFzc2EgbGliZXJvLCBxdWlzIGVsZW1lbnR1bSBtYXVy +aXMuIFZlc3RpYnVsdW0gYW50ZSBpcHN1bSBwcmltaXMgaW4gZmF1Y2lidXMgb3Jj +aSBsdWN0dXMgZXQgdWx0cmljZXMgcG9zdWVyZSBjdWJpbGlhIEN1cmFlOyBWZXN0 +aWJ1bHVtIHZhcml1cyB2ZWxpdCBhIG9yY2kgZ3JhdmlkYSB1bHRyaWNpZXMgc2Vk +IHZlbCBsaWd1bGEuIFZlc3RpYnVsdW0gcHJldGl1bSB2ZWhpY3VsYSBhbGlxdWV0 +LiBTdXNwZW5kaXNzZSBhdWN0b3IgY29uZ3VlIG1hZ25hLCBhYyBjb252YWxsaXMg +ZGlhbSB1bGxhbWNvcnBlciB2ZWwuCgpBZW5lYW4gcGxhY2VyYXQgbW9sbGlzIGlw +c3VtLCBuZWMgdWxsYW1jb3JwZXIgcXVhbSBoZW5kcmVyaXQgZWdldC4gQWVuZWFu +IHNlZCBpcHN1bSBhIGFyY3UgbG9ib3J0aXMgdGluY2lkdW50LiBDbGFzcyBhcHRl +bnQgdGFjaXRpIHNvY2lvc3F1IGFkIGxpdG9yYSB0b3JxdWVudCBwZXIgY29udWJp +YSBub3N0cmEsIHBlciBpbmNlcHRvcyBoaW1lbmFlb3MuIEV0aWFtIGNvbnZhbGxp +cyB0b3J0b3Igc2FnaXR0aXMgbmlzbCBwb3J0YSBmZXJtZW50dW0uIFZpdmFtdXMg +YWNjdW1zYW4gbHVjdHVzIGNvbmd1ZS4gTWF1cmlzIGV0IGxlY3R1cyBsb3JlbS4g +TnVuYyBldCBudW5jIGV0IGF1Z3VlIGdyYXZpZGEgYmliZW5kdW0uIE51bGxhbSBz +dXNjaXBpdCBhcmN1IGV0IG1hdXJpcyBpYWN1bGlzIHZpdGFlIGNvbmd1ZSBuaXNs +IHRlbXB1cy4gQ2xhc3MgYXB0ZW50IHRhY2l0aSBzb2Npb3NxdSBhZCBsaXRvcmEg +dG9ycXVlbnQgcGVyIGNvbnViaWEgbm9zdHJhLCBwZXIgaW5jZXB0b3MgaGltZW5h +ZW9zLiBDcmFzIGRvbG9yIHRlbGx1cywgbHVjdHVzIHNlZCBpbXBlcmRpZXQgZXUs +IGFjY3Vtc2FuIG5lYyBsb3JlbS4gQ3JhcyBxdWlzIGlwc3VtIGFudGUuIFZlc3Rp +YnVsdW0gYW50ZSBpcHN1bSBwcmltaXMgaW4gZmF1Y2lidXMgb3JjaSBsdWN0dXMg +ZXQgdWx0cmljZXMgcG9zdWVyZSBjdWJpbGlhIEN1cmFlOyBRdWlzcXVlIHZpdGFl +IGRpYW0gYXVndWUsIGV1IHVsdHJpY2VzIGFyY3UuIFByYWVzZW50IGFudGUgdmVs +aXQsIHZlaGljdWxhIGVnZXQgY3Vyc3VzIGV0LCBjb25zZXF1YXQgc2l0IGFtZXQg +dG9ydG9yLiBNYWVjZW5hcyB1bHRyaWNlcyBsaWd1bGEgaW4gb2RpbyB2ZWhpY3Vs +YSB0aW5jaWR1bnQuIEFlbmVhbiB1bHRyaWNpZXMgaXBzdW0gdXQgc2VtIHZ1bHB1 +dGF0ZSB2aXRhZSBwdWx2aW5hciBkaWFtIGNvbnNlY3RldHVyLiBOYW0gdmVsIGVn +ZXN0YXMgZXJvcy4KClByb2luIHVybmEgbmliaCwgYWxpcXVldCBuZWMgc2FnaXR0 +aXMgYSwgY29uZ3VlIHNlZCBqdXN0by4gTWF1cmlzIHJpc3VzIG5lcXVlLCBibGFu +ZGl0IGN1cnN1cyBzZW1wZXIgZXUsIGZlcm1lbnR1bSBlZ2V0IHB1cnVzLiBDdXJh +Yml0dXIgaW4gbGFjdXMgYXVndWUsIHNpdCBhbWV0IGNvbmRpbWVudHVtIG1pLiBN +YXVyaXMgZXUgc2VtIGlwc3VtLCBpbiB1bHRyaWNlcyBtZXR1cy4gUXVpc3F1ZSBm +cmluZ2lsbGEgc2VtIGEgbmlzaSBjb21tb2RvIHZhcml1cy4gTnVuYyB1bHRyaWNl +cyBwbGFjZXJhdCBwbGFjZXJhdC4gVml2YW11cyBub24gbGVjdHVzIGRvbG9yLCBl +Z2V0IGhlbmRyZXJpdCBhdWd1ZS4gTmFtIHV0IG1hdHRpcyBwdXJ1cy4gSW50ZWdl +ciB2ZWwgdXJuYSBldCB0ZWxsdXMgbGFjaW5pYSBmYWNpbGlzaXMgcGVsbGVudGVz +cXVlIHV0IHRlbGx1cy4gRXRpYW0gbGFvcmVldCByaXN1cyBxdWlzIGVsaXQgZGlj +dHVtIGlkIHRyaXN0aXF1ZSBsZW8gc2VtcGVyLiBVdCBvcm5hcmUgbmlzbCBldSBu +aXNsIHVsbGFtY29ycGVyIGluIHNvbGxpY2l0dWRpbiBtYXVyaXMgZ3JhdmlkYS4g +RXRpYW0gaW4gdGluY2lkdW50IHZlbGl0LiBVdCB0ZW1wdXMgdHVycGlzIHZpdGFl +IHVybmEgc2FnaXR0aXMgdmVsIHBvcnRhIHNlbSB2b2x1dHBhdC4gRHVpcyBub24g +anVzdG8gbWV0dXMsIHRlbXBvciBmYXVjaWJ1cyBxdWFtLiBBbGlxdWFtIGluIGxh +Y3VzIG5lYyBtaSB2ZXN0aWJ1bHVtIGZyaW5naWxsYS4gUHJhZXNlbnQgdGVtcG9y +IGxlY3R1cyBhdCBtZXR1cyBwb3J0YSB1dCBjb25ndWUgZHVpIGZyaW5naWxsYS4K +Ck5hbSBhYyBsZWN0dXMgc2VtLCBhdCB2aXZlcnJhIHJpc3VzLiBDcmFzIHNpdCBh +bWV0IHNvZGFsZXMgbWFzc2EuIFF1aXNxdWUgY29uc2VjdGV0dXIgbGlndWxhIHBv +c3VlcmUgdHVycGlzIGV1aXNtb2QgaW50ZXJkdW0uIFV0IGV1IHRlbGx1cyBldSBt +YXNzYSB1bHRyaWNpZXMgYmliZW5kdW0gdml0YWUgaWQgbWV0dXMuIEN1cmFiaXR1 +ciBpbXBlcmRpZXQgY29uc2VxdWF0IHRpbmNpZHVudC4gVXQgZW5pbSBxdWFtLCBj +b25zZWN0ZXR1ciBhdCBwb3J0dGl0b3IgaW4sIHZhcml1cyBldSBtYWduYS4gTnVu +YyBhcmN1IGVsaXQsIHNvZGFsZXMgbm9uIGRhcGlidXMgdnVscHV0YXRlLCBsYWNp +bmlhIGlkIGZlbGlzLiBDdXJhYml0dXIgbHVjdHVzLCByaXN1cyBxdWlzIHZpdmVy +cmEgY29udmFsbGlzLCBtYXNzYSBqdXN0byB0ZW1wdXMgbGliZXJvLCB2aXRhZSBw +b3J0dGl0b3IgbGlndWxhIHZlbGl0IGEgdHVycGlzLiBOdW5jIHZpdmVycmEsIG1l +dHVzIGEgbWFsZXN1YWRhIGNvbnZhbGxpcywgbmVxdWUgYW50ZSBiaWJlbmR1bSBu +aXNsLCBlZ2V0IGltcGVyZGlldCBlbmltIGxlY3R1cyBldSBlbmltLiBQZWxsZW50 +ZXNxdWUgZW5pbSBuaXNsLCBhZGlwaXNjaW5nIGVnZXQgbW9sZXN0aWUgYXQsIGNv +bnNlY3RldHVyIGV1IG9yY2kuIFNlZCBwb3J0YSB1bGxhbWNvcnBlciBlc3QsIG5l +YyBkaWN0dW0gdHVycGlzIHNlbXBlciBzaXQgYW1ldC4KClF1aXNxdWUgcG9ydGEg +bWkgYWMgdmVsaXQgcmhvbmN1cyBhIHZlaGljdWxhIGxlbyBjb25zZXF1YXQuIE1v +cmJpIGxhb3JlZXQgbWF1cmlzIGVsaXQuIEZ1c2NlIHNlbXBlciByaXN1cyB2ZWwg +bGFjdXMgZWdlc3RhcyByaG9uY3VzLiBQZWxsZW50ZXNxdWUgdGluY2lkdW50IG51 +bGxhIGp1c3RvLCB2aXRhZSB2ZWhpY3VsYSBsaWJlcm8uIE1hdXJpcyBkYXBpYnVz +IGR1aSBpbiBtYWduYSB0cmlzdGlxdWUgc2l0IGFtZXQgZmFjaWxpc2lzIHJpc3Vz +IGxvYm9ydGlzLiBBZW5lYW4gc2l0IGFtZXQgZG9sb3Igdml0YWUgbG9yZW0gZXVp +c21vZCBjb252YWxsaXMuIE51bGxhbSBzaXQgYW1ldCBhZGlwaXNjaW5nIGp1c3Rv +LiBWaXZhbXVzIHZlc3RpYnVsdW0gb3JuYXJlIHN1c2NpcGl0LiBWZXN0aWJ1bHVt +IG1hbGVzdWFkYSB1bHRyaWNlcyB2ZWxpdCBub24gZmV1Z2lhdC4gVmVzdGlidWx1 +bSBhbnRlIGlwc3VtIHByaW1pcyBpbiBmYXVjaWJ1cyBvcmNpIGx1Y3R1cyBldCB1 +bHRyaWNlcyBwb3N1ZXJlIGN1YmlsaWEgQ3VyYWU7IE1hdXJpcyBhcmN1IGlwc3Vt +LCBjb21tb2RvIGluIGlhY3VsaXMgc2VkLCBjb25zZXF1YXQgdXQgYXVndWUuIEFs +aXF1YW0gbGliZXJvIG1hdXJpcywgYWxpcXVldCBhdCBjb25kaW1lbnR1bSBub24s +IGhlbmRyZXJpdCBuZWMgZXJhdC4gSW4gdXQgbWF1cmlzIGxvcmVtLiBWaXZhbXVz +IGVnZXQgbGlndWxhIGlkIG5pc2kgc29sbGljaXR1ZGluIHBsYWNlcmF0IGlkIG5l +YyB0ZWxsdXMuIE51bGxhIG5vbiBmYXVjaWJ1cyBsb3JlbS4gTnVsbGEgbm9uIG5p +YmggZXUgZW5pbSB2aXZlcnJhIGNvbnNlY3RldHVyLiBNb3JiaSBsaWJlcm8gbmlz +bCwgY29udmFsbGlzIGlkIGFsaXF1YW0gaWQsIHN1c2NpcGl0IGFjIGRpYW0uIENs +YXNzIGFwdGVudCB0YWNpdGkgc29jaW9zcXUgYWQgbGl0b3JhIHRvcnF1ZW50IHBl +ciBjb251YmlhIG5vc3RyYSwgcGVyIGluY2VwdG9zIGhpbWVuYWVvcy4gSW50ZWdl +ciBlZ2V0IGFudGUgc2FwaWVuLiBTZWQgbm9uIGF1Y3RvciBtYXNzYS4KCk1hZWNl +bmFzIHRpbmNpZHVudCBncmF2aWRhIGNvbnZhbGxpcy4gVmVzdGlidWx1bSBldCBp +YWN1bGlzIGxpYmVyby4gU2VkIHVybmEgb3JjaSwgY29udmFsbGlzIGluIGNvbnNl +cXVhdCBpZCwgdWx0cmljaWVzIHF1aXMgc2VtLiBFdGlhbSBhbGlxdWV0IHNhZ2l0 +dGlzIGltcGVyZGlldC4gTWF1cmlzIG5lYyBuZXF1ZSBxdWFtLiBNb3JiaSB0aW5j +aWR1bnQgbW9sbGlzIHZlbGl0IGVnZXQgdWx0cmljZXMuIERvbmVjIGF0IHR1cnBp +cyBtYWduYSwgZXUgcGxhY2VyYXQgZXJvcy4gUXVpc3F1ZSB0b3J0b3IgbmlzbCwg +dGluY2lkdW50IGV1IGltcGVyZGlldCBxdWlzLCBwb3N1ZXJlIG5lYyBlbGl0LiBD +dW0gc29jaWlzIG5hdG9xdWUgcGVuYXRpYnVzIGV0IG1hZ25pcyBkaXMgcGFydHVy +aWVudCBtb250ZXMsIG5hc2NldHVyIHJpZGljdWx1cyBtdXMuIFF1aXNxdWUgYWxp +cXVldCBsYW9yZWV0IGRpY3R1bS4KClF1aXNxdWUgdmVsIGJpYmVuZHVtIGxlby4g +RXRpYW0gZXQgbWF1cmlzIGxhY3VzLCBzZWQgc29sbGljaXR1ZGluIG5pc2kuIFF1 +aXNxdWUgaWQgcmlzdXMgaW4gbG9yZW0gbWF0dGlzIGRpY3R1bS4gU3VzcGVuZGlz +c2UgcG90ZW50aS4gRG9uZWMgbmVjIGp1c3RvIGFyY3UsIHV0IHBlbGxlbnRlc3F1 +ZSBzZW0uIFN1c3BlbmRpc3NlIHBvdGVudGkuIFBlbGxlbnRlc3F1ZSBlZ2V0IG5p +c2kgaWQgbmlzbCBsYWNpbmlhIGltcGVyZGlldC4gTmFtIGNvbnNlY3RldHVyIGZh +Y2lsaXNpcyBsZW8gbmVjIHRlbXBvci4gRHVpcyBmZXJtZW50dW0gbGFvcmVldCB0 +dXJwaXMgZXQgcHJldGl1bS4gQ2xhc3MgYXB0ZW50IHRhY2l0aSBzb2Npb3NxdSBh +ZCBsaXRvcmEgdG9ycXVlbnQgcGVyIGNvbnViaWEgbm9zdHJhLCBwZXIgaW5jZXB0 +b3MgaGltZW5hZW9zLiBBZW5lYW4gbGFvcmVldCBlc3Qgc2l0IGFtZXQgZWxpdCBm +ZXVnaWF0IGRhcGlidXMuIEV0aWFtIHRlbXB1cyBzdXNjaXBpdCB2ZWxpdCwgb3Ju +YXJlIGRhcGlidXMgaXBzdW0gcG9ydGEgbm9uLiBOdW5jIHV0IGRvbG9yIHV0IGR1 +aSBwb3J0YSBhY2N1bXNhbi4gSW50ZWdlciBkaWN0dW0sIHNlbSBub24gc3VzY2lw +aXQgc29sbGljaXR1ZGluLCB0b3J0b3IgZXJhdCBsYW9yZWV0IHRlbGx1cywgc2l0 +IGFtZXQgcHJldGl1bSBkb2xvciBtaSB1dCBpcHN1bS4gVml2YW11cyBhdWN0b3Ig +ZGlhbSBkaWN0dW0gc2FwaWVuIGZlcm1lbnR1bSBhZGlwaXNjaW5nLiBQaGFzZWxs +dXMgc2NlbGVyaXNxdWUgb2RpbyBxdWlzIG9yY2kgY3Vyc3VzIGV0IHRlbXBvciBz +ZW0gdGluY2lkdW50LiBJbiBoYWMgaGFiaXRhc3NlIHBsYXRlYSBkaWN0dW1zdC4g +QWVuZWFuIHNvZGFsZXMsIGVzdCBldCBtYXR0aXMgc29kYWxlcywgbG9yZW0gZGlh +bSBkYXBpYnVzIHF1YW0sIGFjIHByZXRpdW0gbGFjdXMgbGVjdHVzIGV1IHNhcGll +bi4gRG9uZWMgYWRpcGlzY2luZyBsb2JvcnRpcyBtaSBlZ2V0IHZlc3RpYnVsdW0u +CgpNYWVjZW5hcyBhdCBhbnRlIGVsaXQuIEluIHRlbXB1cyBydXRydW0gZXN0LCB2 +aXRhZSBlbGVtZW50dW0gbnVuYyBtb2xlc3RpZSBhYy4gQWxpcXVhbSB1dCBlbmlt +IGFyY3UsIG5lYyBzb2RhbGVzIG51bGxhLiBVdCBkaWduaXNzaW0gYWRpcGlzY2lu +ZyBvcm5hcmUuIER1aXMgZGljdHVtIGNvbW1vZG8gaXBzdW0sIGEgb3JuYXJlIHJp +c3VzIG1hbGVzdWFkYSBzZWQuIEV0aWFtIGlkIGFyY3UgbWF1cmlzLCBuZWMgcGhh +cmV0cmEgc2FwaWVuLiBMb3JlbSBpcHN1bSBkb2xvciBzaXQgYW1ldCwgY29uc2Vj +dGV0dXIgYWRpcGlzY2luZyBlbGl0LiBBZW5lYW4gcnV0cnVtIGxlY3R1cyBzZWQg +dHVycGlzIHBvcnR0aXRvciBoZW5kcmVyaXQuIEludGVnZXIgbWV0dXMgbGVvLCBs +dWN0dXMgYWMgbGFjaW5pYSBpbiwgZWxlaWZlbmQgZXQgbmVxdWUuIFBlbGxlbnRl +c3F1ZSBiaWJlbmR1bSBudWxsYSBzaXQgYW1ldCB0ZWxsdXMgZXVpc21vZCB2ZWwg +c2NlbGVyaXNxdWUgbWFnbmEgcnV0cnVtLiBBZW5lYW4gdWx0cmljZXMgY29udmFs +bGlzIG5pc2wsIGlkIG9ybmFyZSB0ZWxsdXMgYXVjdG9yIGV1LiBRdWlzcXVlIGxv +Ym9ydGlzIGF1Y3RvciBqdXN0bywgc2l0IGFtZXQgdGluY2lkdW50IGR1aSBsYWNp +bmlhIG5lYy4gTnVsbGFtIGNvbmd1ZSBudW5jIGF0IGZlbGlzIHBvcnR0aXRvciBy +dXRydW0gbm9uIGF0IGVuaW0uCgpVdCBjb252YWxsaXMgY29uZGltZW50dW0gbGFj +dXMgc2VkIGZhY2lsaXNpcy4gQWxpcXVhbSBwcmV0aXVtIGxpZ3VsYSBlZ2V0IG1h +Z25hIHBsYWNlcmF0IHZvbHV0cGF0LiBEb25lYyBub24gbG9yZW0gcGVsbGVudGVz +cXVlIGlwc3VtIGxvYm9ydGlzIHVsbGFtY29ycGVyLiBTdXNwZW5kaXNzZSB2b2x1 +dHBhdCBmZXJtZW50dW0gbWFsZXN1YWRhLiBQcmFlc2VudCBtb2xlc3RpZSBtYWxl +c3VhZGEgbG9yZW0sIHNpdCBhbWV0IGVsZWlmZW5kIG1hc3NhIGVsZWlmZW5kIG5l +Yy4gTnVsbGEgZmFjaWxpc2lzIHRpbmNpZHVudCBlcmF0LCBpbiBwb3J0dGl0b3Ig +ZXJvcyBzYWdpdHRpcyBpZC4gU2VkIGxvYm9ydGlzLCBsaWJlcm8gYXVjdG9yIGlu +dGVyZHVtIGhlbmRyZXJpdCwgZmVsaXMgcXVhbSB2ZXN0aWJ1bHVtIG5pYmgsIGVn +ZXQgaW1wZXJkaWV0IG1hZ25hIGxpZ3VsYSBhdCBudWxsYS4gQWxpcXVhbSBlcmF0 +IHZvbHV0cGF0LiBBbGlxdWFtIG5lYyBuaXNsIHZlbGl0LiBOdW5jIGRhcGlidXMg +ZGlnbmlzc2ltIG1hc3NhIGFjIGx1Y3R1cy4gTWF1cmlzIG5vbiBvZGlvIHB1cnVz +LiBEdWlzIGVyYXQgYW50ZSwgY29uc2VjdGV0dXIgcXVpcyBjb21tb2RvIGEsIGlh +Y3VsaXMgc2VkIGVzdC4gQ3VyYWJpdHVyIGp1c3RvIGp1c3RvLCBiaWJlbmR1bSBp +biBzZW1wZXIgdmVsLCBmYXVjaWJ1cyBpbiBuaWJoLiBFdGlhbSBtYWduYSBhcmN1 +LCBldWlzbW9kIGF0IHRpbmNpZHVudCBxdWlzLCBzb2xsaWNpdHVkaW4gZXQgbGVj +dHVzLiBOdWxsYW0gcHVydXMgbWV0dXMsIGZlcm1lbnR1bSBlZ2V0IHVsdHJpY2ll +cyBuZWMsIGNvbmd1ZSBhIG5pYmguIFBoYXNlbGx1cyBhIGxhY3VzIGlwc3VtLCBp +ZCBzb2xsaWNpdHVkaW4gdmVsaXQuCgpQaGFzZWxsdXMgbm9uIHZlbGl0IG9yY2ks +IGFjIGZldWdpYXQgbGFjdXMuIEN1cmFiaXR1ciBzZWQgc2FwaWVuIG1hZ25hLiBJ +biB2ZWwgcHVsdmluYXIgZmVsaXMuIE1hdXJpcyBxdWlzIGRpYW0gcXVpcyBtYXNz +YSB2YXJpdXMgdmFyaXVzLiBQcmFlc2VudCB1dCBhdWd1ZSBsZW8sIGV0IGZhY2ls +aXNpcyBtYXNzYS4gSW50ZWdlciBhdCB2ZWxpdCBvcmNpLCBuZWMgbW9sZXN0aWUg +ZXN0LiBNb3JiaSBwb3J0YSBibGFuZGl0IHR1cnBpcyBhdCBmcmluZ2lsbGEuIFNl +ZCBsYW9yZWV0IG9kaW8gdXQgZWxpdCBmZXJtZW50dW0gc2VkIGFjY3Vtc2FuIHRv +cnRvciB2b2x1dHBhdC4gVmVzdGlidWx1bSBhbnRlIGlwc3VtIHByaW1pcyBpbiBm +YXVjaWJ1cyBvcmNpIGx1Y3R1cyBldCB1bHRyaWNlcyBwb3N1ZXJlIGN1YmlsaWEg +Q3VyYWU7IEV0aWFtIGlkIG1hc3NhIHZpdGFlIGVyb3MgaWFjdWxpcyBmYWNpbGlz +aXMgc2VkIGFjIHNlbS4gRXRpYW0gdG9ydG9yIHF1YW0sIG1hbGVzdWFkYSBpbiBz +b2RhbGVzIGEsIHZ1bHB1dGF0ZSB0aW5jaWR1bnQgcXVhbS4gTnVsbGEgZmFjaWxp +c2kuIERvbmVjIGNvbmRpbWVudHVtIHZhcml1cyB1bHRyaWNlcy4gRnVzY2UgYmxh +bmRpdCwgdmVsaXQgdml0YWUgc2NlbGVyaXNxdWUgZXVpc21vZCwgbmliaCBudWxs +YSBpbnRlcmR1bSBhcmN1LCB2ZWwgdnVscHV0YXRlIGZlbGlzIGVzdCBpbiB0b3J0 +b3IuIFNlZCB1dCB1cm5hIGZlcm1lbnR1bSBkaWFtIGVsZWlmZW5kIGxvYm9ydGlz +LgoKQWxpcXVhbSBub24gbnVuYyBvZGlvLiBBbGlxdWFtIGlkIGRpYW0gdmVsIG1p +IHBvc3VlcmUgYXVjdG9yLiBQcmFlc2VudCB0ZW1wb3IgdGVsbHVzIHF1aXMgb2Rp +byB0aW5jaWR1bnQgcG9zdWVyZS4gSW50ZWdlciBhIG1hc3NhIHB1cnVzLCBhYyBn +cmF2aWRhIG1pLiBEb25lYyB2YXJpdXMgbmVxdWUgZXUgZXJvcyBzY2VsZXJpc3F1 +ZSBibGFuZGl0LiBNYWVjZW5hcyBjb25kaW1lbnR1bSB2b2x1dHBhdCBvZGlvIHBy +ZXRpdW0gY29udmFsbGlzLiBEdWlzIHBvc3VlcmUgdmVoaWN1bGEgdm9sdXRwYXQu +IFNlZCB0aW5jaWR1bnQgc2FwaWVuIGV1IGRpYW0gY3Vyc3VzIHZpdGFlIG9ybmFy +ZSBxdWFtIGFkaXBpc2NpbmcuIE5hbSBmYXVjaWJ1cyB0aW5jaWR1bnQgZWxlaWZl +bmQuIEFlbmVhbiBmYWNpbGlzaXMgY29uc2VxdWF0IHR1cnBpcywgYWMgbG9ib3J0 +aXMgdmVsaXQgZGljdHVtIHF1aXMuIE1hdXJpcyBpbXBlcmRpZXQgY29udmFsbGlz +IGxpZ3VsYSBtYXR0aXMgY29uZ3VlLiBOdWxsYW0gdWx0cmljaWVzIGNvbmd1ZSBs +YWN1cyBldCBwcmV0aXVtLiBQcmFlc2VudCBlcm9zIGFyY3UsIGxvYm9ydGlzIHV0 +IHBvcnR0aXRvciB1dCwgaW50ZXJkdW0gZXUgbGliZXJvLiBOYW0gbmVjIG9yY2kg +ZXJhdC4gQ3JhcyBoZW5kcmVyaXQgY29uc2VjdGV0dXIgbWFzc2EsIGlkIGxvYm9y +dGlzIGFyY3UgZXVpc21vZCBpZC4gU3VzcGVuZGlzc2UgcG90ZW50aS4gTnVsbGFt +IGVnZXN0YXMsIGVyb3MgYWMgc3VzY2lwaXQgbW9sZXN0aWUsIG5lcXVlIHRlbGx1 +cyBhZGlwaXNjaW5nIG1hdXJpcywgbm9uIGNvbW1vZG8gZmVsaXMgb2RpbyB1dCBz +ZW0uIE51bGxhbSBzYWdpdHRpcyBncmF2aWRhIHByZXRpdW0uIEZ1c2NlIHJ1dHJ1 +bSBjdXJzdXMgc2NlbGVyaXNxdWUuIFF1aXNxdWUgY29udmFsbGlzLCBkb2xvciBp +biBwdWx2aW5hciBhbGlxdWV0LCBzYXBpZW4gaXBzdW0gdGVtcG9yIGR1aSwgaWQg +dHJpc3RpcXVlIGVzdCBtYXVyaXMgYXVjdG9yIGp1c3RvLgoKQWVuZWFuIGFsaXF1 +ZXQgbWV0dXMgZXUgbWFnbmEgdHJpc3RpcXVlIGV1IGZlcm1lbnR1bSBtYWduYSB1 +bGxhbWNvcnBlci4gQWVuZWFuIHNjZWxlcmlzcXVlIGJsYW5kaXQgZWxlaWZlbmQu +IEludGVnZXIgYSBvcm5hcmUgb2Rpby4gTWFlY2VuYXMgZWxlaWZlbmQgaGVuZHJl +cml0IGFudGUgaWQgbW9sZXN0aWUuIE1hdXJpcyByaG9uY3VzIHBsYWNlcmF0IGFs +aXF1YW0uIFN1c3BlbmRpc3NlIGEgZWxpdCBkaWFtLCBldCBwaGFyZXRyYSBlc3Qu +IER1aXMgZWxlbWVudHVtIG9yY2kgZXUgYW50ZSBtYXR0aXMgYWMgY29uZ3VlIG5p +c2wgYWxpcXVldC4gSW50ZWdlciBzaXQgYW1ldCBkb2xvciBldCBtYXVyaXMgZWxl +aWZlbmQgbGFvcmVldC4gU2VkIGFsaXF1ZXQgcHJldGl1bSBudWxsYSwgaW4gZWxl +aWZlbmQgYXVndWUgcnV0cnVtIHF1aXMuIFF1aXNxdWUgZGFwaWJ1cyBuaXNsIHZp +dGFlIHRlbGx1cyBpbnRlcmR1bSBldSBibGFuZGl0IGFyY3UgY29uc2VxdWF0LiBF +dGlhbSBzZWQgcHVydXMgcmlzdXMuIEZ1c2NlIHR1cnBpcyBsaWJlcm8sIGFsaXF1 +YW0gbmVjIGxhY2luaWEgYXQsIGJsYW5kaXQgbmVjIG51bmMuIFByYWVzZW50IHZp +dmVycmEsIGxvcmVtIGFjIHBvcnR0aXRvciBtYWxlc3VhZGEsIGxvcmVtIHZlbGl0 +IHNvbGxpY2l0dWRpbiB2ZWxpdCwgc2l0IGFtZXQgdGluY2lkdW50IHVybmEgZHVp +IHZpdGFlIGxlby4KCkRvbmVjIHZpdGFlIGZlbGlzIHF1aXMgZW5pbSB2dWxwdXRh +dGUgcmhvbmN1cy4gUHJhZXNlbnQgZWxlbWVudHVtIHRyaXN0aXF1ZSBjb25ndWUu +IERvbmVjIHF1aXMgbWV0dXMgbmliaC4gTWFlY2VuYXMgYXJjdSBhbnRlLCBsYWNp +bmlhIGluIGRhcGlidXMgaWQsIGZlcm1lbnR1bSBzZWQgZXJhdC4gTW9yYmkgYWRp +cGlzY2luZyBncmF2aWRhIG1hZ25hLCB1dCBwb3N1ZXJlIG9kaW8gZmV1Z2lhdCB2 +aXRhZS4gU3VzcGVuZGlzc2UgcG9ydGEgbHVjdHVzIGxhb3JlZXQuIEFsaXF1YW0g +aW4gZXJhdCBzaXQgYW1ldCBvZGlvIHZlaGljdWxhIG9ybmFyZSBxdWlzIGF0IGR1 +aS4gU3VzcGVuZGlzc2Ugbm9uIGxvcmVtIHZpdGFlIGxpZ3VsYSBsdWN0dXMgY29u +c2VjdGV0dXIgYWMgaWQgcHVydXMuIE51bmMgdXQgbmlzaSBqdXN0by4gTnVsbGFt +IGVnZXQgc2FwaWVuIGNvbW1vZG8gZHVpIHN1c2NpcGl0IHBlbGxlbnRlc3F1ZS4g +Vml2YW11cyBzZW1wZXIgbWkgc2VkIGFyY3Ugc2VtcGVyIHZhcml1cy4gQ3JhcyBh +bGlxdWV0IHZlc3RpYnVsdW0gc2FwaWVuLCBhIGludGVyZHVtIG1pIHVsbGFtY29y +cGVyIHZlbC4gTW9yYmkgcHVydXMgZGlhbSwgb3JuYXJlIG5vbiB0ZW1wb3Igbm9u +LCBjb252YWxsaXMgbmVjIGVuaW0uIE51bGxhbSB0cmlzdGlxdWUgdnVscHV0YXRl +IGxlbyBuZWMgZmFjaWxpc2lzLiBQZWxsZW50ZXNxdWUgaGFiaXRhbnQgbW9yYmkg +dHJpc3RpcXVlIHNlbmVjdHVzIGV0IG5ldHVzIGV0IG1hbGVzdWFkYSBmYW1lcyBh +YyB0dXJwaXMgZWdlc3Rhcy4KCk1vcmJpIGltcGVyZGlldCB2ZWhpY3VsYSBjb25n +dWUuIE1hdXJpcyBxdWlzIG51bGxhIG9kaW8sIGEgZmF1Y2lidXMgdXJuYS4gTnVs +bGEgZXQgZXJvcyBkb2xvci4gRnVzY2UgYSBmYXVjaWJ1cyBpcHN1bS4gTWF1cmlz +IGZlcm1lbnR1bSBmZXVnaWF0IGRpZ25pc3NpbS4gVXQgYSBqdXN0byBlbGl0LCBu +b24gYXVjdG9yIHF1YW0uIFNlZCBsYWN1cyBhdWd1ZSwgcGxhY2VyYXQgYXQgYWxp +cXVhbSBub24sIG1hdHRpcyBpZCBtaS4gQWVuZWFuIGEgbGFvcmVldCBlcm9zLiBD +cmFzIHVsdHJpY2llcyBlbGl0IGluIG51bmMgc3VzY2lwaXQgaWQgc29sbGljaXR1 +ZGluIGVuaW0gY29uZGltZW50dW0uIFBoYXNlbGx1cyBkaWduaXNzaW0gbmlzaSBx +dWlzIGxlbyBpbnRlcmR1bSBwaGFyZXRyYS4gRG9uZWMgc2l0IGFtZXQgbGVvIGEg +ZHVpIHZpdmVycmEgbW9sZXN0aWUuIEN1cmFiaXR1ciBsb2JvcnRpcyBzYXBpZW4g +cXVpcyBuZXF1ZSBwdWx2aW5hciBhdCBmcmluZ2lsbGEgbmlzaSB2ZWhpY3VsYS4K +ClByYWVzZW50IG5vbiBwdXJ1cyB0ZWxsdXMuIEludGVnZXIgaWFjdWxpcyBkYXBp +YnVzIG5pc2wsIHRyaXN0aXF1ZSB2ZXN0aWJ1bHVtIG1pIG1hbGVzdWFkYSBzaXQg +YW1ldC4gU2VkIGxvYm9ydGlzIGhlbmRyZXJpdCBsb2JvcnRpcy4gUXVpc3F1ZSB0 +ZW1wb3IsIGFyY3UgYWMgdGVtcHVzIGF1Y3RvciwgbmVxdWUgcXVhbSBkaWN0dW0g +cXVhbSwgdml0YWUgZ3JhdmlkYSBsaWd1bGEgbmliaCBldSBhdWd1ZS4gQWVuZWFu +IGV1aXNtb2QgdGVtcG9yIGlwc3VtIGEgaGVuZHJlcml0LiBDcmFzIGRvbG9yIGxp +Z3VsYSwgZmF1Y2lidXMgYWMgaGVuZHJlcml0IGVnZXQsIGFsaXF1YW0gYSBuaXNs +LiBJbnRlZ2VyIG5lYyBjb25zZXF1YXQganVzdG8uIEludGVnZXIgcGhhcmV0cmEg +c2NlbGVyaXNxdWUgbGVvLiBBZW5lYW4gZXVpc21vZCB2ZWhpY3VsYSBhbnRlIG5v +biBwaGFyZXRyYS4gVmVzdGlidWx1bSBzb2xsaWNpdHVkaW4ganVzdG8gZXUgc2Vt +IGxhb3JlZXQgaW4gdGVtcHVzIG5lcXVlIGNvbW1vZG8uCgpVdCBpbiBhcmN1IGFu +dGUuIEN1cmFiaXR1ciB1bHRyaWNpZXMgdmVsaXQgZGlhbS4gQWxpcXVhbSB2ZWxp +dCBlcm9zLCB2b2x1dHBhdCBxdWlzIGN1cnN1cyBpZCwgdmVoaWN1bGEgYWMgdG9y +dG9yLiBOdWxsYSBwcmV0aXVtLCBlcmF0IGlkIGZhY2lsaXNpcyBibGFuZGl0LCBy +aXN1cyB0ZWxsdXMgYWxpcXVldCBvcmNpLCB2ZWwgY29uZGltZW50dW0gbmliaCBl +bGl0IHZpdGFlIGVsaXQuIFBoYXNlbGx1cyB1bGxhbWNvcnBlciBjb25zZWN0ZXR1 +ciBhbnRlIHNpdCBhbWV0IGx1Y3R1cy4gTnVsbGEgdXQgbnVsbGEgZWdldCBlcm9z +IGRpY3R1bSBwZWxsZW50ZXNxdWUgdmVsIHV0IG51bGxhLiBEb25lYyBsYW9yZWV0 +IHZpdmVycmEgbWFnbmEgdXQgaW50ZXJkdW0uIFZpdmFtdXMgcHVsdmluYXIgc2Fw +aWVuIGNvbnZhbGxpcyBtYWduYSBzb2RhbGVzIGVnZXQgZWdlc3RhcyBlc3QgaW1w +ZXJkaWV0LiBRdWlzcXVlIGZhY2lsaXNpcyBhbGlxdWFtIHNvZGFsZXMuIEV0aWFt +IGZlcm1lbnR1bSwgb2RpbyBhYyBzZW1wZXIgc2NlbGVyaXNxdWUsIHB1cnVzIGVu +aW0gaW1wZXJkaWV0IGF1Z3VlLCBzaXQgYW1ldCBkaWduaXNzaW0gc2FwaWVuIHRv +cnRvciBuZWMgbWF1cmlzLiBTdXNwZW5kaXNzZSBlbGVpZmVuZCBjb21tb2RvIG51 +bmMgcXVpcyBjb25zZWN0ZXR1ci4gRG9uZWMgZWdldCB0cmlzdGlxdWUgbGVvLgoK +U3VzcGVuZGlzc2Ugc29sbGljaXR1ZGluIHBoYXJldHJhIHNlbXBlci4gU2VkIGp1 +c3RvIGVzdCwgZmF1Y2lidXMgaWQgY3Vyc3VzIGEsIHBlbGxlbnRlc3F1ZSBpbiBt +aS4gTWF1cmlzIHNhZ2l0dGlzLCBpcHN1bSBjdXJzdXMgYmxhbmRpdCBpbXBlcmRp +ZXQsIGVzdCBlc3QgbHVjdHVzIHJpc3VzLCBxdWlzIGZlcm1lbnR1bSBsZW8gb3Jj +aSBhIG9kaW8uIE51bmMgc2l0IGFtZXQgdmVsaXQgaXBzdW0uIE5hbSBldWlzbW9k +IHB1bHZpbmFyIG1ldHVzLCBhYyBhZGlwaXNjaW5nIGR1aSB1bGxhbWNvcnBlciBh +LiBWZXN0aWJ1bHVtIGFudGUgaXBzdW0gcHJpbWlzIGluIGZhdWNpYnVzIG9yY2kg +bHVjdHVzIGV0IHVsdHJpY2VzIHBvc3VlcmUgY3ViaWxpYSBDdXJhZTsgU2VkIG1v +bGVzdGllIHRpbmNpZHVudCBkb2xvciwgc2VkIHByZXRpdW0gbWFnbmEgY29uc2Vj +dGV0dXIgdXQuIExvcmVtIGlwc3VtIGRvbG9yIHNpdCBhbWV0LCBjb25zZWN0ZXR1 +ciBhZGlwaXNjaW5nIGVsaXQuIEFsaXF1YW0gbGVjdHVzIGxpZ3VsYSwgaW50ZXJk +dW0gYXQgbG9ib3J0aXMgaWQsIGNvbnZhbGxpcyBzaXQgYW1ldCBzZW0uIFNlZCBl +Z2V0IG5lcXVlIGluIGFyY3UgdWx0cmljZXMgZmV1Z2lhdC4gUHJvaW4gdnVscHV0 +YXRlIGxlbyBlZ2V0IGVyb3MgZGFwaWJ1cyBhbGlxdWV0LiBGdXNjZSBmYWNpbGlz +aXMgY29uc2VxdWF0IGRpYW0sIHNlZCB2ZXN0aWJ1bHVtIG1pIHVsdHJpY2llcyBl +Z2V0LiBVdCBwb3N1ZXJlIGNvbmd1ZSBsaWJlcm8gc2l0IGFtZXQgZGlnbmlzc2lt +LiBQcm9pbiBxdWlzIGFyY3UgbGliZXJvLgoKVmVzdGlidWx1bSBhdCBhdWd1ZSBt +YXVyaXMuIEFsaXF1YW0gc2FnaXR0aXMgcG9ydGEgYW50ZSBpbiB2YXJpdXMuIFZl +c3RpYnVsdW0gbHVjdHVzIGlhY3VsaXMgYXJjdSBhIGludGVyZHVtLiBVdCB2YXJp +dXMgaGVuZHJlcml0IGxhY3VzIG5lYyBzYWdpdHRpcy4gU2VkIHV0IHJpc3VzIGFj +IGxlY3R1cyB1bHRyaWNpZXMgbW9sbGlzLiBOdW5jIGZldWdpYXQgc3VzY2lwaXQg +bnVuYyBxdWlzIGVsZW1lbnR1bS4gU3VzcGVuZGlzc2UgcG90ZW50aS4gRnVzY2Ug +bGFvcmVldCBlbGl0IGV1IG9kaW8gZnJpbmdpbGxhIHBlbGxlbnRlc3F1ZS4gRXRp +YW0gdml0YWUgYXJjdSBxdWlzIHF1YW0gc29kYWxlcyBmYWNpbGlzaXMgY29uc2Vx +dWF0IHV0IG9yY2kuIFBoYXNlbGx1cyB2aXRhZSBxdWFtIHF1aXMgbGVvIGNvbmd1 +ZSBpbnRlcmR1bSBzZWQgc3VzY2lwaXQgZXN0LiBNYWVjZW5hcyBjb25kaW1lbnR1 +bSwgbWFzc2EgZWdldCB0ZW1wb3IgcGhhcmV0cmEsIGVyYXQgbGVvIGxhY2luaWEg +b2Rpbywgc2l0IGFtZXQgZmV1Z2lhdCBtYXVyaXMgcmlzdXMgc2VkIHNhcGllbi4g +TW9yYmkgYXJjdSBsb3JlbSwgZGFwaWJ1cyBlZ2V0IHZlbmVuYXRpcyBzZWQsIHNl +bXBlciBlZ2V0IGVyb3MuIENyYXMgc2VtcGVyIHVsdHJpY2llcyBlcm9zIHZvbHV0 +cGF0IHZ1bHB1dGF0ZS4gTW9yYmkgYXQgbnVuYyBlZ2V0IG5pYmggZmV1Z2lhdCB0 +ZW1wdXMuCgpJbiBlZ2V0IGVsaXQgYSBkaWFtIHBsYWNlcmF0IHZvbHV0cGF0IHNl +ZCB0ZW1wdXMgZGlhbS4gTWFlY2VuYXMgdGVtcG9yIHNlbSBpZCBzZW0gdml2ZXJy +YSB2ZWwgZmVybWVudHVtIHJpc3VzIHBvcnR0aXRvci4gUHJvaW4gYSBtZXR1cyBt +ZXR1cy4gQWVuZWFuIHF1aXMgdGluY2lkdW50IG1hZ25hLiBEb25lYyBzaXQgYW1l +dCBwb3N1ZXJlIHJpc3VzLiBEb25lYyBlc3QganVzdG8sIGRhcGlidXMgaW4gc29s +bGljaXR1ZGluIGV1LCB2ZW5lbmF0aXMgc2l0IGFtZXQgZWxpdC4gQ2xhc3MgYXB0 +ZW50IHRhY2l0aSBzb2Npb3NxdSBhZCBsaXRvcmEgdG9ycXVlbnQgcGVyIGNvbnVi +aWEgbm9zdHJhLCBwZXIgaW5jZXB0b3MgaGltZW5hZW9zLiBDcmFzIGluIHR1cnBp +cyBuZWMgbnVuYyBmcmluZ2lsbGEgaWFjdWxpcy4gRXRpYW0gc3VzY2lwaXQgbmli +aCB2aXRhZSBsaWJlcm8gcGVsbGVudGVzcXVlIHZpdmVycmEuIENyYXMgaWQgbGVj +dHVzIHF1aXMgZW5pbSBvcm5hcmUgbW9sZXN0aWUgdml0YWUgdmVsIHRlbGx1cy4g +SW4gdmVzdGlidWx1bSB2dWxwdXRhdGUgdHVycGlzIGlkIHBvc3VlcmUuCgpOYW0g +ZXN0IGVyYXQsIHJob25jdXMgbm9uIGltcGVyZGlldCBpbiwgc2FnaXR0aXMgdml0 +YWUgaXBzdW0uIE51bGxhIHJ1dHJ1bSB0aW5jaWR1bnQgbGVjdHVzIGV0IGJsYW5k +aXQuIFV0IHNlZCBsaWd1bGEgbmlzbCwgbm9uIGRpY3R1bSBlcmF0LiBBZW5lYW4g +bG9yZW0gZW5pbSwgbW9sbGlzIHV0IHRpbmNpZHVudCBpZCwgY29tbW9kbyBzaXQg +YW1ldCBuaXNsLiBNYWVjZW5hcyBibGFuZGl0IHJob25jdXMgc2VtcGVyLiBGdXNj +ZSBhIG1hc3NhIG9yY2ksIGV0IHZlbmVuYXRpcyBhcmN1LiBNYXVyaXMgbW9sbGlz +IGR1aSBxdWlzIGZlbGlzIGJpYmVuZHVtIHBoYXJldHJhLiBDcmFzIHNlZCBpcHN1 +bSBtYXNzYSwgcG9ydHRpdG9yIHB1bHZpbmFyIG5pc2kuIExvcmVtIGlwc3VtIGRv +bG9yIHNpdCBhbWV0LCBjb25zZWN0ZXR1ciBhZGlwaXNjaW5nIGVsaXQuIFZpdmFt +dXMgY3Vyc3VzIGVsaXQgc2FnaXR0aXMgbGliZXJvIGhlbmRyZXJpdCB2ZXN0aWJ1 +bHVtLiBTZWQgcG9ydHRpdG9yLCB0b3J0b3IgdGluY2lkdW50IHBvcnR0aXRvciBz +ZW1wZXIsIGRpYW0gbWFnbmEgZWxlaWZlbmQgbnVuYywgc2VkIGNvbmRpbWVudHVt +IG5pYmggZXJhdCBxdWlzIG9kaW8uIERvbmVjIHBvc3VlcmUgdmVoaWN1bGEgcHVy +dXMsIGluIHB1bHZpbmFyIG9kaW8gaW50ZXJkdW0gZXUuIFZlc3RpYnVsdW0gZmFj +aWxpc2lzIHRpbmNpZHVudCBkYXBpYnVzLiBGdXNjZSBsdWN0dXMgbG9yZW0gZWdl +dCBxdWFtIGFjY3Vtc2FuIGluIG1hdHRpcyBuaWJoIHZvbHV0cGF0LiBOdWxsYW0g +ZXQgbGVvIGEgdXJuYSBwb3J0YSB2YXJpdXMgbm9uIHZpdGFlIGR1aS4gU2VkIGlu +dGVyZHVtLCBtZXR1cyBldSBydXRydW0gcGhhcmV0cmEsIG5pc2wgc2VtIHRlbXB1 +cyBqdXN0bywgdmFyaXVzIGNvbnZhbGxpcyBpcHN1bSBkaWFtIHV0IGxlY3R1cy4K +CkluIGhhYyBoYWJpdGFzc2UgcGxhdGVhIGRpY3R1bXN0LiBWZXN0aWJ1bHVtIGNv +bmd1ZSBzb2RhbGVzIG5pc2kgcXVpcyBvcm5hcmUuIEZ1c2NlIGN1cnN1cyBuaXNp +IGF0IHR1cnBpcyBjb25ndWUgaGVuZHJlcml0LiBWZXN0aWJ1bHVtIG5vbiBsYWN1 +cyB2ZWwgc2FwaWVuIHB1bHZpbmFyIHZlaGljdWxhIGF0IGluIGFudGUuIE51bGxh +IGZhY2lsaXNpLiBVdCB0cmlzdGlxdWUgdGluY2lkdW50IGVyYXQgaWQgbHVjdHVz +LiBDdXJhYml0dXIgcG9zdWVyZSBzb2RhbGVzIG5lcXVlIHF1aXMgdmFyaXVzLiBD +dXJhYml0dXIgY3Vyc3VzIGFjY3Vtc2FuIGlwc3VtLCB2ZWwgbHVjdHVzIGxpZ3Vs +YSBkYXBpYnVzIG5vbi4gQ3JhcyB2ZWhpY3VsYSBtYWduYSBpbiBsYWN1cyBvcm5h +cmUgZGFwaWJ1cy4gRG9uZWMgYWxpcXVldCBzb2xsaWNpdHVkaW4gbGFjdXMsIGV1 +IGlhY3VsaXMgZXJhdCBiaWJlbmR1bSBjb21tb2RvLiBEb25lYyBibGFuZGl0IGJp +YmVuZHVtIGZldWdpYXQuIFByYWVzZW50IGV1IGVzdCBqdXN0by4gUGVsbGVudGVz +cXVlIGF0IGVuaW0gc2VkIHNlbSB2aXZlcnJhIGNvbnZhbGxpcy4gTWFlY2VuYXMg +dmVuZW5hdGlzIG1ldHVzIHNhcGllbi4gU2VkIHBsYWNlcmF0IGZhY2lsaXNpcyBl +bGl0IG5lYyBtYWxlc3VhZGEuIEZ1c2NlIHNhcGllbiBlc3QsIGNvbnNlcXVhdCBh +IGNvbmd1ZSBlZ2V0LCBhY2N1bXNhbiBlZ2V0IGxvcmVtLiBTdXNwZW5kaXNzZSB0 +aW5jaWR1bnQgcHJldGl1bSBtYWduYSBlZ2V0IGRhcGlidXMuIEZ1c2NlIHZlbCBl +cm9zIGV0IGxvcmVtIGNvbnNlcXVhdCB0cmlzdGlxdWUgbmVjIGEgaXBzdW0uCgpQ +cm9pbiBxdWlzIGN1cnN1cyBhcmN1LiBNYWVjZW5hcyBlbGVpZmVuZCBsb3JlbSBp +ZCBuaXNsIHNjZWxlcmlzcXVlIHBsYWNlcmF0LiBGdXNjZSBpbXBlcmRpZXQgbG9y +ZW0gZXUgdXJuYSBkaWduaXNzaW0gZmVybWVudHVtLiBQZWxsZW50ZXNxdWUgbnVu +YyBuaXNsLCBpbXBlcmRpZXQgdXQgYWNjdW1zYW4gaWQsIGZlcm1lbnR1bSBub24g +bWF1cmlzLiBBZW5lYW4gZnJpbmdpbGxhIGxlY3R1cyB2aXRhZSB0dXJwaXMgZmVy +bWVudHVtIHZpdGFlIGZhY2lsaXNpcyBvZGlvIG1vbGxpcy4gQWVuZWFuIG5vbiBz +ZW0gZXQgZXJvcyBjb25ndWUgcG9ydGEgaWQgc2l0IGFtZXQgZGlhbS4gRG9uZWMg +ZnJpbmdpbGxhIGVyb3MgYXQgcXVhbSBpbXBlcmRpZXQgYXQgZ3JhdmlkYSB0b3J0 +b3IgdWxsYW1jb3JwZXIuIEZ1c2NlIGRvbG9yIHJpc3VzLCB2aXZlcnJhIGlkIGFs +aXF1ZXQgc2VkLCBkaWduaXNzaW0gcXVpcyBtYXVyaXMuIFF1aXNxdWUgYWMgbWV0 +dXMgaWQgcXVhbSBsb2JvcnRpcyB0cmlzdGlxdWUgYXQgdmVsIGVuaW0uIFBoYXNl +bGx1cyBpbiB0b3J0b3IgbWF1cmlzLiBTZWQgdGluY2lkdW50IGR1aSBub24gZXJv +cyBzb2xsaWNpdHVkaW4gdm9sdXRwYXQuIEN1cmFiaXR1ciB2aXZlcnJhIGVsZW1l +bnR1bSBhcmN1IGFjIHVsdHJpY2VzLiBOdWxsYSBmZWxpcyBsaWd1bGEsIGF1Y3Rv +ciBhdCBsYWNpbmlhIHNlZCwgdGluY2lkdW50IGF0IG1pLiBJbiB2ZWwgZWxpdCBv +cmNpLiBWZXN0aWJ1bHVtIGVyYXQgbmlzaSwgbW9sZXN0aWUgdmVsIGF1Y3RvciB2 +ZWwsIHNhZ2l0dGlzIGFjIGxlY3R1cy4gUGVsbGVudGVzcXVlIHVsdHJpY2llcyBj +b25kaW1lbnR1bSBudWxsYSBuZWMgZXVpc21vZC4KCkRvbmVjIGNvbnNlY3RldHVy +IHZlbmVuYXRpcyBzZW1wZXIuIFN1c3BlbmRpc3NlIHZlbCBkaWN0dW0gYXVndWUu +IFBlbGxlbnRlc3F1ZSBub24gbWF1cmlzIGp1c3RvLiBEb25lYyBhY2N1bXNhbiwg +bWV0dXMgdXQgcHJldGl1bSBtb2xlc3RpZSwgbGlndWxhIGp1c3RvIGx1Y3R1cyBv +cmNpLCBub24gdmFyaXVzIG1pIG5pYmggZXUganVzdG8uIFZlc3RpYnVsdW0gc2Vt +IHNlbSwgdGluY2lkdW50IGVnZXQgcG9ydGEgYSwgZmVybWVudHVtIGV0IHNhcGll +bi4gTnVsbGEgZmFjaWxpc2kuIFBlbGxlbnRlc3F1ZSBpbiB2ZXN0aWJ1bHVtIGFu +dGUuIE51bmMgaWFjdWxpcyBsaWd1bGEgbmVjIG9kaW8gc2FnaXR0aXMgbmVjIHBv +cnR0aXRvciBuaWJoIHNlbXBlci4gVXQgZWdldCBtZXR1cyBvcmNpLiBQcm9pbiBn +cmF2aWRhIG9yY2kgZGlnbmlzc2ltIGRpYW0gaWFjdWxpcyBhY2N1bXNhbi4gQWVu +ZWFuIGF1Z3VlIG9yY2ksIHBsYWNlcmF0IGV0IGNvbnZhbGxpcyBlZ2V0LCBzb2Rh +bGVzIHF1aXMgZGlhbS4gU2VkIHN1c2NpcGl0IG5pc2kgcXVpcyBsaWJlcm8gc29s +bGljaXR1ZGluIGV1IG1vbGxpcyBuZXF1ZSBtb2xlc3RpZS4gTWFlY2VuYXMgcHVy +dXMgbmlzbCwgY29uc2VjdGV0dXIgbm9uIHZlaGljdWxhIHNpdCBhbWV0LCB1bGxh +bWNvcnBlciBxdWlzIG5pYmguIFByYWVzZW50IHF1YW0gaXBzdW0sIG1vbGVzdGll +IGV1IHB1bHZpbmFyIGF0LCBpYWN1bGlzIGV1IHR1cnBpcy4gQ3JhcyBuZWMgZWxp +dCB1dCBsaWJlcm8gc3VzY2lwaXQgYWxpcXVldCBldCBuZWMgbGVjdHVzLiBWZXN0 +aWJ1bHVtIHB1cnVzIGF1Z3VlLCB0cmlzdGlxdWUgdml0YWUgY29udmFsbGlzIGF0 +LCB2ZWhpY3VsYSBub24gbWV0dXMuIEZ1c2NlIGx1Y3R1cyBjb25ndWUgbWksIHZl +bCBzYWdpdHRpcyBkb2xvciBtb2xsaXMgdmVsLiBQcmFlc2VudCBpbiBudW5jIGFj +Y3Vtc2FuIGxvcmVtIGxvYm9ydGlzIGlhY3VsaXMgdXQgdml0YWUgaXBzdW0uIFN1 +c3BlbmRpc3NlIHB1bHZpbmFyLCBudW5jIGFjIGFsaXF1ZXQgc2VtcGVyLCBsYWN1 +cyBsb3JlbSBldWlzbW9kIHB1cnVzLCB2ZWwgbW9sbGlzIG1ldHVzIHJpc3VzIG5l +YyBzYXBpZW4uCgpJbiB2ZW5lbmF0aXMgcG9zdWVyZSBzYXBpZW4sIHNpdCBhbWV0 +IGV1aXNtb2QgZG9sb3IgcGVsbGVudGVzcXVlIGV1LiBQcmFlc2VudCBsYW9yZWV0 +IGZlbGlzIHV0IG1ldHVzIHZlc3RpYnVsdW0gY29uZGltZW50dW0uIFV0IHNjZWxl +cmlzcXVlIGxlbyBhdWd1ZS4gU3VzcGVuZGlzc2Ugdml0YWUgZG9sb3IgcHVydXMs +IGlkIHJ1dHJ1bSBhbnRlLiBGdXNjZSBpbiB2ZWxpdCBhbnRlLCBhIHBlbGxlbnRl +c3F1ZSBtaS4gTWFlY2VuYXMgdmVsIHJpc3VzIGVnZXQgb3JjaSBmZXJtZW50dW0g +cHJldGl1bSBuZWMgdmVsIHNhcGllbi4gUGhhc2VsbHVzIGlwc3VtIG1hZ25hLCBi +aWJlbmR1bSBxdWlzIGZhdWNpYnVzIHZlbCwgcGxhY2VyYXQgaWQgbWFnbmEuIFZp +dmFtdXMgcXVhbSBkdWksIGNvbnNlY3RldHVyIHNlZCBwdWx2aW5hciBldSwgaW50 +ZXJkdW0gaWQgaXBzdW0uIENyYXMgbG9ib3J0aXMgZmFjaWxpc2lzIHJ1dHJ1bS4g +Q3VtIHNvY2lpcyBuYXRvcXVlIHBlbmF0aWJ1cyBldCBtYWduaXMgZGlzIHBhcnR1 +cmllbnQgbW9udGVzLCBuYXNjZXR1ciByaWRpY3VsdXMgbXVzLiBOYW0gdmVzdGli +dWx1bSBudW5jIHNlZCBqdXN0byBkaWduaXNzaW0gYWMgdGluY2lkdW50IHNhcGll +biBjb25ndWUuCgpQaGFzZWxsdXMgbm9uIGRpY3R1bSB0dXJwaXMuIFByb2luIGVn +ZXQgbWFzc2EgbGFjaW5pYSBsaWJlcm8gcnV0cnVtIHZlc3RpYnVsdW0uIE51bGxh +IGFsaXF1ZXQgbGliZXJvIGlkIHNhcGllbiBhbGlxdWFtIGZlcm1lbnR1bS4gVml2 +YW11cyBsZWN0dXMgaXBzdW0sIHBoYXJldHJhIHV0IGRhcGlidXMgdXQsIGFsaXF1 +YW0gYWMgbmVxdWUuIFZpdmFtdXMgZmF1Y2lidXMgbWkgcXVpcyBtYXVyaXMgcnV0 +cnVtIGFjIHBsYWNlcmF0IG5pc2kgc2NlbGVyaXNxdWUuIE1hdXJpcyBlbGl0IG9y +Y2ksIGFkaXBpc2NpbmcgZXUgY29uc2VxdWF0IGlkLCB2ZW5lbmF0aXMgaW4gbnVu +Yy4gQWVuZWFuIG5vbiBibGFuZGl0IGxpYmVyby4gU3VzcGVuZGlzc2UgaWQgYXVn +dWUgZHVpLiBRdWlzcXVlIG5lYyBvcmNpIHZlbCBvZGlvIG1hdHRpcyBncmF2aWRh +LiBWZXN0aWJ1bHVtIGFudGUgaXBzdW0gcHJpbWlzIGluIGZhdWNpYnVzIG9yY2kg +bHVjdHVzIGV0IHVsdHJpY2VzIHBvc3VlcmUgY3ViaWxpYSBDdXJhZTsgTWF1cmlz +IHZvbHV0cGF0IGR1aSB1dCBsYWN1cyBhZGlwaXNjaW5nIGJpYmVuZHVtLiBMb3Jl +bSBpcHN1bSBkb2xvciBzaXQgYW1ldCwgY29uc2VjdGV0dXIgYWRpcGlzY2luZyBl +bGl0LiBWaXZhbXVzIHZlbmVuYXRpcyBqdXN0byBldSBzYXBpZW4gZmVybWVudHVt +IGNvbmd1ZSBxdWlzIGluIG51bmMuIE51bGxhbSBsYWNpbmlhIGVyb3MgbG9yZW0s +IHV0IGFsaXF1YW0gb3JjaS4gUGhhc2VsbHVzIHN1c2NpcGl0LCBsYWN1cyBldCB0 +ZW1wb3Igc2VtcGVyLCBlc3QgbWF1cmlzIGNvbmd1ZSBtYXNzYSwgc2VkIHVsdHJp +Y2VzIG9yY2kgZGlhbSB2aXRhZSBpcHN1bS4KCk51bGxhIGZhY2lsaXNpLiBTZWQg +cG9zdWVyZSBmcmluZ2lsbGEgZmVsaXMsIGFjIHZlbmVuYXRpcyBkdWkgdnVscHV0 +YXRlIHV0LiBQcm9pbiBlbGVpZmVuZCB0ZW1wb3IgbW9sZXN0aWUuIE51bGxhIHRp +bmNpZHVudCBsZWN0dXMgdml0YWUgbmVxdWUgYmliZW5kdW0gcHJldGl1bS4gSW4g +bGliZXJvIG5pc2wsIHRyaXN0aXF1ZSBuZWMgYmliZW5kdW0gc2l0IGFtZXQsIHVs +bGFtY29ycGVyIG5lYyBlcmF0LiBTdXNwZW5kaXNzZSBpbnRlcmR1bSBwb3J0YSBv +cmNpLCBxdWlzIHZpdmVycmEgZXJhdCBhdWN0b3IgYXQuIER1aXMgYWMgZGlhbSBl +dCBsaWd1bGEgYmxhbmRpdCB0ZW1wb3IgbmVjIGV1IGxhY3VzLiBDdW0gc29jaWlz +IG5hdG9xdWUgcGVuYXRpYnVzIGV0IG1hZ25pcyBkaXMgcGFydHVyaWVudCBtb250 +ZXMsIG5hc2NldHVyIHJpZGljdWx1cyBtdXMuIFByYWVzZW50IHBlbGxlbnRlc3F1 +ZSB2YXJpdXMgbnVsbGEgdmVsIGFsaXF1YW0uIEFsaXF1YW0gdXQgbGVjdHVzIG1h +dXJpcywgaWQgYWxpcXVldCBsYWN1cy4gSW50ZWdlciBzY2VsZXJpc3F1ZSBlbGVt +ZW50dW0gZHVpLCBldSBsYW9yZWV0IGF1Z3VlIGVsZW1lbnR1bSBzaXQgYW1ldC4g +VXQgdWxsYW1jb3JwZXIgdGVsbHVzIGNvbnZhbGxpcyBzYXBpZW4gdmVzdGlidWx1 +bSBub24gbGFvcmVldCBwdXJ1cyBhZGlwaXNjaW5nLiBOdW5jIG5lYyBxdWFtIG51 +bmMuIFZpdmFtdXMgdWx0cmljZXMgZmVybWVudHVtIG1hc3NhLCBzaXQgYW1ldCBz +Y2VsZXJpc3F1ZSBudW5jIGltcGVyZGlldCB1dC4KClZlc3RpYnVsdW0gYW50ZSBp +cHN1bSBwcmltaXMgaW4gZmF1Y2lidXMgb3JjaSBsdWN0dXMgZXQgdWx0cmljZXMg +cG9zdWVyZSBjdWJpbGlhIEN1cmFlOyBJbiBoYWMgaGFiaXRhc3NlIHBsYXRlYSBk +aWN0dW1zdC4gTnVsbGFtIHRpbmNpZHVudCBtb2xlc3RpZSBpcHN1bSB2ZWwgcmhv +bmN1cy4gSW50ZWdlciBlZ2V0IG51bmMgZXUgdGVsbHVzIHRpbmNpZHVudCBsYWNp +bmlhLiBJbnRlZ2VyIG5lYyBuaXNpIGVnZXQgYXVndWUgc2VtcGVyIHZhcml1cyBp +ZCBhYyBxdWFtLiBOYW0gdGluY2lkdW50LCB0ZWxsdXMgYWMgY29uZGltZW50dW0g +YWNjdW1zYW4sIGRvbG9yIGVyb3Mgdml2ZXJyYSBsZW8sIHBoYXJldHJhIHB1bHZp +bmFyIGxlY3R1cyBlcm9zIGluIG1pLiBEb25lYyBjb25zZXF1YXQsIHR1cnBpcyBp +ZCBjb252YWxsaXMgdm9sdXRwYXQsIGFudGUgc2VtIGVsZW1lbnR1bSBtYWduYSwg +cXVpcyB0ZW1wb3IgcmlzdXMgZGlhbSB2ZWwgdHVycGlzLiBNb3JiaSBhIG9yY2kg +b3JjaSwgZWdlc3RhcyBmZXVnaWF0IGxlY3R1cy4gTnVsbGEgbmVjIG5pYmggaWQg +YXVndWUgaW50ZXJkdW0gbW9sbGlzLiBTdXNwZW5kaXNzZSBwbGFjZXJhdCB0ZW1w +dXMgbnVuYyBhYyB2ZXN0aWJ1bHVtLiBEb25lYyBldCBtZXR1cyBkaWN0dW0gbGVv +IGJpYmVuZHVtIHVsdHJpY2VzIGluIG5lYyBsZWN0dXMuIFV0IHNlZCB2ZWxpdCBu +aWJoLCBzb2RhbGVzIHBvcnRhIG51bmMuIEluIGhhYyBoYWJpdGFzc2UgcGxhdGVh +IGRpY3R1bXN0LiBTZWQgZWxpdCB0b3J0b3IsIGFsaXF1ZXQgdmVsIHZvbHV0cGF0 +IGEsIHRpbmNpZHVudCBzZWQgc2FwaWVuLiBTdXNwZW5kaXNzZSBlZ2V0IGxpYmVy +byBsYWN1cy4gVml2YW11cyBhdWN0b3IgYW50ZSBub24gbmVxdWUgcG9ydHRpdG9y +IHV0IHByZXRpdW0gbmlzbCB0ZW1wdXMuIE51bGxhIHNvZGFsZXMgcmlzdXMgZXQg +ZXJhdCB2YXJpdXMgbGFvcmVldC4gTWFlY2VuYXMgbHVjdHVzIGxvYm9ydGlzIGxp +Z3VsYSBlZ2V0IGZlcm1lbnR1bS4KClZpdmFtdXMgY29udmFsbGlzIG5pYmggdml0 +YWUgdHVycGlzIGZldWdpYXQgdWx0cmljZXMuIFF1aXNxdWUgdml0YWUgYmxhbmRp +dCBtYXNzYS4gTWF1cmlzIGV1aXNtb2QgdXJuYSB1dCBuZXF1ZSBmZXJtZW50dW0g +dml0YWUgaW1wZXJkaWV0IG1hdXJpcyBldWlzbW9kLiBJbiBhIGR1aSB0ZWxsdXMs +IG5lYyBwb3N1ZXJlIGRvbG9yLiBBZW5lYW4gdWxsYW1jb3JwZXIgYXVndWUgaWQg +ZXJhdCBsYWNpbmlhIHB1bHZpbmFyLiBQZWxsZW50ZXNxdWUgYXQgbnVsbGEgdGVs +bHVzLiBOYW0gZWxlbWVudHVtIGlhY3VsaXMgcHVsdmluYXIuIFZpdmFtdXMgdG9y +dG9yIGxlY3R1cywgZ3JhdmlkYSB1dCBjb21tb2RvIGEsIHZpdmVycmEgdXQgb2Rp +by4gUGhhc2VsbHVzIGVsZW1lbnR1bSBibGFuZGl0IG9kaW8sIG5lYyBkYXBpYnVz +IGFudGUgbWFsZXN1YWRhIGEuIE1hZWNlbmFzIGltcGVyZGlldCwgZmVsaXMgYSBz +ZW1wZXIgZmFjaWxpc2lzLCBtYXNzYSBudWxsYSBhbGlxdWV0IHRvcnRvciwgZXQg +bWFsZXN1YWRhIG1hZ25hIGxlY3R1cyBhYyBwdXJ1cy4gQWVuZWFuIGF1Y3RvciB0 +ZWxsdXMgaWQganVzdG8gY29uZGltZW50dW0gdHJpc3RpcXVlLiBDcmFzIHZpdGFl +IHJ1dHJ1bSBhcmN1LiBNYXVyaXMgdGVtcHVzLCBtYWduYSBlZ2V0IHZhcml1cyBp +bnRlcmR1bSwgbmlzbCBqdXN0byBwb3J0YSBhdWd1ZSwgc2VkIHBvcnRhIG5pc2wg +cXVhbSBhIG5pYmguIE1hZWNlbmFzIHZpdGFlIHB1cnVzIGRpYW0uIFByYWVzZW50 +IGJpYmVuZHVtIG5pYmggZHVpLCBpbiB0aW5jaWR1bnQgbnVuYy4gRHVpcyB2aXRh +ZSBzZW0gYW50ZS4KCk1hdXJpcyBwb3N1ZXJlIGZlbGlzIGV0IHR1cnBpcyBzb2Rh +bGVzIGhlbmRyZXJpdCB1dCBpZCBudW5jLiBEb25lYyBsYW9yZWV0IG1hbGVzdWFk +YSBlcm9zLiBOYW0gcXVpcyBkaWFtIGFyY3UsIGV1IHRyaXN0aXF1ZSB0ZWxsdXMu +IFBlbGxlbnRlc3F1ZSBxdWlzIGVsaXQgbnVuYy4gQ3JhcyBsZW8gbG9yZW0sIG9y +bmFyZSBjb21tb2RvIG1vbGVzdGllIHNpdCBhbWV0LCBjb25zZXF1YXQgdmVsIGVz +dC4gSW4gaGFjIGhhYml0YXNzZSBwbGF0ZWEgZGljdHVtc3QuIENyYXMgcmlzdXMg +cXVhbSwgc3VzY2lwaXQgc2VtcGVyIGltcGVyZGlldCB1bHRyaWNlcywgdHJpc3Rp +cXVlIG5lYyBzYXBpZW4uIFBlbGxlbnRlc3F1ZSBjb25kaW1lbnR1bSwgdHVycGlz +IG5lYyBzb2RhbGVzIGNvbnNlY3RldHVyLCBkaWFtIHNlbSBiaWJlbmR1bSBkaWFt +LCB2aXRhZSBhbGlxdWV0IG1pIGFyY3UgYSBhcmN1LiBQaGFzZWxsdXMgaGVuZHJl +cml0LCBtYWduYSBxdWlzIGdyYXZpZGEgZmVybWVudHVtLCBtYWduYSBsZWN0dXMg +c2VtcGVyIG1hc3NhLCBzZWQgY29uZ3VlIHVybmEgbmliaCBhdCBudWxsYS4gQ3Jh +cyBzZWQgbmliaCBtaS4gTnVsbGEgdGVtcG9yIHByZXRpdW0gcG9ydGEuCgpVdCBp +ZCBqdXN0byB2aXRhZSB0dXJwaXMgY29udmFsbGlzIGNvbmd1ZS4gQ3VyYWJpdHVy +IG1hbGVzdWFkYSBwdXJ1cyBlZ2V0IGRpYW0gYXVjdG9yIGV0IHVsbGFtY29ycGVy +IHZlbGl0IG1hbGVzdWFkYS4gUGhhc2VsbHVzIHNjZWxlcmlzcXVlIGZlcm1lbnR1 +bSBsaWJlcm8uIE1vcmJpIGR1aSB0b3J0b3IsIGJsYW5kaXQgbWFsZXN1YWRhIGxv +Ym9ydGlzIHVsdHJpY2llcywgYmxhbmRpdCBldCBuaXNpLiBOdWxsYSBtYXR0aXMg +ZmFjaWxpc2lzIGxhY3VzLiBBbGlxdWFtIHNvZGFsZXMgZWxpdCBzaXQgYW1ldCBt +ZXR1cyB2ZW5lbmF0aXMgYSBjb21tb2RvIHF1YW0gYmliZW5kdW0uIFV0IG5vbiB0 +ZWxsdXMgdG9ydG9yLiBTZWQgc2VtcGVyLCBuaXNpIGluIHRlbXBvciB2ZXN0aWJ1 +bHVtLCBzZW0gbnVsbGEgZXVpc21vZCBhcmN1LCB1dCBzb2RhbGVzIGVzdCBudW5j +IGF0IHRlbGx1cy4gRG9uZWMgbm9uIG1ldHVzIG5vbiBkb2xvciBzY2VsZXJpc3F1 +ZSB2aXZlcnJhLiBQaGFzZWxsdXMgbmVjIG51bGxhIGp1c3RvLCB1dCBwb3J0dGl0 +b3IgbnVsbGEuIEZ1c2NlIGZldWdpYXQgZ3JhdmlkYSBzb2xsaWNpdHVkaW4uIFNl +ZCBpZCBoZW5kcmVyaXQgbWF1cmlzLiBEb25lYyBsZWN0dXMgdG9ydG9yLCBwb3J0 +YSBzaXQgYW1ldCBjb25kaW1lbnR1bSBzZWQsIHZhcml1cyBhIHZlbGl0LiBJbiBk +aWN0dW0gZG9sb3Igc2VkIGVzdCBkaWN0dW0gaW4gcnV0cnVtIG5lcXVlIHN1c2Np +cGl0LgoKTWFlY2VuYXMgaW1wZXJkaWV0IGNvbnZhbGxpcyB1bHRyaWNpZXMuIEN1 +bSBzb2NpaXMgbmF0b3F1ZSBwZW5hdGlidXMgZXQgbWFnbmlzIGRpcyBwYXJ0dXJp +ZW50IG1vbnRlcywgbmFzY2V0dXIgcmlkaWN1bHVzIG11cy4gUGVsbGVudGVzcXVl +IG51bmMgdHVycGlzLCBpYWN1bGlzIHF1aXMgZWxlaWZlbmQgZXUsIHRpbmNpZHVu +dCB1dCBsYWN1cy4gQ3VyYWJpdHVyIHZpdGFlIHRlbGx1cyBuaWJoLiBQZWxsZW50 +ZXNxdWUgZWdldCBjb21tb2RvIG5pYmguIE51bGxhIGxhb3JlZXQsIGVyb3MgaWQg +aW1wZXJkaWV0IG1vbGxpcywgbmlzaSBlc3QgZWdlc3RhcyBmZWxpcywgZWdldCBs +dWN0dXMgZW5pbSBsYWN1cyB2aXRhZSBhcmN1LiBOdWxsYW0gaXBzdW0gZGlhbSwg +ZmF1Y2lidXMgZmV1Z2lhdCBjb21tb2RvIGV0LCB0ZW1wb3IgYWMgbGFjdXMuIERv +bmVjIHZlbCBlcmF0IG1hc3NhLCBhdCBwcmV0aXVtIGVzdC4gUGVsbGVudGVzcXVl +IGx1Y3R1cyBuaXNpIG51bGxhLCBhYyBhbGlxdWV0IGF1Z3VlLiBNYWVjZW5hcyBp +ZCBwaGFyZXRyYSBkb2xvci4gUHJvaW4gZGFwaWJ1cyBtYXR0aXMgY3Vyc3VzLiBN +b3JiaSBpbnRlcmR1bSwgZW5pbSBxdWlzIGZlcm1lbnR1bSBwbGFjZXJhdCwgbmlz +aSBtaSBjb25ndWUgc2VtLCBhIHRlbXBvciBuaXNsIG1hdXJpcyBpbiBzZW0uIElu +IGNvbmRpbWVudHVtLCBpcHN1bSBuZWMgdmVuZW5hdGlzIHZlbmVuYXRpcywgbnVs +bGEgZW5pbSBsYW9yZWV0IGFudGUsIG5lYyBoZW5kcmVyaXQgaXBzdW0gbGVjdHVz +IGVnZXQgcmlzdXMuIFBlbGxlbnRlc3F1ZSBlbmltIGxpYmVybywgdGluY2lkdW50 +IHZpdGFlIG1vbGVzdGllIHNpdCBhbWV0LCBncmF2aWRhIG5lYyBsYWN1cy4gRHVp +cyBhYyBzYXBpZW4gbGliZXJvLCBpbiBhbGlxdWV0IHF1YW0uIE1vcmJpIHRlbXBv +ciBsaWJlcm8gcXVpcyBlc3QgZ3JhdmlkYSBzZWQgZWdlc3RhcyBudWxsYSB2dWxw +dXRhdGUuCgpEb25lYyBsYWNpbmlhIG1pIGF0IHRlbGx1cyB2aXZlcnJhIGxvYm9y +dGlzLiBOdWxsYSBpbnRlcmR1bSwgdXJuYSB1dCBmYXVjaWJ1cyBzZW1wZXIsIGR1 +aSBsZWN0dXMgZnJpbmdpbGxhIGVyYXQsIHV0IGFsaXF1YW0gbmlzbCBpcHN1bSBh +dCBlcm9zLiBWaXZhbXVzIGNvbnZhbGxpcyBoZW5kcmVyaXQgYXJjdSBxdWlzIGNv +bmRpbWVudHVtLiBQcmFlc2VudCBhdCBmZXVnaWF0IHNhcGllbi4gUXVpc3F1ZSBu +b24gb3JjaSBhcmN1LiBQZWxsZW50ZXNxdWUgZWdldCBtaSBhcmN1LCBzaXQgYW1l +dCBsdWN0dXMgbnVuYy4gQ3VyYWJpdHVyIGxlY3R1cyBsZW8sIGNvbnNlcXVhdCBz +ZW1wZXIgaW1wZXJkaWV0IGV0LCBlbGVtZW50dW0gdml0YWUgZGlhbS4gUHJvaW4g +cHVydXMgbnVsbGEsIHB1bHZpbmFyIGlkIGltcGVyZGlldCBzZWQsIGZldWdpYXQg +YSBudWxsYS4gUHJvaW4gc3VzY2lwaXQgZWxpdCB2ZWwgYXJjdSB2ZW5lbmF0aXMg +c29kYWxlcy4gQ3JhcyBhY2N1bXNhbiBtYXNzYSBhYyBudWxsYSBwdWx2aW5hciBm +ZXVnaWF0IGV1IGF0IHRlbGx1cy4gUXVpc3F1ZSB2aXRhZSBlcmF0IG9yY2ksIG5v +biB0ZW1wb3IgZW5pbS4gRG9uZWMgb3JuYXJlIGxvYm9ydGlzIG1pIHZpdGFlIGNv +bnNlcXVhdC4gSW50ZWdlciB2aXZlcnJhLCB2ZWxpdCB2ZWwgcGVsbGVudGVzcXVl +IGFjY3Vtc2FuLCBhdWd1ZSBsaWd1bGEgYmxhbmRpdCBuaXNsLCBlZ2V0IGNvbmRp +bWVudHVtIG5lcXVlIGFyY3UgaW4gZXJhdC4gTmFtIHF1aXMgbG9yZW0gbG9yZW0s +IHZlbCBjdXJzdXMgcmlzdXMuIEluIG5lYyBudW5jIGRvbG9yLCBxdWlzIHBvcnR0 +aXRvciBuZXF1ZS4gTWFlY2VuYXMgdHVycGlzIG9kaW8sIGRpY3R1bSB2aXRhZSBj +b21tb2RvIHRpbmNpZHVudCwgYWxpcXVhbSB1dCBhdWd1ZS4gUGhhc2VsbHVzIGF0 +IGp1c3RvIGxhY3VzLiBQaGFzZWxsdXMgc2l0IGFtZXQgdXJuYSBhdCBhbnRlIHZh +cml1cyBwZWxsZW50ZXNxdWUuIFBlbGxlbnRlc3F1ZSBpbiBsaWJlcm8gYWMgdXJu +YSBmcmluZ2lsbGEgdGluY2lkdW50IHZpdGFlIHNlZCB2ZWxpdC4KCkRvbmVjIGFj +IHJpc3VzIHNhcGllbi4gTnVsbGEgZmFjaWxpc2kuIERvbmVjIGF0IHZlbGl0IG5v +biBudW5jIHRlbXB1cyBmZXJtZW50dW0uIEN1bSBzb2NpaXMgbmF0b3F1ZSBwZW5h +dGlidXMgZXQgbWFnbmlzIGRpcyBwYXJ0dXJpZW50IG1vbnRlcywgbmFzY2V0dXIg +cmlkaWN1bHVzIG11cy4gRnVzY2UgaW50ZXJkdW0gYWxpcXVhbSBsb3JlbSwgaW4g +c2NlbGVyaXNxdWUgZW5pbSB0aW5jaWR1bnQgaWQuIFByYWVzZW50IHNvbGxpY2l0 +dWRpbiBkdWkgbmVjIGxhY3VzIGxhY2luaWEgcGxhY2VyYXQuIFV0IGVnZXQgbWF0 +dGlzIG1ldHVzLiBJbiB2ZWwgc2VtIHVybmEsIGV1IGNvbnZhbGxpcyB0dXJwaXMu +IER1aXMgaGVuZHJlcml0IGlwc3VtIHVybmEsIG5vbiBwZWxsZW50ZXNxdWUgb3Jj +aS4gVXQgZXN0IG1ldHVzLCBlbGVtZW50dW0gaW4gYmliZW5kdW0gaWQsIHZpdmVy +cmEgZGlnbmlzc2ltIHRlbGx1cy4gRHVpcyBpZCBlcmF0IGxpYmVyby4gVmVzdGli +dWx1bSBpbiBsaWJlcm8gbm9uIHNlbSB0aW5jaWR1bnQgZWxlbWVudHVtIHNlZCBl +dCBuaXNpLiBQaGFzZWxsdXMgbGVjdHVzIGVyYXQsIGVsZWlmZW5kIGlkIHNhZ2l0 +dGlzIHV0LCBmcmluZ2lsbGEgc2VkIHR1cnBpcy4gQWxpcXVhbSB2ZWwgZXJvcyBp +ZCBudW5jIHZlbmVuYXRpcyB1bGxhbWNvcnBlci4gQWxpcXVhbSB0cmlzdGlxdWUg +bWFzc2EgYSBtYXVyaXMgc2NlbGVyaXNxdWUgbm9uIGZhdWNpYnVzIG5lcXVlIHVs +dHJpY2llcy4KCkFsaXF1YW0gY29uc2VxdWF0IGx1Y3R1cyBlbGl0LCBpZCBtYWxl +c3VhZGEgZXJvcyBsb2JvcnRpcyB1dC4gTnVsbGFtIGEgaGVuZHJlcml0IGxpYmVy +by4gTWFlY2VuYXMgZXQgc2VtIGF0IGVyYXQgbWF0dGlzIGVsZWlmZW5kIHNlZCBz +aXQgYW1ldCBzZW0uIE51bGxhIGxvYm9ydGlzIG5pYmggYSBvcmNpIGVsZWlmZW5k +IHRlbXBvci4gUHJvaW4gbnVsbGEgZmVsaXMsIHZlbmVuYXRpcyBxdWlzIHVsdHJp +Y2llcyB2ZWwsIGFsaXF1ZXQgaW4gZG9sb3IuIFBoYXNlbGx1cyB0aW5jaWR1bnQg +ZG9sb3IgZmVybWVudHVtIG1hc3NhIGlhY3VsaXMgZGlnbmlzc2ltIHZlbCB1dCBk +dWkuIFByb2luIHRpbmNpZHVudCBzYWdpdHRpcyBzb2RhbGVzLiBQcm9pbiBtYXR0 +aXMgdmFyaXVzIGVuaW0sIGF0IGx1Y3R1cyBzZW0gaGVuZHJlcml0IGV1LiBVdCB2 +aXRhZSBncmF2aWRhIG9kaW8uIEFsaXF1YW0gZXJhdCB2b2x1dHBhdC4gTnVsbGEg +ZnJpbmdpbGxhIHBsYWNlcmF0IHZlbGl0LCBzZWQgYWxpcXVldCBudWxsYSBpbXBl +cmRpZXQgYS4gRG9uZWMgZWxlaWZlbmQgcHVsdmluYXIgb3JjaSwgaW4gcG9ydGEg +ZGlhbSBwb3N1ZXJlIGJpYmVuZHVtLiBQcm9pbiBlZ2VzdGFzIHBvcnR0aXRvciBh +bGlxdWFtLiBRdWlzcXVlIHNhcGllbiBmZWxpcywgaGVuZHJlcml0IGlkIGNvbmd1 +ZSBldSwgdGluY2lkdW50IHNlZCBlc3QuIFZpdmFtdXMgY3Vyc3VzIHByZXRpdW0g +ZXJhdCB1dCBmYXVjaWJ1cy4gSW50ZWdlciBsaWJlcm8gZWxpdCwgdmVuZW5hdGlz +IHZlbCBhbGlxdWV0IG5lYywgaW50ZXJkdW0gaW4gZW5pbS4gTmFtIGEgdmVsaXQg +anVzdG8sIHZpdGFlIGlhY3VsaXMgdHVycGlzLgoKVml2YW11cyBuaWJoIGxpZ3Vs +YSwgaW50ZXJkdW0gdmVzdGlidWx1bSB2ZW5lbmF0aXMgdml0YWUsIGZlcm1lbnR1 +bSBpbiBtYWduYS4gU3VzcGVuZGlzc2UgZHVpIGFyY3UsIGdyYXZpZGEgYWMgZWdl +c3RhcyBub24sIGNvbmd1ZSBub24gZGlhbS4gUGVsbGVudGVzcXVlIGhhYml0YW50 +IG1vcmJpIHRyaXN0aXF1ZSBzZW5lY3R1cyBldCBuZXR1cyBldCBtYWxlc3VhZGEg +ZmFtZXMgYWMgdHVycGlzIGVnZXN0YXMuIFBlbGxlbnRlc3F1ZSBwdWx2aW5hciBw +aGFyZXRyYSBsb3JlbSwgZXQgcG9zdWVyZSBzZW0gY29uZ3VlIHV0LiBTZWQgZWxl +bWVudHVtIGNvbnZhbGxpcyBkb2xvciBldSB2dWxwdXRhdGUuIEludGVnZXIgbmli +aCBqdXN0bywgcGVsbGVudGVzcXVlIGVnZXQgdWx0cmljaWVzIGF1Y3RvciwgZmVy +bWVudHVtIG5vbiBtaS4gUGVsbGVudGVzcXVlIGF0IG5lcXVlIGVzdC4gQ3VyYWJp +dHVyIHBlbGxlbnRlc3F1ZSBhcmN1IHNlZCBsYWN1cyBwbGFjZXJhdCBxdWlzIGRp +Z25pc3NpbSBvcmNpIHBsYWNlcmF0LiBOdWxsYW0gcGVsbGVudGVzcXVlIGxpYmVy +byBpZCBhbnRlIGRhcGlidXMgc2VkIGJpYmVuZHVtIG1ldHVzIHRyaXN0aXF1ZS4g +Vml2YW11cyBpZCBkdWkgcXVpcyBhcmN1IHVsdHJpY2VzIHZpdmVycmEuIFBlbGxl +bnRlc3F1ZSBhdWN0b3IgbmlzaSBzZWQgZXN0IGxhb3JlZXQgdml2ZXJyYS4gU3Vz +cGVuZGlzc2UgbGFjaW5pYSBsZWN0dXMgbWFzc2EuIEFsaXF1YW0gZXJhdCB2b2x1 +dHBhdC4KClF1aXNxdWUgdWxsYW1jb3JwZXIgYXVndWUgaW4ganVzdG8gdWx0cmlj +aWVzIHBvcnRhLiBTZWQgcXVpcyBhcmN1IGFjIGxvcmVtIGFjY3Vtc2FuIHBvc3Vl +cmUuIE1hdXJpcyBjb25zZXF1YXQsIGxpYmVybyBlZ2V0IGZldWdpYXQgbG9ib3J0 +aXMsIGlwc3VtIGZlbGlzIHZlc3RpYnVsdW0gdGVsbHVzLCB2ZWwgdWx0cmljZXMg +aXBzdW0gYXJjdSBldSBuaXNsLiBDdW0gc29jaWlzIG5hdG9xdWUgcGVuYXRpYnVz +IGV0IG1hZ25pcyBkaXMgcGFydHVyaWVudCBtb250ZXMsIG5hc2NldHVyIHJpZGlj +dWx1cyBtdXMuIEluIGhhYyBoYWJpdGFzc2UgcGxhdGVhIGRpY3R1bXN0LiBEdWlz +IHZpdmVycmEgdHVycGlzIHZlbCBlbGl0IGVsZWlmZW5kIGF0IHBvcnR0aXRvciB2 +ZWxpdCByaG9uY3VzLiBTZWQgYXQgZG9sb3IgcXVpcyBuaXNpIGNvbW1vZG8gcG9y +dHRpdG9yLiBNb3JiaSBsb3JlbSBvcmNpLCBjb21tb2RvIGEgbGFvcmVldCBuZWMs +IHZhcml1cyBhdCBsYWN1cy4gTWF1cmlzIHNlZCB2YXJpdXMgZW5pbS4gQWxpcXVh +bSBncmF2aWRhIGFkaXBpc2Npbmcgc2VtIG5vbiBzZW1wZXIuIFN1c3BlbmRpc3Nl +IGVnZXQgZ3JhdmlkYSBudW5jLgoKQ3JhcyB2ZXN0aWJ1bHVtIHRvcnRvciBuZWMg +bGlndWxhIG9ybmFyZSB0ZW1wb3IuIFV0IGlhY3VsaXMgbGlndWxhIGV0IGxlY3R1 +cyB0aW5jaWR1bnQgaWFjdWxpcy4gTWFlY2VuYXMgcHVsdmluYXIgdm9sdXRwYXQg +bGFjaW5pYS4gQ3VyYWJpdHVyIGhlbmRyZXJpdCBtYWxlc3VhZGEgbGVjdHVzLCBz +ZWQgbWFsZXN1YWRhIGVyb3MgZWdlc3RhcyBlZ2V0LiBBbGlxdWFtIGJpYmVuZHVt +IHZhcml1cyBvZGlvIHZhcml1cyBtYXR0aXMuIFByb2luIGFjIHJob25jdXMgYXJj +dS4gTnVsbGEgc3VzY2lwaXQgdG9ydG9yIGEgZXN0IHZpdmVycmEgdWxsYW1jb3Jw +ZXIuIEN1cmFiaXR1ciBldCBkdWkgZGlhbS4gU2VkIGF0IG5lcXVlIG5pc2wuIEN1 +cmFiaXR1ciBzYWdpdHRpcyBvcmNpIG5pc2wuIEN1bSBzb2NpaXMgbmF0b3F1ZSBw +ZW5hdGlidXMgZXQgbWFnbmlzIGRpcyBwYXJ0dXJpZW50IG1vbnRlcywgbmFzY2V0 +dXIgcmlkaWN1bHVzIG11cy4KCkNyYXMgZmVsaXMgbWV0dXMsIHZhcml1cyBzaXQg +YW1ldCBjb25zZXF1YXQgZWdldCwgc2VtcGVyIHZpdGFlIGxlby4gTWF1cmlzIHV0 +IG5pc2kgbGFjdXMsIGEgcHJldGl1bSBsYWN1cy4gRHVpcyBlZ2V0IGVzdCBuZWMg +ZG9sb3Igc29sbGljaXR1ZGluIGZlcm1lbnR1bS4gTWFlY2VuYXMgb3JuYXJlIGFk +aXBpc2NpbmcgZHVpLCB2aXRhZSBwZWxsZW50ZXNxdWUgbmlzbCBhbGlxdWFtIGEu +IFZpdmFtdXMgYXVjdG9yIGZyaW5naWxsYSBsaWd1bGEsIGlkIHRlbXBvciBqdXN0 +byBjb25ndWUgYS4gUHJhZXNlbnQgcXVpcyBsYW9yZWV0IGF1Z3VlLiBEb25lYyBp +ZCBvcmNpIHV0IG5pc2kgdml2ZXJyYSBjb21tb2RvLiBQZWxsZW50ZXNxdWUgZGlj +dHVtIHZhcml1cyBvcmNpIHZlbCBwaGFyZXRyYS4gTnVuYyBsaWJlcm8gbmlzbCBt +YXNzYSBudW5jLg== + + + + text/plain + + + + + \ No newline at end of file -- cgit v1.2.3 From b7dd29046e232e4d42623655efc28965cce942b8 Mon Sep 17 00:00:00 2001 From: clemenso Date: Fri, 13 Nov 2009 15:13:21 +0000 Subject: git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@546 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- .../egiz/bku/online/applet/AppletSecureViewer.java | 4 +- BKUApplet/src/test/resources/DejaVuLGCSansMono.ttf | Bin 0 -> 282704 bytes BKUApplet/src/test/resources/appletTest.html | 6 +- .../main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java | 5 +- .../main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java | 318 +++++++++++---------- .../main/java/at/gv/egiz/bku/gui/MimeFilter.java | 110 ------- .../at/gv/egiz/bku/gui/SecureViewerDialog.java | 146 ++++------ .../java/at/gv/egiz/bku/gui/viewer/MimeFilter.java | 115 ++++++++ .../bku/gui/viewer/SecureViewerSaveDialog.java | 120 ++++++++ .../at/gv/egiz/bku/gui/Messages.properties | 4 + .../at/gv/egiz/bku/gui/Messages_en.properties | 2 +- .../at/gv/egiz/bku/gui/SecureViewerDialogTest.java | 4 +- .../webapp/help/de/help.unsupported.mimetype.html | 41 +++ .../gv/egiz/stal/service/impl/STALServiceImpl.java | 258 +++++++++-------- .../egiz/stal/service/impl/TestSignatureData.java | 47 +++ .../egiz/bku/slcommands/impl/xsect/DataObject.java | 3 +- 16 files changed, 694 insertions(+), 489 deletions(-) create mode 100644 BKUApplet/src/test/resources/DejaVuLGCSansMono.ttf delete mode 100644 BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/MimeFilter.java create mode 100644 BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeFilter.java create mode 100644 BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewerSaveDialog.java create mode 100644 BKUHelp/src/main/webapp/help/de/help.unsupported.mimetype.html create mode 100644 BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/TestSignatureData.java (limited to 'bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java') diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java index 929cecb1..2e0cb331 100644 --- a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java +++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java @@ -185,13 +185,13 @@ public class AppletSecureViewer implements SecureViewer { throw new Exception("No hashdata input for reference " + signedRefId + " provided by service"); } if (log.isDebugEnabled()) { - log.debug("Got HashDataInput " + signedRefId + " (" + mimeType + ";" + encoding + ")"); + log.debug("Digesting reference " + signedRefId + " (" + mimeType + ";" + encoding + ")"); } byte[] hashDataInputDigest = digest(hdi, signedDigestAlg); if (log.isDebugEnabled()) { - log.debug("Comparing digest values... "); + log.debug("Comparing digest to claimed digest value for reference " + signedRefId); } // log.warn("***************** DISABLED HASHDATA VERIFICATION"); if (!Arrays.equals(hashDataInputDigest, signedDigest)) { diff --git a/BKUApplet/src/test/resources/DejaVuLGCSansMono.ttf b/BKUApplet/src/test/resources/DejaVuLGCSansMono.ttf new file mode 100644 index 00000000..21647753 Binary files /dev/null and b/BKUApplet/src/test/resources/DejaVuLGCSansMono.ttf differ diff --git a/BKUApplet/src/test/resources/appletTest.html b/BKUApplet/src/test/resources/appletTest.html index 85834763..22495a32 100644 --- a/BKUApplet/src/test/resources/appletTest.html +++ b/BKUApplet/src/test/resources/appletTest.html @@ -21,7 +21,7 @@ -

Run applet test with appletviewer -J-Djava.security.policy=appletviewer.policy appletTest.html

+

Run applet test with appletviewer (-J-d32) -J-Djava.security.policy=appletviewer.policy appletTest.html

@@ -30,8 +30,8 @@ - - + + diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java index e4af6443..91c91dcb 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java @@ -46,7 +46,7 @@ public interface BKUGUIFacade { public static final String DEFAULT_BACKGROUND = "/at/gv/egiz/bku/gui/chip32.png"; public static final String DEFAULT_ICON = "/at/gv/egiz/bku/gui/chiperling105.png"; public static final String HELP_IMG = "/at/gv/egiz/bku/gui/help.png"; - public static final String HELP_IMG_FOCUS = "/at/gv/egiz/bku/gui/help_focus.png"; + public static final String HELP_IMG_FOCUS = "/at/gv/egiz/bku/gui/help.png"; //help_focus.png"; public static final String HASHDATA_FONT = "Monospaced"; public static final Color ERROR_COLOR = Color.RED; public static final Color HYPERLINK_COLOR = Color.BLUE; @@ -56,6 +56,7 @@ public interface BKUGUIFacade { public static final String TITLE_CARDPIN = "title.cardpin"; public static final String TITLE_SIGN = "title.sign"; public static final String TITLE_ERROR = "title.error"; + public static final String TITLE_WARNING = "title.warning"; public static final String TITLE_ENTRY_TIMEOUT = "title.entry.timeout"; public static final String TITLE_RETRY = "title.retry"; public static final String TITLE_WAIT = "title.wait"; @@ -79,6 +80,8 @@ public interface BKUGUIFacade { public static final String MESSAGE_HASHDATALINK_FOCUS = "hashdatalink.focus"; public static final String MESSAGE_HASHDATALINK_TINY_FOCUS = "hashdatalink.tiny.focus"; public static final String MESSAGE_HASHDATALIST = "hashdatalist"; + public static final String MESSAGE_HASHDATA_VIEWER = "hashdata.viewer"; + public static final String MESSAGE_UNSUPPORTED_MIMETYPE = "unsupported.mimetype"; public static final String MESSAGE_RETRIES = "retries"; public static final String MESSAGE_LAST_RETRY = "retries.last"; public static final String MESSAGE_RETRIES_PINPAD = "retries.pinpad"; diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java index 20fe4f56..baffb3fd 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java @@ -19,6 +19,7 @@ package at.gv.egiz.bku.gui; import at.gv.egiz.bku.gui.viewer.FontProviderException; import at.gv.egiz.bku.gui.viewer.FontProvider; +import at.gv.egiz.bku.gui.viewer.SecureViewerSaveDialog; import at.gv.egiz.smcc.PINSpec; import at.gv.egiz.stal.HashDataInput; import java.awt.Color; @@ -1384,26 +1385,34 @@ public class BKUGUIImpl implements BKUGUIFacade { new Object[] {"no signature data provided"}, backListener, backCommand); } else if (dataToBeSigned.size() == 1) { - try { - log.debug("[" + Thread.currentThread().getName() + "] scheduling secure viewer"); - - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { - try { - showSecureViewer(dataToBeSigned.get(0)); - } catch (FontProviderException ex) { - log.error("failed to display secure viewer", ex); - showErrorDialog(ERR_VIEWER, new Object[] {ex.getMessage()}, backListener, backCommand); + //TODO pull out (see also SignedReferencesSelectionListener) + if (SecureViewerDialog.SUPPORTED_MIME_TYPES.contains(dataToBeSigned.get(0).getMimeType())) { + try { + log.debug("[" + Thread.currentThread().getName() + "] scheduling secure viewer"); + + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + try { + showMessageDialog(TITLE_HASHDATA, MESSAGE_HASHDATA_VIEWER); + showSecureViewer(dataToBeSigned.get(0), backListener, backCommand); + } catch (FontProviderException ex) { + log.error("failed to display secure viewer", ex); + showErrorDialog(ERR_VIEWER, new Object[] {ex.getMessage()}, backListener, backCommand); + } } - } - }); - - } catch (Exception ex) { //InterruptedException InvocationTargetException - log.error("Failed to display secure viewer: " + ex.getMessage()); - log.trace(ex); - showErrorDialog(ERR_UNKNOWN, null, backListener, backCommand); + }); + + } catch (Exception ex) { //InterruptedException InvocationTargetException + log.error("Failed to display secure viewer: " + ex.getMessage()); + log.trace(ex); + showErrorDialog(ERR_UNKNOWN, null, backListener, backCommand); + } + } else { + log.debug("[" + Thread.currentThread().getName() + "] mime-type not supported by secure viewer, scheduling save dialog"); + showMessageDialog(TITLE_HASHDATA, MESSAGE_UNSUPPORTED_MIMETYPE); + SecureViewerSaveDialog.showSaveDialog(dataToBeSigned.get(0), messages, backListener, backCommand); } } else { showSignedReferencesListDialog(dataToBeSigned, backListener, backCommand); @@ -1412,30 +1421,48 @@ public class BKUGUIImpl implements BKUGUIFacade { /** * has to be called from event dispatcher thread - * This method blocks until the dialog's close button is pressed. * @param hashDataText * @param saveListener * @param saveCommand */ - private void showSecureViewer(HashDataInput dataToBeSigned) throws FontProviderException { +// private void showSecureViewer(HashDataInput dataToBeSigned) throws FontProviderException { +// +// log.debug("[" + Thread.currentThread().getName() + "] show secure viewer"); +// if (secureViewer == null) { +// secureViewer = new SecureViewerDialog(null, messages, +// fontProvider, helpMouseListener.getActionListener()); +// +// // workaround for [#439] +// // avoid AlwaysOnTop at least in applet, otherwise make secureViewer AlwaysOnTop since MOCCA Dialog (JFrame created in LocalSTALFactory) is always on top. +// Window window = SwingUtilities.getWindowAncestor(contentPane); +// if (window != null && window.isAlwaysOnTop()) { +// log.debug("make secureViewer alwaysOnTop"); +// secureViewer.setAlwaysOnTop(true); +// } +// } +// secureViewer.setContent(dataToBeSigned); +// log.trace("show secure viewer returned"); +// } + private void showSecureViewer(HashDataInput dataToBeSigned, ActionListener closeListener, String closeCommand) throws FontProviderException { log.debug("[" + Thread.currentThread().getName() + "] show secure viewer"); - if (secureViewer == null) { - secureViewer = new SecureViewerDialog(null, messages, - fontProvider, helpMouseListener.getActionListener()); - - // workaround for [#439] - // avoid AlwaysOnTop at least in applet, otherwise make secureViewer AlwaysOnTop since MOCCA Dialog (JFrame created in LocalSTALFactory) is always on top. - Window window = SwingUtilities.getWindowAncestor(contentPane); - if (window != null && window.isAlwaysOnTop()) { - log.debug("make secureViewer alwaysOnTop"); - secureViewer.setAlwaysOnTop(true); - } + SecureViewerDialog secureViewer = new SecureViewerDialog(null, messages, + closeListener, closeCommand, + fontProvider, helpMouseListener.getActionListener()); + + // workaround for [#439] + // avoid AlwaysOnTop at least in applet, otherwise make secureViewer AlwaysOnTop since MOCCA Dialog (JFrame created in LocalSTALFactory) is always on top. + Window window = SwingUtilities.getWindowAncestor(contentPane); + if (window != null && window.isAlwaysOnTop()) { + log.debug("make secureViewer alwaysOnTop"); + secureViewer.setAlwaysOnTop(true); } secureViewer.setContent(dataToBeSigned); - log.trace("show secure viewer returned"); + log.trace("viewer setContent returned"); } + + private void showSignedReferencesListDialog(final List signedReferences, final ActionListener backListener, final String backCommand) { @@ -1468,44 +1495,10 @@ public class BKUGUIImpl implements BKUGUIFacade { hashDataTable.setDefaultRenderer(HashDataInput.class, new HyperlinkRenderer(renderRefId)); hashDataTable.setTableHeader(null); - // not possible to add mouse listener to TableCellRenderer - hashDataTable.addMouseMotionListener(new MouseMotionAdapter() { - - @Override - public void mouseMoved(MouseEvent e) { - if (hashDataTable.columnAtPoint(e.getPoint()) == 0) { - hashDataTable.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } else { - hashDataTable.setCursor(Cursor.getDefaultCursor()); - } - } - }); + hashDataTable.addMouseMotionListener(new SignedReferencesMouseMotionListener(hashDataTable)); hashDataTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - hashDataTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - - @Override - public void valueChanged(final ListSelectionEvent e) { - //invoke later to allow thread to paint selection background - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { - ListSelectionModel lsm = (ListSelectionModel) e.getSource(); - int selectionIdx = lsm.getMinSelectionIndex(); - if (selectionIdx >= 0) { - final HashDataInput selection = signedReferences.get(selectionIdx); - try { - showSecureViewer(selection); - } catch (FontProviderException ex) { - log.error("failed to display secure viewer", ex); - showErrorDialog(ERR_VIEWER, new Object[] {ex.getMessage()}, backListener, backCommand); - } - } - } - }); - } - }); + hashDataTable.getSelectionModel().addListSelectionListener(new SignedReferencesSelectionListener(signedReferences, backListener, backCommand)); JScrollPane hashDataScrollPane = new JScrollPane(hashDataTable); @@ -1560,97 +1553,106 @@ public class BKUGUIImpl implements BKUGUIFacade { }); } + + /** - * @param okListener may be null + * not possible to add mouse listener to TableCellRenderer + * to change cursor on specific columns only, use table.columnAtPoint(e.getPoint()) + * */ -// private void showSaveDialog(final List signedRefs, -// final ActionListener okListener, final String okCommand) { -// -// log.debug("scheduling save dialog"); -// -// SwingUtilities.invokeLater(new Runnable() { -// -// @Override -// public void run() { -// -// log.debug("show save dialog"); -// -// String userHome = System.getProperty("user.home"); -// -// JFileChooser fileDialog = new JFileChooser(userHome); -// fileDialog.setMultiSelectionEnabled(false); -// fileDialog.setDialogType(JFileChooser.SAVE_DIALOG); -// fileDialog.setFileHidingEnabled(true); -// if (signedRefs.size() == 1) { -// fileDialog.setDialogTitle(getMessage(WINDOWTITLE_SAVE)); -// fileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY); -// String mimeType = signedRefs.get(0).getMimeType(); -// MimeFilter mimeFilter = new MimeFilter(mimeType, messages); -// fileDialog.setFileFilter(mimeFilter); -// String filename = getMessage(SAVE_HASHDATAINPUT_PREFIX) + MimeFilter.getExtension(mimeType); -// fileDialog.setSelectedFile(new File(userHome, filename)); -// } else { -// fileDialog.setDialogTitle(getMessage(WINDOWTITLE_SAVEDIR)); -// fileDialog.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); -// } -// -// //parent contentPane -> placed over applet -// switch (fileDialog.showSaveDialog(fileDialog)) { -// case JFileChooser.APPROVE_OPTION: -// File f = fileDialog.getSelectedFile(); -// for (HashDataInput hashDataInput : signedRefs) { -// String mimeType = hashDataInput.getMimeType(); -// String id = hashDataInput.getReferenceId(); -// File file; -// if (f.isDirectory()) { -// String filename = getMessage(SAVE_HASHDATAINPUT_PREFIX) + '_' + id + MimeFilter.getExtension(mimeType); -// file = new File(f, filename); -// } else { -// file = f; -// } -// if (file.exists()) { -// String ovrwrt = getMessage(MESSAGE_OVERWRITE); -// int overwrite = JOptionPane.showConfirmDialog(fileDialog, MessageFormat.format(ovrwrt, file), getMessage(WINDOWTITLE_OVERWRITE), JOptionPane.OK_CANCEL_OPTION); -// if (overwrite != JOptionPane.OK_OPTION) { -// continue; -// } -// } -// if (log.isDebugEnabled()) { -// log.debug("writing hashdata input " + id + " (" + mimeType + ") to file " + file); -// } -// FileOutputStream fos = null; -// try { -// fos = new FileOutputStream(file); -// BufferedOutputStream bos = new BufferedOutputStream(fos); -// InputStream hdi = hashDataInput.getHashDataInput(); -// int b; -// while ((b = hdi.read()) != -1) { -// bos.write(b); -// } -// bos.flush(); -// bos.close(); -// } catch (IOException ex) { -// log.error("Failed to write " + file + ": " + ex.getMessage()); -// showErrorDialog(ERR_WRITE_HASHDATA, new Object[] {ex.getMessage()}, null, null); -// ex.printStackTrace(); -// } finally { -// try { -// fos.close(); -// } catch (IOException ex) { -// } -// } -// } -// break; -// case JFileChooser.CANCEL_OPTION : -// log.debug("cancelled save dialog"); -// break; -// } -// if (okListener != null) { -// okListener.actionPerformed(new ActionEvent(fileDialog, ActionEvent.ACTION_PERFORMED, okCommand)); -// } -// } -// }); -// } + private class SignedReferencesMouseMotionListener extends MouseMotionAdapter { + + JTable hashDataTable; + + public SignedReferencesMouseMotionListener(JTable table) { + this.hashDataTable = table; + } + + @Override + public void mouseMoved(MouseEvent e) { +// if (hashDataTable.columnAtPoint(e.getPoint()) == 0) { + hashDataTable.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } + } + + /////////// + // SignedReferencesList (TODO pull out) + + public class SignedReferencesSelectionListener implements ListSelectionListener { + + List signedReferences; + ActionListener backListener; + String backCommand; + + public SignedReferencesSelectionListener(List signedReferences, ActionListener backListener, String backCommand) { + this.signedReferences = signedReferences; + this.backListener = backListener; + this.backCommand = backCommand; + } + + @Override + public void valueChanged(ListSelectionEvent event) { + + if (event.getValueIsAdjusting()) { + return; + } + + ListSelectionModel lsm = (ListSelectionModel) event.getSource(); + int selectionIdx = lsm.getMinSelectionIndex(); + + log.debug("[" + Thread.currentThread().getName() + "] reference " + selectionIdx + " selected"); + + if (selectionIdx >= 0) { + final HashDataInput selection = signedReferences.get(selectionIdx); + final SignedReferencesListDisplayer backToListListener = new SignedReferencesListDisplayer(signedReferences, backListener, backCommand); + + if (SecureViewerDialog.SUPPORTED_MIME_TYPES.contains(selection.getMimeType())) { + log.debug("[" + Thread.currentThread().getName() + "] scheduling secure viewer dialog"); + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + try { + showMessageDialog(TITLE_HASHDATA, MESSAGE_HASHDATA_VIEWER); + showSecureViewer(selection, backToListListener, null); +// SecureViewerDialog.showSecureViewer(selection, messages, fontProvider, helpMouseListener.getActionListener(), false); + } catch (FontProviderException ex) { + log.error("failed to display secure viewer", ex); + showErrorDialog(BKUGUIFacade.ERR_VIEWER, new Object[] {ex.getMessage()}, backToListListener, null); + } + + } + }); + } else { + log.debug("[" + Thread.currentThread().getName() + "] mime-type not supported by secure viewer, scheduling save dialog"); + showMessageDialog(BKUGUIFacade.TITLE_HASHDATA, BKUGUIFacade.MESSAGE_UNSUPPORTED_MIMETYPE); + SecureViewerSaveDialog.showSaveDialog(selection, messages, backToListListener, null); + } + } + } + + /** + * ActionListener that returns to signed references list + */ + private class SignedReferencesListDisplayer implements ActionListener { + List sr; + ActionListener bl; + String bc; + + public SignedReferencesListDisplayer(List signedReferences, ActionListener backListener, String backCommand) { + sr = signedReferences; + bl = backListener; + bc = backCommand; + } + + @Override + public void actionPerformed(ActionEvent e) { +// log.debug("[" + Thread.currentThread().getName() + "] displaying signed references list"); + showSignedReferencesListDialog(sr, bl, bc); + } + } + } + //////////////////////////////////////////////////////////////////////////// // UTILITY METHODS diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/MimeFilter.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/MimeFilter.java deleted file mode 100644 index 4b48081a..00000000 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/MimeFilter.java +++ /dev/null @@ -1,110 +0,0 @@ -/* -* Copyright 2008 Federal Chancellery Austria and -* Graz University of Technology -* -* 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 at.gv.egiz.bku.gui; - -import java.io.File; -import java.util.ResourceBundle; -import javax.swing.filechooser.FileFilter; - -/** - * - * @author clemens - */ -class MimeFilter extends FileFilter { - - private static final String MIMETYPE_DESC_XML = "mimetype.desc.xml"; - private static final String MIMETYPE_DESC_HTML = "mimetype.desc.html"; - private static final String MIMETYPE_DESC_XHTML = "mimetype.desc.xhtml"; - private static final String MIMETYPE_DESC_TXT = "mimetype.desc.txt"; - private static final String MIMETYPE_DESC_PDF = "mimetype.desc.pdf"; - private static final String MIMETYPE_DESC_BIN = "mimetype.desc.bin"; - - protected String mimeType; - protected ResourceBundle messages; - - public MimeFilter(String mimeType, ResourceBundle messages) { - this.mimeType = mimeType; - this.messages = messages; - } - - @Override - public boolean accept(File f) { - - if (f.isDirectory()) { - return true; - } - - String ext = getExtension(f); - if ("text/xml".equals(mimeType)) { - return "xml".equalsIgnoreCase(ext); - } else if ("text/html".equals(mimeType)) { - return "html".equalsIgnoreCase(ext) || "htm".equalsIgnoreCase(ext); - } else if ("application/xhtml+xml".equals(mimeType)) { - return "xhtml".equalsIgnoreCase(ext); - } else if ("text/plain".equals(mimeType)) { - return "txt".equalsIgnoreCase(ext); - } else if ("application/pdf".equals(mimeType)) { - return "pdf".equalsIgnoreCase(ext); - } else { - return true; - } - } - - private String getExtension(File f) { - String ext = null; - String s = f.getName(); - int i = s.lastIndexOf('.'); - - if (i > 0 && i < s.length() - 1) { - ext = s.substring(i + 1).toLowerCase(); - } - return ext; - } - - @Override - public String getDescription() { - if ("text/xml".equals(mimeType)) { - return messages.getString(MIMETYPE_DESC_XML); - } else if ("text/html".equals(mimeType)) { - return messages.getString(MIMETYPE_DESC_HTML); - } else if ("application/xhtml+xml".equals(mimeType)) { - return messages.getString(MIMETYPE_DESC_XHTML); - } else if ("text/plain".equals(mimeType)) { - return messages.getString(MIMETYPE_DESC_TXT); - } else if ("application/pdf".equals(mimeType)) { - return messages.getString(MIMETYPE_DESC_PDF); - } else { - return messages.getString(MIMETYPE_DESC_BIN); - } - } - - public static String getExtension(String mimeType) { - if ("text/xml".equals(mimeType)) { - return ".xml"; - } else if ("text/html".equals(mimeType)) { - return ".html"; - } else if ("application/xhtml+xml".equals(mimeType)) { - return ".xhtml"; - } else if ("text/plain".equals(mimeType)) { - return ".txt"; - } else if ("application/pdf".equals(mimeType)) { - return ".pdf"; - } else { - return ".bin"; - } - } -} \ No newline at end of file diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java index 878a998b..7bae4673 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java @@ -17,12 +17,15 @@ package at.gv.egiz.bku.gui; import at.gv.egiz.bku.gui.viewer.FontProvider; +import at.gv.egiz.bku.gui.viewer.FontProviderException; +import at.gv.egiz.bku.gui.viewer.SecureViewerSaveDialog; import at.gv.egiz.stal.HashDataInput; import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Font; import java.awt.Frame; +import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; @@ -41,6 +44,9 @@ import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.Charset; import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; import java.util.ResourceBundle; import javax.swing.GroupLayout; import javax.swing.ImageIcon; @@ -72,6 +78,12 @@ public class SecureViewerDialog extends JDialog implements ActionListener { * BKUViewer has compile dependency BKUFonts, transitive in BKUOnline and BKULocal */ public static final Dimension VIEWER_DIMENSION = new Dimension(600, 400); + + public static final List SUPPORTED_MIME_TYPES = new ArrayList(); + static { + SUPPORTED_MIME_TYPES.add("text/plain"); + SUPPORTED_MIME_TYPES.add("application/xhtml+xml"); + } protected static final Log log = LogFactory.getLog(SecureViewerDialog.class); // private static SecureViewerDialog dialog; protected ResourceBundle messages; @@ -102,7 +114,7 @@ public class SecureViewerDialog extends JDialog implements ActionListener { // dialog.setVisible(true); // } public SecureViewerDialog(Frame owner, ResourceBundle messages, - // ActionListener saveListener, String saveCommand, + ActionListener closeListener, String closeCommand, FontProvider fontProvider, ActionListener helpListener) { super(owner, messages.getString(BKUGUIFacade.WINDOWTITLE_VIEWER), true); this.setIconImages(BKUIcons.icons); @@ -111,7 +123,7 @@ public class SecureViewerDialog extends JDialog implements ActionListener { initContentPane(VIEWER_DIMENSION, createViewerPanel(helpListener), - createButtonPanel()); //saveListener, saveCommand)); + createButtonPanel(closeListener, closeCommand)); pack(); if (owner != null) { @@ -289,15 +301,22 @@ public class SecureViewerDialog extends JDialog implements ActionListener { toFront(); } - private JPanel createButtonPanel() { //ActionListener saveListener, String saveCommand) { + private JPanel createButtonPanel(ActionListener closeListener, String closeCommand) { JButton closeButton = new JButton(); closeButton.setText(messages.getString(BKUGUIFacade.BUTTON_CLOSE)); - closeButton.setActionCommand("close"); - closeButton.addActionListener(this); + closeButton.setActionCommand(closeCommand); + closeButton.addActionListener(closeListener); + closeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + log.trace("[" + Thread.currentThread().getName() + "] closing secure viewer"); + setVisible(false); + } + }); JButton saveButton = new JButton(); saveButton.setText(messages.getString(BKUGUIFacade.BUTTON_SAVE)); - saveButton.setActionCommand("save"); + saveButton.setActionCommand("save"); //TODO ensure unequal to closeCommand saveButton.addActionListener(this); int buttonSize = closeButton.getPreferredSize().width; @@ -319,100 +338,37 @@ public class SecureViewerDialog extends JDialog implements ActionListener { @Override public void actionPerformed(ActionEvent e) { - if ("close".equals(e.getActionCommand())) { - log.trace("[" + Thread.currentThread().getName() + "] closing secure viewer"); - setVisible(false); - log.trace("secure viewer closed"); - } else if ("save".equals(e.getActionCommand())) { + if ("save".equals(e.getActionCommand())) { log.trace("[" + Thread.currentThread().getName() + "] display secure viewer save dialog"); - showSaveDialog(content, null, null); + SecureViewerSaveDialog.showSaveDialog(content, messages, null, null); log.trace("done secure viewer save"); } else { log.warn("unknown action command " + e.getActionCommand()); } } + + +// //TEST +// private static SecureViewerDialog secureViewer; +// public static void showSecureViewerXXX(HashDataInput dataToBeSigned, ResourceBundle messages, FontProvider fontProvider, ActionListener helpListener, boolean alwaysOnTop) throws FontProviderException { +// +//// ResourceBundle messages = ResourceBundle.getBundle(BKUGUIFacade.MESSAGES_BUNDLE, locale); +// +// log.debug("[" + Thread.currentThread().getName() + "] show secure viewer"); +// if (secureViewer == null) { +// secureViewer = new SecureViewerDialog(null, messages, +// fontProvider, helpListener); +// +// // workaround for [#439] +// // avoid AlwaysOnTop at least in applet, otherwise make secureViewer AlwaysOnTop since MOCCA Dialog (JFrame created in LocalSTALFactory) is always on top. +//// Window window = SwingUtilities.getWindowAncestor(contentPane); +//// if (window != null && window.isAlwaysOnTop()) { +//// log.debug("make secureViewer alwaysOnTop"); +// secureViewer.setAlwaysOnTop(alwaysOnTop); +//// } +// } +// secureViewer.setContent(dataToBeSigned); +// log.trace("show secure viewer returned"); +// } - private void showSaveDialog(final HashDataInput hashDataInput, - final ActionListener okListener, final String okCommand) { - - log.debug("[" + Thread.currentThread().getName() + "] scheduling save dialog"); - - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { - - log.debug("[" + Thread.currentThread().getName() + "] show save dialog"); - - String userHome = System.getProperty("user.home"); - - JFileChooser fileDialog = new JFileChooser(userHome); - fileDialog.setMultiSelectionEnabled(false); - fileDialog.setDialogType(JFileChooser.SAVE_DIALOG); - fileDialog.setFileHidingEnabled(true); - fileDialog.setDialogTitle(messages.getString(BKUGUIFacade.WINDOWTITLE_SAVE)); - fileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY); - String mimeType = hashDataInput.getMimeType(); - MimeFilter mimeFilter = new MimeFilter(mimeType, messages); - fileDialog.setFileFilter(mimeFilter); - String filename = messages.getString(BKUGUIFacade.SAVE_HASHDATAINPUT_PREFIX) + - MimeFilter.getExtension(mimeType); - fileDialog.setSelectedFile(new File(userHome, filename)); - - //parent contentPane -> placed over applet - switch (fileDialog.showSaveDialog(fileDialog)) { - case JFileChooser.APPROVE_OPTION: - File file = fileDialog.getSelectedFile(); - String id = hashDataInput.getReferenceId(); - if (file.exists()) { - String msgPattern = messages.getString(BKUGUIFacade.MESSAGE_OVERWRITE); - int overwrite = JOptionPane.showConfirmDialog(fileDialog, - MessageFormat.format(msgPattern, file), - messages.getString(BKUGUIFacade.WINDOWTITLE_OVERWRITE), - JOptionPane.OK_CANCEL_OPTION); - if (overwrite != JOptionPane.OK_OPTION) { - return; - } - } - if (log.isDebugEnabled()) { - log.debug("writing hashdata input " + id + " (" + mimeType + ") to file " + file); - } - FileOutputStream fos = null; - try { - fos = new FileOutputStream(file); - BufferedOutputStream bos = new BufferedOutputStream(fos); - InputStream hdi = hashDataInput.getHashDataInput(); - int b; - while ((b = hdi.read()) != -1) { - bos.write(b); - } - bos.flush(); - bos.close(); - } catch (IOException ex) { - log.error("Failed to write " + file + ": " + ex.getMessage()); - log.debug(ex); - String errPattern = messages.getString(BKUGUIFacade.ERR_WRITE_HASHDATA); - JOptionPane.showMessageDialog(fileDialog, - MessageFormat.format(errPattern, ex.getMessage()), - messages.getString(BKUGUIFacade.WINDOWTITLE_ERROR), - JOptionPane.ERROR_MESSAGE); - } finally { - try { - if (fos != null) { - fos.close(); - } - } catch (IOException ex) { - } - } - break; - case JFileChooser.CANCEL_OPTION: - log.debug("cancelled save dialog"); - break; - } - if (okListener != null) { - okListener.actionPerformed(new ActionEvent(fileDialog, ActionEvent.ACTION_PERFORMED, okCommand)); - } - } - }); - } } diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeFilter.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeFilter.java new file mode 100644 index 00000000..c0385dce --- /dev/null +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeFilter.java @@ -0,0 +1,115 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.bku.gui.viewer; + +import java.io.File; +import java.util.ResourceBundle; +import javax.swing.filechooser.FileFilter; + +/** + * + * @author clemens + */ +class MimeFilter extends FileFilter { + + private static final String MIMETYPE_DESC_XML = "mimetype.desc.xml"; + private static final String MIMETYPE_DESC_HTML = "mimetype.desc.html"; + private static final String MIMETYPE_DESC_XHTML = "mimetype.desc.xhtml"; + private static final String MIMETYPE_DESC_TXT = "mimetype.desc.txt"; + private static final String MIMETYPE_DESC_PDF = "mimetype.desc.pdf"; + private static final String MIMETYPE_DESC_BIN = "mimetype.desc.bin"; + private static final String MIMETYPE_DESC_UNKNOWN = "mimetype.desc.unknown"; + + protected String mimeType; + protected ResourceBundle messages; + + public MimeFilter(String mimeType, ResourceBundle messages) { + this.mimeType = mimeType; + this.messages = messages; + } + + @Override + public boolean accept(File f) { + + if (f.isDirectory()) { + return true; + } + + String ext = getExtension(f); + if ("text/xml".equals(mimeType)) { + return "xml".equalsIgnoreCase(ext); + } else if ("text/html".equals(mimeType)) { + return "html".equalsIgnoreCase(ext) || "htm".equalsIgnoreCase(ext); + } else if ("application/xhtml+xml".equals(mimeType)) { + return "xhtml".equalsIgnoreCase(ext); + } else if ("text/plain".equals(mimeType)) { + return "txt".equalsIgnoreCase(ext); + } else if ("application/pdf".equals(mimeType)) { + return "pdf".equalsIgnoreCase(ext); + } else { + return true; + } + } + + private String getExtension(File f) { + String ext = null; + String s = f.getName(); + int i = s.lastIndexOf('.'); + + if (i > 0 && i < s.length() - 1) { + ext = s.substring(i + 1).toLowerCase(); + } + return ext; + } + + @Override + public String getDescription() { + if ("text/xml".equals(mimeType)) { + return messages.getString(MIMETYPE_DESC_XML); + } else if ("text/html".equals(mimeType)) { + return messages.getString(MIMETYPE_DESC_HTML); + } else if ("application/xhtml+xml".equals(mimeType)) { + return messages.getString(MIMETYPE_DESC_XHTML); + } else if ("text/plain".equals(mimeType)) { + return messages.getString(MIMETYPE_DESC_TXT); + } else if ("application/pdf".equals(mimeType)) { + return messages.getString(MIMETYPE_DESC_PDF); + } else if ("application/octet-stream".equals(mimeType)) { + return messages.getString(MIMETYPE_DESC_BIN); + } else { + return messages.getString(MIMETYPE_DESC_UNKNOWN); + } + } + + public static String getExtension(String mimeType) { + if ("text/xml".equals(mimeType)) { + return ".xml"; + } else if ("text/html".equals(mimeType)) { + return ".html"; + } else if ("application/xhtml+xml".equals(mimeType)) { + return ".xhtml"; + } else if ("text/plain".equals(mimeType)) { + return ".txt"; + } else if ("application/pdf".equals(mimeType)) { + return ".pdf"; + } else if ("application/octet-stream".equals(mimeType)) { + return ".bin"; + } else { + return ""; + } + } +} \ No newline at end of file diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewerSaveDialog.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewerSaveDialog.java new file mode 100644 index 00000000..40133f95 --- /dev/null +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewerSaveDialog.java @@ -0,0 +1,120 @@ +package at.gv.egiz.bku.gui.viewer; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.MessageFormat; +import java.util.Locale; +import java.util.ResourceBundle; + +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.bku.gui.BKUGUIFacade; +import at.gv.egiz.stal.HashDataInput; + +public class SecureViewerSaveDialog { + + protected static final Log log = LogFactory.getLog(SecureViewerSaveDialog.class); + + public static void showSaveDialog(final HashDataInput hashDataInput, final ResourceBundle messages, + final ActionListener okListener, final String okCommand) { + + log.debug("[" + Thread.currentThread().getName() + + "] scheduling save dialog"); + + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + + log + .debug("[" + Thread.currentThread().getName() + + "] show save dialog"); + + String userHome = System.getProperty("user.home"); + + JFileChooser fileDialog = new JFileChooser(userHome); + fileDialog.setMultiSelectionEnabled(false); + fileDialog.setDialogType(JFileChooser.SAVE_DIALOG); + fileDialog.setFileHidingEnabled(true); + fileDialog.setDialogTitle(messages + .getString(BKUGUIFacade.WINDOWTITLE_SAVE)); + fileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY); + String mimeType = hashDataInput.getMimeType(); + MimeFilter mimeFilter = new MimeFilter(mimeType, messages); + fileDialog.setFileFilter(mimeFilter); + String filename = messages + .getString(BKUGUIFacade.SAVE_HASHDATAINPUT_PREFIX) + + MimeFilter.getExtension(mimeType); + fileDialog.setSelectedFile(new File(userHome, filename)); + + // parent contentPane -> placed over applet + switch (fileDialog.showSaveDialog(fileDialog)) { + case JFileChooser.APPROVE_OPTION: + File file = fileDialog.getSelectedFile(); + String id = hashDataInput.getReferenceId(); + if (file.exists()) { + String msgPattern = messages + .getString(BKUGUIFacade.MESSAGE_OVERWRITE); + int overwrite = JOptionPane.showConfirmDialog(fileDialog, + MessageFormat.format(msgPattern, file), messages + .getString(BKUGUIFacade.WINDOWTITLE_OVERWRITE), + JOptionPane.OK_CANCEL_OPTION); + if (overwrite != JOptionPane.OK_OPTION) { + break; + } + } + if (log.isDebugEnabled()) { + log.debug("writing hashdata input " + id + " (" + mimeType + + ") to file " + file); + } + FileOutputStream fos = null; + try { + fos = new FileOutputStream(file); + BufferedOutputStream bos = new BufferedOutputStream(fos); + InputStream hdi = hashDataInput.getHashDataInput(); + int b; + while ((b = hdi.read()) != -1) { + bos.write(b); + } + bos.flush(); + bos.close(); + } catch (IOException ex) { + log.error("Failed to write " + file + ": " + ex.getMessage()); + log.debug(ex); + String errPattern = messages + .getString(BKUGUIFacade.ERR_WRITE_HASHDATA); + JOptionPane.showMessageDialog(fileDialog, MessageFormat.format( + errPattern, ex.getMessage()), messages + .getString(BKUGUIFacade.WINDOWTITLE_ERROR), + JOptionPane.ERROR_MESSAGE); + } finally { + try { + if (fos != null) { + fos.close(); + } + } catch (IOException ex) { + } + } + break; + case JFileChooser.CANCEL_OPTION: + log.debug("cancelled save dialog"); + break; + } + if (okListener != null) { + okListener.actionPerformed(new ActionEvent(fileDialog, + ActionEvent.ACTION_PERFORMED, okCommand)); + } + } + }); + } +} diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties index b458a214..7135b561 100644 --- a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties @@ -20,6 +20,7 @@ title.cardnotsupported=Die Karte wird nicht unterst\u00FCtzt title.cardpin=Karte wird gelesen title.sign=Signatur erstellen title.error=Fehler +title.warning=Achtung title.entry.timeout=Zeit\u00FCberschreitung title.retry=Falsche PIN title.wait=Bitte warten @@ -46,6 +47,8 @@ hashdatalink.tiny.focus=[Signaturdaten] #message.hashdata=Dies ist eine Voransicht des zu signierenden Inhaltes. F\u00FCr Details siehe Hilfe (i). #verwenden sie bitte die von ihrem System zur Verf\u00FCgung gestellte {0} Anwendung. hashdatalist={0} Signaturdaten: +hashdata.viewer=Signaturdaten werden im Betrachter angezeigt +unsupported.mimetype=Signaturdaten können nicht angezeigt werden retries.last=Letzter Versuch! retries=Noch {0} Versuche retries.pinpad.last=Eingabe wiederholen, letzter Versuch! @@ -68,6 +71,7 @@ mimetype.desc.xhtml=XHTML-Dateien (.xhtml) mimetype.desc.txt=Textdateien (.txt) mimetype.desc.pdf=Adobe PDF-Dateien (.pdf) mimetype.desc.bin=Bin\u00E4rdateien (.bin) +mimetype.desc.unknown=Alle Dateien (.*) save.hashdatainput.prefix=Signaturdaten alt.help=Hilfe diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties index 109b4faa..6e89510e 100644 --- a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties @@ -54,7 +54,7 @@ retries.pinpad=Re-enter pin, {0} tries left overwrite=Overwrite {0}? help=Help topic {0} -warning.xhtml=Remark: This is a preview of the data to-be signed. For standards compliant display see help. +warning.xhtml=Remark: This is a preview of the data to-be signed. For standard-compliant display see help. label.pin={0}: label.pinsize=({0} digits) button.ok=OK diff --git a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/SecureViewerDialogTest.java b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/SecureViewerDialogTest.java index fc8dcd96..131a344f 100644 --- a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/SecureViewerDialogTest.java +++ b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/SecureViewerDialogTest.java @@ -7,6 +7,8 @@ package at.gv.egiz.bku.gui; import at.gv.egiz.stal.impl.ByteArrayHashDataInput; import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -33,7 +35,7 @@ public class SecureViewerDialogTest { @BeforeClass public static void setUpClass() throws Exception { messages = ResourceBundle.getBundle("at/gv/egiz/bku/gui/Messages"); - secureViewer = new SecureViewerDialog(null, messages, new DummyFontLoader(), null); + secureViewer = new SecureViewerDialog(null, messages,null, null, new DummyFontLoader(), null); } @AfterClass diff --git a/BKUHelp/src/main/webapp/help/de/help.unsupported.mimetype.html b/BKUHelp/src/main/webapp/help/de/help.unsupported.mimetype.html new file mode 100644 index 00000000..09440dc2 --- /dev/null +++ b/BKUHelp/src/main/webapp/help/de/help.unsupported.mimetype.html @@ -0,0 +1,41 @@ + + + + +Bürgerkarte - Hilfe + + + + + + + +
+ +
+

Bildschirmfoto des Applets

+

Hinweis: Das Bildschirmfoto oben kann von der Darstellung in der Webseite abweichen.

+
+
+

Signaturdaten können nicht dargestellt werden

+

Die Signaturdatenanzeige unterstützt reine Textdaten sowie XHTML, andere MIME-Typen können nicht angezeigt werden. + Um die Daten standardkonform darzustellen, müssen diese abgespeichert und mit einem geeigneten externen Betrachter geöffnen werden.

+


+
+ +
+ + diff --git a/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALServiceImpl.java b/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALServiceImpl.java index 08b4d7de..2ca108e0 100644 --- a/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALServiceImpl.java +++ b/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALServiceImpl.java @@ -37,12 +37,16 @@ import at.gv.egiz.stal.service.types.QuitRequestType; import at.gv.egiz.stal.service.types.RequestType; import at.gv.egiz.stal.service.types.ResponseType; import at.gv.egiz.stal.service.types.SignRequestType; +import at.gv.egiz.stal.service.types.GetHashDataInputType.Reference; +//import at.gv.egiz.stal.service.types.GetHashDataInputResponseType.Reference; + import com.sun.xml.ws.developer.UsesJAXBContext; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import javax.annotation.Resource; @@ -204,113 +208,97 @@ public class STALServiceImpl implements STALPortType { log.debug("Received GetHashDataInputRequest for session " + sessionId + " containing " + request.getReference().size() + " reference(s)"); } + if (TEST_SESSION_ID.equals(sessionId)) { + return getTestSessionHashDataInputResponse(request.getReference()); + } + GetHashDataInputResponseType response = new GetHashDataInputResponseType(); response.setSessionId(sessionId.toString()); - if (TEST_SESSION_ID.equals(sessionId)) { - log.debug("Received GetHashDataInput for session " + TEST_SESSION_ID + ", return DummyHashDataInput"); - GetHashDataInputResponseType.Reference ref = new GetHashDataInputResponseType.Reference(); - ref.setID("signed-data-reference-0-1214921968-27971781-24309"); //Reference-" + TEST_SESSION_ID + "-001"); - ref.setMimeType("text/plain"); - - Charset charset; - try { - charset = Charset.forName("iso-8859-15"); - ref.setEncoding("iso-8859-15"); - } catch (Exception ex) { - log.warn(ex.getMessage()); - charset = Charset.defaultCharset(); - ref.setEncoding(charset.toString()); - } - ref.setValue("hashdatainput-öäüß@€-00000000001".getBytes(charset)); - response.getReference().add(ref); - return response; - } else { - STALRequestBroker stal = getStal(sessionId); + STALRequestBroker stal = getStal(sessionId); - if (stal != null) { - List hashDataInputs = stal.getHashDataInput(); + if (stal != null) { + List hashDataInputs = stal.getHashDataInput(); - if (hashDataInputs != null) { + if (hashDataInputs != null) { - Map hashDataIdMap = new HashMap(); - for (HashDataInput hdi : hashDataInputs) { - if (log.isTraceEnabled()) { - log.trace("Provided HashDataInput for reference " + hdi.getReferenceId()); - } - hashDataIdMap.put(hdi.getReferenceId(), hdi); + Map hashDataIdMap = new HashMap(); + for (HashDataInput hdi : hashDataInputs) { + if (log.isTraceEnabled()) { + log.trace("Provided HashDataInput for reference " + hdi.getReferenceId()); } + hashDataIdMap.put(hdi.getReferenceId(), hdi); + } - List reqRefs = request.getReference(); - for (GetHashDataInputType.Reference reqRef : reqRefs) { - String reqRefId = reqRef.getID(); - HashDataInput reqHdi = hashDataIdMap.get(reqRefId); - if (reqHdi == null) { - String msg = "Failed to resolve HashDataInput for reference " + reqRefId; - log.error(msg); - GetHashDataInputFaultType faultInfo = new GetHashDataInputFaultType(); - faultInfo.setErrorCode(1); - faultInfo.setErrorMessage(msg); - throw new GetHashDataInputFault(msg, faultInfo); - } + List reqRefs = request.getReference(); + for (GetHashDataInputType.Reference reqRef : reqRefs) { + String reqRefId = reqRef.getID(); + HashDataInput reqHdi = hashDataIdMap.get(reqRefId); + if (reqHdi == null) { + String msg = "Failed to resolve HashDataInput for reference " + reqRefId; + log.error(msg); + GetHashDataInputFaultType faultInfo = new GetHashDataInputFaultType(); + faultInfo.setErrorCode(1); + faultInfo.setErrorMessage(msg); + throw new GetHashDataInputFault(msg, faultInfo); + } - InputStream hashDataIS = reqHdi.getHashDataInput(); - if (hashDataIS == null) { - //HashDataInput not cached? - String msg = "Failed to obtain HashDataInput for reference " + reqRefId + ", reference not cached"; - log.error(msg); - GetHashDataInputFaultType faultInfo = new GetHashDataInputFaultType(); - faultInfo.setErrorCode(1); - faultInfo.setErrorMessage(msg); - throw new GetHashDataInputFault(msg, faultInfo); + InputStream hashDataIS = reqHdi.getHashDataInput(); + if (hashDataIS == null) { + //HashDataInput not cached? + String msg = "Failed to obtain HashDataInput for reference " + reqRefId + ", reference not cached"; + log.error(msg); + GetHashDataInputFaultType faultInfo = new GetHashDataInputFaultType(); + faultInfo.setErrorCode(1); + faultInfo.setErrorMessage(msg); + throw new GetHashDataInputFault(msg, faultInfo); + } + ByteArrayOutputStream baos = null; + try { + if (log.isDebugEnabled()) { + log.debug("Resolved HashDataInput " + reqRefId + " (" + reqHdi.getMimeType() + ";charset=" + reqHdi.getEncoding() + ")"); + } + baos = new ByteArrayOutputStream(hashDataIS.available()); + int c; + while ((c = hashDataIS.read()) != -1) { + baos.write(c); } - ByteArrayOutputStream baos = null; + GetHashDataInputResponseType.Reference ref = new GetHashDataInputResponseType.Reference(); + ref.setID(reqRefId); + ref.setMimeType(reqHdi.getMimeType()); + ref.setEncoding(reqHdi.getEncoding()); + ref.setValue(baos.toByteArray()); + response.getReference().add(ref); + } catch (IOException ex) { + String msg = "Failed to get HashDataInput for reference " + reqRefId; + log.error(msg, ex); + GetHashDataInputFaultType faultInfo = new GetHashDataInputFaultType(); + faultInfo.setErrorCode(1); + faultInfo.setErrorMessage(msg); + throw new GetHashDataInputFault(msg, faultInfo, ex); + } finally { try { - if (log.isDebugEnabled()) { - log.debug("Resolved HashDataInput " + reqRefId + " (" + reqHdi.getMimeType() + ";charset=" + reqHdi.getEncoding() + ")"); - } - baos = new ByteArrayOutputStream(hashDataIS.available()); - int c; - while ((c = hashDataIS.read()) != -1) { - baos.write(c); - } - GetHashDataInputResponseType.Reference ref = new GetHashDataInputResponseType.Reference(); - ref.setID(reqRefId); - ref.setMimeType(reqHdi.getMimeType()); - ref.setEncoding(reqHdi.getEncoding()); - ref.setValue(baos.toByteArray()); - response.getReference().add(ref); + baos.close(); } catch (IOException ex) { - String msg = "Failed to get HashDataInput for reference " + reqRefId; - log.error(msg, ex); - GetHashDataInputFaultType faultInfo = new GetHashDataInputFaultType(); - faultInfo.setErrorCode(1); - faultInfo.setErrorMessage(msg); - throw new GetHashDataInputFault(msg, faultInfo, ex); - } finally { - try { - baos.close(); - } catch (IOException ex) { - } } } - return response; - } else { - String msg = "Failed to resolve any HashDataInputs for session " + sessionId; - log.error(msg); - GetHashDataInputFaultType faultInfo = new GetHashDataInputFaultType(); - faultInfo.setErrorCode(1); - faultInfo.setErrorMessage(msg); - throw new GetHashDataInputFault(msg, faultInfo); } + return response; } else { - String msg = "Session timeout"; //Failed to get STAL for session " + sessionId; - log.error(msg + " " + sessionId); + String msg = "Failed to resolve any HashDataInputs for session " + sessionId; + log.error(msg); GetHashDataInputFaultType faultInfo = new GetHashDataInputFaultType(); faultInfo.setErrorCode(1); faultInfo.setErrorMessage(msg); throw new GetHashDataInputFault(msg, faultInfo); } + } else { + String msg = "Session timeout"; //Failed to get STAL for session " + sessionId; + log.error(msg + " " + sessionId); + GetHashDataInputFaultType faultInfo = new GetHashDataInputFaultType(); + faultInfo.setErrorCode(1); + faultInfo.setErrorMessage(msg); + throw new GetHashDataInputFault(msg, faultInfo); } } @@ -332,45 +320,83 @@ public class STALServiceImpl implements STALPortType { List> reqs = response.getInfoboxReadRequestOrSignRequestOrQuitRequest(); if (responsesIn == null) { - log.info("[TestSession] received CONNECT, return dummy requests "); -// addDummyRequests(reqs); - ScriptType scriptT = ccObjFactory.createScriptType(); - CommandAPDUType cmd = ccObjFactory.createCommandAPDUType(); - cmd.setValue("TestSession CardChannelCMD 1234".getBytes()); - scriptT.getResetOrCommandAPDUOrVerifyAPDU().add(cmd); - reqs.add(ccObjFactory.createScript(scriptT)); + log.info("[TestSession] CONNECT"); +// addTestCardChannelRequest(reqs); +// addTestInfoboxReadRequest("IdentityLink", reqs); +// addTestInfoboxReadRequest("SecureSignatureKeypair", reqs); +// addTestInfoboxReadRequest("CertifiedKeypair", reqs); + addTestSignatureRequests("SecureSignatureKeypair", reqs); } else if (responsesIn != null && responsesIn.size() > 0 && responsesIn.get(0).getValue() instanceof ErrorResponseType) { log.info("[TestSession] received ErrorResponse, return QUIT request"); QuitRequestType quitT = stalObjFactory.createQuitRequestType(); reqs.add(stalObjFactory.createGetNextRequestResponseTypeQuitRequest(quitT)); } else { - log.info("[TestSession] received " + responsesIn.size() + " response(s), return dummy requests" ); - addDummyRequests(reqs); + log.info("[TestSession] received " + responsesIn.size() + " response(s), return QUIT" ); + QuitRequestType quitT = stalObjFactory.createQuitRequestType(); + reqs.add(stalObjFactory.createGetNextRequestResponseTypeQuitRequest(quitT)); + } + return response; + } + + + private GetHashDataInputResponseType getTestSessionHashDataInputResponse(List references) { + log.debug("[TestSession] received GET_HASHDATAINPUT"); + + GetHashDataInputResponseType response = new GetHashDataInputResponseType(); + response.setSessionId(TEST_SESSION_ID.toString()); + + for (Reference reference : references) { + String refId = reference.getID(); + log.debug("[TestSession] adding hashdata input for " + refId); + GetHashDataInputResponseType.Reference ref = new GetHashDataInputResponseType.Reference(); + ref.setID(refId); + ref.setMimeType(TestSignatureData.HASHDATA_MIMETYPES.get(refId)); //todo resolve from TestSignatureData + ref.setValue(TestSignatureData.HASHDATA_INPUT.get(refId)); + ref.setEncoding(TestSignatureData.ENCODING); + response.getReference().add(ref); } +// GetHashDataInputResponseType.Reference ref = new GetHashDataInputResponseType.Reference(); +// ref.setID("signed-data-reference-0-1214921968-27971781-24309"); //Reference-" + TEST_SESSION_ID + "-001"); +// ref.setMimeType("text/plain"); + +// Charset charset; +// try { +// charset = Charset.forName("iso-8859-15"); +// ref.setEncoding("iso-8859-15"); +// } catch (Exception ex) { +// log.warn(ex.getMessage()); +// charset = Charset.defaultCharset(); +// ref.setEncoding(charset.toString()); +// } +// ref.setValue("hashdatainput-öäüß@€-00000000001".getBytes(charset)); + +// ref.setValue("Ich bin ein einfacher Text. llšŠŸ§Û".getBytes()); +// response.getReference().add(ref); return response; } + + private void addTestCardChannelRequest(List> requestList) { + log.info("[TestSession] add CARDCHANNEL request"); + ScriptType scriptT = ccObjFactory.createScriptType(); + CommandAPDUType cmd = ccObjFactory.createCommandAPDUType(); + cmd.setValue("TestSession CardChannelCMD 1234".getBytes()); + scriptT.getResetOrCommandAPDUOrVerifyAPDU().add(cmd); + requestList.add(ccObjFactory.createScript(scriptT)); + } - private void addDummyRequests(List> reqs) { -// log.info("[TestSession] add READ request for Infobox IdentityLink"); -// InfoboxReadRequestType ibrT1 = stalObjFactory.createInfoboxReadRequestType(); -// ibrT1.setInfoboxIdentifier("IdentityLink"); -// reqs.add(stalObjFactory.createGetNextRequestResponseTypeInfoboxReadRequest(ibrT1)); - - log.info("[TestSession] add READ request for Infobox CertifiedKeypair"); - InfoboxReadRequestType ibrT2 = stalObjFactory.createInfoboxReadRequestType(); - ibrT2.setInfoboxIdentifier("CertifiedKeypair"); - reqs.add(stalObjFactory.createGetNextRequestResponseTypeInfoboxReadRequest(ibrT2)); - - log.info("[TestSession] add READ request for Infobox SecureSignatureKeypair"); - InfoboxReadRequestType ibrT3 = stalObjFactory.createInfoboxReadRequestType(); - ibrT3.setInfoboxIdentifier("SecureSignatureKeypair"); - reqs.add(stalObjFactory.createGetNextRequestResponseTypeInfoboxReadRequest(ibrT3)); - - log.info("[TestSession] add SIGN request"); - SignRequestType sigT1 = stalObjFactory.createSignRequestType(); - sigT1.setKeyIdentifier("SecureSignatureKeypair"); - sigT1.setSignedInfo(" id('signed-data-object-0-1214921968-27971781-13578')/node() H1IePEEfGQ2SG03H6LTzw1TpCuM=yV6Q+I60buqR4mMaxA7fi+CV35A=".getBytes()); - reqs.add(stalObjFactory.createGetNextRequestResponseTypeSignRequest(sigT1)); + private void addTestInfoboxReadRequest(String infoboxIdentifier, List> requestList) { + log.info("[TestSession] add READ "+ infoboxIdentifier + " request"); + InfoboxReadRequestType ibrT = stalObjFactory.createInfoboxReadRequestType(); + ibrT.setInfoboxIdentifier(infoboxIdentifier); + requestList.add(stalObjFactory.createGetNextRequestResponseTypeInfoboxReadRequest(ibrT)); + } + + private void addTestSignatureRequests(String keyIdentifier, List> reqs) { + log.info("[TestSession] add SIGN " + keyIdentifier + " request"); + SignRequestType sigT = stalObjFactory.createSignRequestType(); + sigT.setKeyIdentifier(keyIdentifier); + sigT.setSignedInfo(TestSignatureData.SIGNED_INFO.get(1)); //select! + reqs.add(stalObjFactory.createGetNextRequestResponseTypeSignRequest(sigT)); } } diff --git a/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/TestSignatureData.java b/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/TestSignatureData.java new file mode 100644 index 00000000..24771d8f --- /dev/null +++ b/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/TestSignatureData.java @@ -0,0 +1,47 @@ +package at.gv.egiz.stal.service.impl; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public final class TestSignatureData { + + protected final static Log log = LogFactory.getLog(TestSignatureData.class); + + public static final String[] ID = new String[] {"signed-data-reference-0-1214921968-27971781-24309", "signed-data-reference-1"}; + public static final String ENCODING = "UTF-8"; + + public static final Map HASHDATA_INPUT = new HashMap(); + static { + try { + HASHDATA_INPUT.put(ID[0], "Ich bin ein einfacher Text. llšŠŸ§Û".getBytes(ENCODING)); + HASHDATA_INPUT.put(ID[1], "2te referenz".getBytes(ENCODING)); + } catch (UnsupportedEncodingException ex) { + log.error("failed to init signature test data", ex); + } + } + public static final Map HASHDATA_MIMETYPES = new HashMap(); + static { + HASHDATA_MIMETYPES.put(ID[0], "text/plain"); + HASHDATA_MIMETYPES.put(ID[1], "any/mime-type"); + } + +// private static final byte[] signedInfo = " id('signed-data-object-0-1214921968-27971781-13578')/node() H1IePEEfGQ2SG03H6LTzw1TpCuM=yV6Q+I60buqR4mMaxA7fi+CV35A=".getBytes(); +// private static final byte[] signedInfo2Ref = " id('signed-data-object-0-1214921968-27971781-13578')/node() H1IePEEfGQ2SG03H6LTzw1TpCuM= id('signed-data-object-1')/node() H1IePEEfGQ2SG03H6LTzw1TpCuM=yV6Q+I60buqR4mMaxA7fi+CV35A=".getBytes(); +// private static final String signedInfo2Ref = " id('signed-data-object-1')/node() H1IePEEfGQ2SG03H6LTzw1TpCuM="; + /** + * SIGNED_INFO[0] contains reference ID[0] + * SIGNED_INFO[1] contains reference ID[0] and ID[1] + */ + public static final List SIGNED_INFO = new ArrayList(); + static { + SIGNED_INFO.add(" id('signed-data-object-0-1214921968-27971781-13578')/node() H1IePEEfGQ2SG03H6LTzw1TpCuM=yV6Q+I60buqR4mMaxA7fi+CV35A=".getBytes()); + SIGNED_INFO.add(" id('signed-data-object-0-1214921968-27971781-13578')/node() H1IePEEfGQ2SG03H6LTzw1TpCuM= id('signed-data-object-1')/node() H1IePEEfGQ2SG03H6LTzw1TpCuM=yV6Q+I60buqR4mMaxA7fi+CV35A=".getBytes()); + } + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java index 2088a684..89124d16 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java @@ -293,8 +293,7 @@ public class DataObject { } } else { - log.info("MIME media type '" + mediaType + "' is not a valid digest input."); - throw new SLViewerException(5001); + log.debug("MIME media type '" + mediaType + "' is not a s/valid/SUPPORTED digest input, omitting validation."); } } -- cgit v1.2.3 From 5af9b75dccc1b52d1382fe0f2df30affd509f5b9 Mon Sep 17 00:00:00 2001 From: clemenso Date: Tue, 24 Nov 2009 18:48:00 +0000 Subject: Filenames derived from reference URI git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@553 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- .../egiz/bku/online/applet/AppletSecureViewer.java | 3 +- .../java/at/gv/egiz/bku/gui/HyperlinkRenderer.java | 10 ++- .../java/at/gv/egiz/bku/gui/viewer/MimeFilter.java | 56 +------------- .../java/at/gv/egiz/bku/gui/viewer/MimeTypes.java | 53 +++++++++++++ .../bku/gui/viewer/SecureViewerSaveDialog.java | 5 +- .../gv/egiz/stal/impl/ByteArrayHashDataInput.java | 9 ++- .../at/gv/egiz/bku/gui/Messages.properties | 3 +- .../at/gv/egiz/bku/gui/Messages_en.properties | 1 + .../test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java | 12 ++- .../at/gv/egiz/bku/gui/SecureViewerDialogTest.java | 6 +- BKUOnline/pom.xml | 2 +- .../gv/egiz/stal/service/impl/STALServiceImpl.java | 1 + BKUOnline/src/main/webapp/META-INF/context.xml | 2 +- BKUOnline/src/main/webapp/WEB-INF/wsdl/stal.xsd | 1 + BKUOnline/src/main/wsdl/stal-service.xsd | 1 + .../egiz/stal/service/STALRequestBrokerTest.java | 21 ++++++ .../main/java/at/gv/egiz/stal/HashDataInput.java | 2 + .../types/GetHashDataInputResponseType.java | 28 +++++++ .../gv/egiz/bku/binding/HTTPBindingProcessor.java | 1 + .../slcommands/impl/DataObjectHashDataInput.java | 6 ++ .../egiz/bku/slcommands/impl/xsect/DataObject.java | 88 ++++++++++++++++++++-- .../bku/slcommands/impl/xsect/SignatureTest.java | 50 +++++++++++- .../impl/DataObjectInfo_Detached_LocRefContent.xml | 13 ++++ .../impl/DataObjectInfo_LocRefContent_2.xml | 2 +- .../at/gv/egiz/slbinding/RedirectEventFilter.java | 3 - .../gv/egiz/slbinding/impl/TransformsInfoType.java | 8 ++ .../at/gv/egiz/slbinding/impl/XMLContentType.java | 9 +++ 27 files changed, 313 insertions(+), 83 deletions(-) create mode 100644 BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeTypes.java create mode 100644 bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/impl/DataObjectInfo_Detached_LocRefContent.xml (limited to 'bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java') diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java index 2e0cb331..c67699af 100644 --- a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java +++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java @@ -180,6 +180,7 @@ public class AppletSecureViewer implements SecureViewer { byte[] hdi = hashDataInput.getValue(); String mimeType = hashDataInput.getMimeType(); String encoding = hashDataInput.getEncoding(); + String filename = hashDataInput.getFilename(); if (hdi == null) { throw new Exception("No hashdata input for reference " + signedRefId + " provided by service"); @@ -199,7 +200,7 @@ public class AppletSecureViewer implements SecureViewer { throw new DigestException("Bad digest value for reference " + signedRefId); } - verifiedHashDataInputs.add(new ByteArrayHashDataInput(hdi, signedRefId, mimeType, encoding)); + verifiedHashDataInputs.add(new ByteArrayHashDataInput(hdi, signedRefId, mimeType, encoding, filename)); } } diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HyperlinkRenderer.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HyperlinkRenderer.java index 16024fcc..6af22815 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HyperlinkRenderer.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HyperlinkRenderer.java @@ -39,10 +39,14 @@ public class HyperlinkRenderer extends DefaultTableCellRenderer { @Override protected void setValue(Object value) { String hrefText; - if (renderReferenceId) { - hrefText = ((HashDataInput) value).getReferenceId(); + if (((HashDataInput) value).getFilename() != null) { + hrefText = ((HashDataInput) value).getFilename(); } else { - hrefText = ((HashDataInput) value).getMimeType(); + if (renderReferenceId) { + hrefText = ((HashDataInput) value).getReferenceId(); + } else { + hrefText = ((HashDataInput) value).getMimeType(); + } } super.setText("" + hrefText + ""); setForeground(BKUGUIFacade.HYPERLINK_COLOR); diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeFilter.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeFilter.java index c0385dce..5d64eb4f 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeFilter.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeFilter.java @@ -26,14 +26,6 @@ import javax.swing.filechooser.FileFilter; */ class MimeFilter extends FileFilter { - private static final String MIMETYPE_DESC_XML = "mimetype.desc.xml"; - private static final String MIMETYPE_DESC_HTML = "mimetype.desc.html"; - private static final String MIMETYPE_DESC_XHTML = "mimetype.desc.xhtml"; - private static final String MIMETYPE_DESC_TXT = "mimetype.desc.txt"; - private static final String MIMETYPE_DESC_PDF = "mimetype.desc.pdf"; - private static final String MIMETYPE_DESC_BIN = "mimetype.desc.bin"; - private static final String MIMETYPE_DESC_UNKNOWN = "mimetype.desc.unknown"; - protected String mimeType; protected ResourceBundle messages; @@ -48,21 +40,7 @@ class MimeFilter extends FileFilter { if (f.isDirectory()) { return true; } - - String ext = getExtension(f); - if ("text/xml".equals(mimeType)) { - return "xml".equalsIgnoreCase(ext); - } else if ("text/html".equals(mimeType)) { - return "html".equalsIgnoreCase(ext) || "htm".equalsIgnoreCase(ext); - } else if ("application/xhtml+xml".equals(mimeType)) { - return "xhtml".equalsIgnoreCase(ext); - } else if ("text/plain".equals(mimeType)) { - return "txt".equalsIgnoreCase(ext); - } else if ("application/pdf".equals(mimeType)) { - return "pdf".equalsIgnoreCase(ext); - } else { - return true; - } + return MimeTypes.getExtension(mimeType).equalsIgnoreCase(getExtension(f)); } private String getExtension(File f) { @@ -78,38 +56,10 @@ class MimeFilter extends FileFilter { @Override public String getDescription() { - if ("text/xml".equals(mimeType)) { - return messages.getString(MIMETYPE_DESC_XML); - } else if ("text/html".equals(mimeType)) { - return messages.getString(MIMETYPE_DESC_HTML); - } else if ("application/xhtml+xml".equals(mimeType)) { - return messages.getString(MIMETYPE_DESC_XHTML); - } else if ("text/plain".equals(mimeType)) { - return messages.getString(MIMETYPE_DESC_TXT); - } else if ("application/pdf".equals(mimeType)) { - return messages.getString(MIMETYPE_DESC_PDF); - } else if ("application/octet-stream".equals(mimeType)) { - return messages.getString(MIMETYPE_DESC_BIN); - } else { - return messages.getString(MIMETYPE_DESC_UNKNOWN); - } + return messages.getString(MimeTypes.getDescriptionKey(mimeType)); } public static String getExtension(String mimeType) { - if ("text/xml".equals(mimeType)) { - return ".xml"; - } else if ("text/html".equals(mimeType)) { - return ".html"; - } else if ("application/xhtml+xml".equals(mimeType)) { - return ".xhtml"; - } else if ("text/plain".equals(mimeType)) { - return ".txt"; - } else if ("application/pdf".equals(mimeType)) { - return ".pdf"; - } else if ("application/octet-stream".equals(mimeType)) { - return ".bin"; - } else { - return ""; - } + return MimeTypes.getExtension(mimeType); } } \ No newline at end of file diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeTypes.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeTypes.java new file mode 100644 index 00000000..4500fa71 --- /dev/null +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeTypes.java @@ -0,0 +1,53 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package at.gv.egiz.bku.gui.viewer; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author clemens + */ +public class MimeTypes { + + private static final Map FILE_EXTENSIONS = new HashMap() {{ + put("application/msword", ".doc"); + put("application/octet-stream", ".bin"); + put("application/pdf", ".pdf"); + put("application/xhtml+xml", ".xhtml"); + put("text/html", ".html"); + put("text/plain", ".txt"); + put("text/xml", ".xml"); + }}; + + private static final Map DESCRIPTIONS = new HashMap() {{ + put("application/msword", "mimetype.desc.doc"); + put("application/octet-stream", "mimetype.desc.bin"); + put("application/pdf", "mimetype.desc.pdf"); + put("application/xhtml+xml", "mimetype.desc.xhtml"); + put("text/html", "mimetype.desc.html"); + put("text/plain", "mimetype.desc.txt"); + put("text/xml", "mimetype.desc.xml"); + }}; + + public static String getExtension(String mimetype) { + if (FILE_EXTENSIONS.containsKey(mimetype)) { + return FILE_EXTENSIONS.get(mimetype); + } + return ""; + } + + /** + * @return bundle key to be resolved in message resource bundle + */ + public static String getDescriptionKey(String mimetype) { + if (DESCRIPTIONS.containsKey(mimetype)) { + return DESCRIPTIONS.get(mimetype); + } + return "mimetype.desc.unknown"; + } +} diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewerSaveDialog.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewerSaveDialog.java index 40133f95..3303d4ef 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewerSaveDialog.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewerSaveDialog.java @@ -52,8 +52,9 @@ public class SecureViewerSaveDialog { String mimeType = hashDataInput.getMimeType(); MimeFilter mimeFilter = new MimeFilter(mimeType, messages); fileDialog.setFileFilter(mimeFilter); - String filename = messages - .getString(BKUGUIFacade.SAVE_HASHDATAINPUT_PREFIX) + String filename = (hashDataInput.getFilename() != null) ? + hashDataInput.getFilename() : + messages.getString(BKUGUIFacade.SAVE_HASHDATAINPUT_PREFIX) + MimeFilter.getExtension(mimeType); fileDialog.setSelectedFile(new File(userHome, filename)); diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/stal/impl/ByteArrayHashDataInput.java b/BKUCommonGUI/src/main/java/at/gv/egiz/stal/impl/ByteArrayHashDataInput.java index 6ca9a0b2..b9416845 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/stal/impl/ByteArrayHashDataInput.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/stal/impl/ByteArrayHashDataInput.java @@ -36,8 +36,9 @@ public class ByteArrayHashDataInput implements HashDataInput { protected String id; protected String mimeType; protected String encoding; + protected String filename; - public ByteArrayHashDataInput(byte[] hashData, String id, String mimeType, String encoding) { + public ByteArrayHashDataInput(byte[] hashData, String id, String mimeType, String encoding, String filename) { if (hashData == null) { throw new NullPointerException("HashDataInput not provided."); } @@ -45,6 +46,7 @@ public class ByteArrayHashDataInput implements HashDataInput { this.id = id; this.mimeType = mimeType; this.encoding = encoding; + this.filename = filename; } /** @@ -96,5 +98,10 @@ public class ByteArrayHashDataInput implements HashDataInput { return encoding; } + @Override + public String getFilename() { + return filename; + } + } diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties index 7135b561..3e483fc8 100644 --- a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties @@ -48,7 +48,7 @@ hashdatalink.tiny.focus=[Signaturdaten] #verwenden sie bitte die von ihrem System zur Verf\u00FCgung gestellte {0} Anwendung. hashdatalist={0} Signaturdaten: hashdata.viewer=Signaturdaten werden im Betrachter angezeigt -unsupported.mimetype=Signaturdaten können nicht angezeigt werden +unsupported.mimetype=Signaturdaten k\u00F6nnen nicht angezeigt werden retries.last=Letzter Versuch! retries=Noch {0} Versuche retries.pinpad.last=Eingabe wiederholen, letzter Versuch! @@ -71,6 +71,7 @@ mimetype.desc.xhtml=XHTML-Dateien (.xhtml) mimetype.desc.txt=Textdateien (.txt) mimetype.desc.pdf=Adobe PDF-Dateien (.pdf) mimetype.desc.bin=Bin\u00E4rdateien (.bin) +mimetype.desc.doc=Microsoft Word-Dateien (.doc) mimetype.desc.unknown=Alle Dateien (.*) save.hashdatainput.prefix=Signaturdaten alt.help=Hilfe diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties index 6e89510e..c553bcb5 100644 --- a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties @@ -69,6 +69,7 @@ mimetype.desc.xhtml=XHTML-files (.xhtml) mimetype.desc.txt=Textfiles (.txt) mimetype.desc.pdf=Adobe PDF-files (.pdf) mimetype.desc.bin=Binary files (.bin) +mimetype.desc.doc=Microsoft Word-files (.doc) mimetype.desc.unknown=All files (.*) save.hashdatainput.prefix=signaturedata alt.help=help diff --git a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java index 20654141..6e345ee3 100644 --- a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java +++ b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java @@ -85,25 +85,29 @@ public class BKUGUIWorker implements Runnable { "Ich bin ein einfacher Text mit Umlauten: öäüßéç@€\n123\n456\n\tHello, world!\n\nlkjsd\nnksdjf".getBytes(), "ref-id-0000000000000000000000001", "text/plain", - "UTF-8"); + "UTF-8", + "file.txt"); HashDataInput signedRef2 = new ByteArrayHashDataInput( "HashDataInput_002".getBytes(), "ref-id-000000002", "application/xhtml+xml", - "UTF-8"); + "UTF-8", + "file.xhtml"); HashDataInput signedRef3 = new ByteArrayHashDataInput( "HashDataInput_003".getBytes(), "ref-id-000000003", "application/xhtml+xml", - "UTF-8"); + "UTF-8", + "file2.xhtml"); HashDataInput signedRef4 = new ByteArrayHashDataInput( "HashDataInput_004".getBytes(), "ref-id-000000004", "text/xml", - "UTF-8"); + "UTF-8", + "file.xml"); // List signedRefs = new ArrayList(); diff --git a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/SecureViewerDialogTest.java b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/SecureViewerDialogTest.java index 131a344f..9bbc1b1a 100644 --- a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/SecureViewerDialogTest.java +++ b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/SecureViewerDialogTest.java @@ -66,7 +66,7 @@ public class SecureViewerDialogTest { String s = new String(bytes, "iso-8859-1"); System.out.println("read iso-8859-1 bytes " + s); - secureViewer.setContent(new ByteArrayHashDataInput(s.getBytes("UTF-8"), "id-1", "text/plain", "iso-8859-1")); + secureViewer.setContent(new ByteArrayHashDataInput(s.getBytes("UTF-8"), "id-1", "text/plain", "iso-8859-1", "file.txt")); } @@ -87,7 +87,7 @@ public class SecureViewerDialogTest { } System.out.println(data.toString()); - secureViewer.setContent(new ByteArrayHashDataInput(data.toString().getBytes("UTF-8"), "id-1", "text/plain", "UTF-8")); + secureViewer.setContent(new ByteArrayHashDataInput(data.toString().getBytes("UTF-8"), "id-1", "text/plain", "UTF-8", "file.txt")); } @@ -146,7 +146,7 @@ public class SecureViewerDialogTest { // byte[] bytes2 = data.getBytes("cp1252"); // System.out.println(data + "\t" + SMCCHelper.toString(bytes2)); - secureViewer.setContent(new ByteArrayHashDataInput(data.toString().getBytes("UTF-8"), "id-1", "text/plain", "UTF-8")); + secureViewer.setContent(new ByteArrayHashDataInput(data.toString().getBytes("UTF-8"), "id-1", "text/plain", "UTF-8", "file.txt")); System.out.println("\n\n=============================\n"); // diff --git a/BKUOnline/pom.xml b/BKUOnline/pom.xml index ed7f228c..c7c40982 100644 --- a/BKUOnline/pom.xml +++ b/BKUOnline/pom.xml @@ -263,7 +263,7 @@ staltypes-custom.xml cardchannel-custom.xml - ${basedir}/src/main/webapp/WEB-INF/wsdl + ${basedir}/src/main/wsdl stal-service.wsdl diff --git a/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALServiceImpl.java b/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALServiceImpl.java index eab9bed5..c8ab280f 100644 --- a/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALServiceImpl.java +++ b/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALServiceImpl.java @@ -267,6 +267,7 @@ public class STALServiceImpl implements STALPortType { ref.setID(reqRefId); ref.setMimeType(reqHdi.getMimeType()); ref.setEncoding(reqHdi.getEncoding()); + ref.setFilename(reqHdi.getFilename()); ref.setValue(baos.toByteArray()); response.getReference().add(ref); } catch (IOException ex) { diff --git a/BKUOnline/src/main/webapp/META-INF/context.xml b/BKUOnline/src/main/webapp/META-INF/context.xml index f38215a1..2a2da79e 100644 --- a/BKUOnline/src/main/webapp/META-INF/context.xml +++ b/BKUOnline/src/main/webapp/META-INF/context.xml @@ -16,4 +16,4 @@ limitations under the License. --> - + diff --git a/BKUOnline/src/main/webapp/WEB-INF/wsdl/stal.xsd b/BKUOnline/src/main/webapp/WEB-INF/wsdl/stal.xsd index 2389e043..a420035f 100644 --- a/BKUOnline/src/main/webapp/WEB-INF/wsdl/stal.xsd +++ b/BKUOnline/src/main/webapp/WEB-INF/wsdl/stal.xsd @@ -151,6 +151,7 @@ + diff --git a/BKUOnline/src/main/wsdl/stal-service.xsd b/BKUOnline/src/main/wsdl/stal-service.xsd index 870e2db6..177b9e7f 100644 --- a/BKUOnline/src/main/wsdl/stal-service.xsd +++ b/BKUOnline/src/main/wsdl/stal-service.xsd @@ -166,6 +166,7 @@ + diff --git a/BKUOnline/src/test/java/at/gv/egiz/stal/service/STALRequestBrokerTest.java b/BKUOnline/src/test/java/at/gv/egiz/stal/service/STALRequestBrokerTest.java index a1f3864e..741974eb 100644 --- a/BKUOnline/src/test/java/at/gv/egiz/stal/service/STALRequestBrokerTest.java +++ b/BKUOnline/src/test/java/at/gv/egiz/stal/service/STALRequestBrokerTest.java @@ -126,6 +126,12 @@ public class STALRequestBrokerTest { public String getEncoding() { return "UTF-8"; } + + + @Override + public String getFilename() { + return "file.txt"; + } }; r1.setHashDataInput(Collections.singletonList(hdi)); requests.add(r1); @@ -172,6 +178,11 @@ public class STALRequestBrokerTest { public String getEncoding() { return "UTF-8"; } + + @Override + public String getFilename() { + return "file.txt"; + } }; r1.setHashDataInput(Collections.singletonList(hdi)); requests.add(r1); @@ -231,6 +242,11 @@ public class STALRequestBrokerTest { public String getEncoding() { return "UTF-8"; } + + @Override + public String getFilename() { + return "file.txt"; + } }; r1.setHashDataInput(Collections.singletonList(hdi)); requests.add(r1); @@ -259,6 +275,11 @@ public class STALRequestBrokerTest { public String getEncoding() { return "UTF-8"; } + + @Override + public String getFilename() { + return "file.xml"; + } }; r2.setHashDataInput(Collections.singletonList(hdi2)); requests2.add(r2); diff --git a/STAL/src/main/java/at/gv/egiz/stal/HashDataInput.java b/STAL/src/main/java/at/gv/egiz/stal/HashDataInput.java index 62c25fc4..7092470c 100644 --- a/STAL/src/main/java/at/gv/egiz/stal/HashDataInput.java +++ b/STAL/src/main/java/at/gv/egiz/stal/HashDataInput.java @@ -31,6 +31,8 @@ public interface HashDataInput { public String getEncoding(); + public String getFilename(); + public InputStream getHashDataInput(); } diff --git a/STALService/src/main/java/at/gv/egiz/stal/service/types/GetHashDataInputResponseType.java b/STALService/src/main/java/at/gv/egiz/stal/service/types/GetHashDataInputResponseType.java index 7536d936..ad029757 100644 --- a/STALService/src/main/java/at/gv/egiz/stal/service/types/GetHashDataInputResponseType.java +++ b/STALService/src/main/java/at/gv/egiz/stal/service/types/GetHashDataInputResponseType.java @@ -28,6 +28,7 @@ import javax.xml.bind.annotation.XmlValue; * <attribute name="ID" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="MimeType" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="Encoding" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="Filename" type="{http://www.w3.org/2001/XMLSchema}string" /> * </extension> * </simpleContent> * </complexType> @@ -118,6 +119,7 @@ public class GetHashDataInputResponseType { * <attribute name="ID" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="MimeType" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="Encoding" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="Filename" type="{http://www.w3.org/2001/XMLSchema}string" /> * </extension> * </simpleContent> * </complexType> @@ -139,6 +141,8 @@ public class GetHashDataInputResponseType { protected String mimeType; @XmlAttribute(name = "Encoding") protected String encoding; + @XmlAttribute(name = "Filename") + protected String filename; /** * Gets the value of the value property. @@ -234,6 +238,30 @@ public class GetHashDataInputResponseType { this.encoding = value; } + /** + * Gets the value of the filename property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getFilename() { + return filename; + } + + /** + * Sets the value of the filename property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setFilename(String value) { + this.filename = value; + } + } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java index b1906666..e39addb5 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java @@ -339,6 +339,7 @@ public class HTTPBindingProcessor extends AbstractBindingProcessor implements // process headers and request setHTTPHeaders(dataUrlResponse.getResponseHeaders()); consumeRequestStream(dataUrlResponse.getStream()); + //TODO check for bindingProcessorError closeDataUrlConnection(); srcContex.setSourceCertificate(conn.getServerCertificate()); srcContex.setSourceIsDataURL(true); diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java index 1a9b56fb..57358ba0 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java @@ -50,4 +50,10 @@ public class DataObjectHashDataInput implements HashDataInput { return HttpUtil.getCharset(dataObject.getMimeType(), false); } + @Override + public String getFilename() { + //TODO obtain filename from dataObject, if not set return null or get filename (extension!) from mimetype + return dataObject.getFilename(); + } + } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java index 89124d16..6e84081e 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java @@ -49,8 +49,6 @@ import javax.xml.crypto.dsig.spec.XPathType; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.w3._2000._09.xmldsig_.TransformType; -import org.w3._2000._09.xmldsig_.TransformsType; import org.w3c.dom.DOMConfiguration; import org.w3c.dom.DOMException; import org.w3c.dom.Document; @@ -71,6 +69,7 @@ import at.buergerkarte.namespaces.securitylayer._1.DataObjectInfoType; import at.buergerkarte.namespaces.securitylayer._1.MetaInfoType; import at.buergerkarte.namespaces.securitylayer._1.TransformsInfoType; import at.gv.egiz.bku.binding.HttpUtil; +import at.gv.egiz.bku.gui.viewer.MimeTypes; import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.bku.slexceptions.SLRequestException; import at.gv.egiz.bku.slexceptions.SLRuntimeException; @@ -81,11 +80,11 @@ import at.gv.egiz.bku.viewer.ValidationException; import at.gv.egiz.bku.viewer.Validator; import at.gv.egiz.bku.viewer.ValidatorFactory; import at.gv.egiz.dom.DOMUtils; -import at.gv.egiz.marshal.NamespacePrefixMapperImpl; import at.gv.egiz.slbinding.impl.XMLContentType; -import javax.xml.namespace.NamespaceContext; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; /** * This class represents a DataObject of an XML-Signature @@ -184,7 +183,9 @@ public class DataObject { * An optional description of the digest input. */ private String description; - + + private String filename; + /** * Creates a new instance. * @@ -230,6 +231,10 @@ public class DataObject { return mimeType; } + public String getFilename() { + return filename; + } + /** * @return the description */ @@ -336,7 +341,74 @@ public class DataObject { } // other values are not allowed by the schema and are therefore ignored - + + this.filename = deriveFilename(); + } + + /** + * Extract filename from reference URI + * or propose reference Id with an apropriate (mime-type) file extension + * + * @return if neither reference nor id can be extracted return null (or data.extension?) + */ + private String deriveFilename() { + + String filename = null; + + if (reference != null) { + if (reference.getURI() != null && !"".equals(reference.getURI())) { + try { + log.info("deriving filename from reference URI " + reference.getURI()); + URI refURI = new URI(reference.getURI()); + + if (refURI.isOpaque()) { + // could check scheme component, but also allow other schemes (e.g. testlocal) + log.trace("opaque reference URI, use scheme-specific part as filename"); + filename = refURI.getSchemeSpecificPart(); + if (!hasExtension(filename)) { + filename += MimeTypes.getExtension(mimeType); + } + // else hierarchical URI: + // for shorthand xpointer use fragment as filename, + // for any other xpointer use reference Id and + // for any other hierarchical (absolute or relative) use filename (ignore fragment, see xmldsig section 4.3.3.2: fragments not recommendet) + } else if ("".equals(refURI.getPath()) && + refURI.getFragment() != null && + refURI.getFragment().indexOf('(') < 0) { // exclude (schemebased) xpointer expressions + log.trace("fragment (shorthand xpointer) URI, use fragment as filename"); + filename = refURI.getFragment(); + if(!hasExtension(filename)) { + filename += MimeTypes.getExtension(mimeType); + } + } else if (!"".equals(refURI.getPath())) { + log.trace("hierarchical URI with path component, use path as filename"); + File refFile = new File(refURI.getPath()); + filename = refFile.getName(); + if(!hasExtension(filename)) { + filename += MimeTypes.getExtension(mimeType); + } + } else { + log.info("failed to derive filename from URI '" + refURI + "', derive filename from reference ID"); + filename = reference.getId() + MimeTypes.getExtension(mimeType); + } + } catch (URISyntaxException ex) { + log.error("failed to derive filename from invalid URI " + ex.getMessage()); + filename = reference.getId() + MimeTypes.getExtension(mimeType); + } + } else { + log.info("same-document URI, derive filename from reference ID"); + filename = reference.getId() + MimeTypes.getExtension(mimeType); + } + } else { + log.error("failed to derive filename, no reference created"); + } + log.debug("derived filename for reference " + reference.getId() + ": " + filename); + return filename; + } + + private static boolean hasExtension(String filename) { + int extDelimiterInd = filename.lastIndexOf('.'); + return extDelimiterInd >= 0 && extDelimiterInd >= filename.length() - 4; } private byte[] getTransformsBytes(at.gv.egiz.slbinding.impl.TransformsInfoType ti) { diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java index 7ce7b42d..ccd29e85 100644 --- a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java @@ -443,8 +443,11 @@ public class SignatureTest { @SuppressWarnings("unchecked") @Test + public void testDataObject_XMLContent_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + System.out.println("\n ****************** testDataObject_XMLContent_1 \n"); + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_XMLContent_1.xml"); Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); @@ -485,6 +488,8 @@ public class SignatureTest { @Test public void testDataObject_XMLContent_2() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + System.out.println("\n ****************** testDataObject_XMLContent_2 \n"); + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_XMLContent_2.xml"); Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); @@ -526,6 +531,8 @@ public class SignatureTest { @Test public void testDataObject_LocRefContent_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + System.out.println("\n ****************** testDataObject_LocRefContent_1 \n"); + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_LocRefContent_1.xml"); Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); @@ -535,7 +542,7 @@ public class SignatureTest { } signature.buildXMLSignature(); - + signAndMarshalSignature(signature); List references = signature.getReferences(); @@ -564,6 +571,8 @@ public class SignatureTest { @Test public void testDataObject_LocRefContent_2() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + System.out.println("\n ****************** testDataObject_LocRefContent_2 \n"); + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_LocRefContent_2.xml"); Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); @@ -602,6 +611,8 @@ public class SignatureTest { @Test public void testDataObject_Reference_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + System.out.println("\n ****************** testDataObject_Reference_1 \n"); + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Reference_1.xml"); Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); @@ -640,6 +651,8 @@ public class SignatureTest { @Test public void testDataObject_Detached_1() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + System.out.println("\n ****************** testDataObject_Detached_1 \n"); + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Detached_1.xml"); Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); @@ -671,6 +684,8 @@ public class SignatureTest { @Test public void testDataObject_Detached_Base64Content() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + System.out.println("\n ****************** testDataObject_Detached_Base64Content \n"); + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Detached_Base64Content.xml"); Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); @@ -698,6 +713,39 @@ public class SignatureTest { } + @SuppressWarnings("unchecked") + @Test + public void testDataObject_Detached_LocRefContent() throws JAXBException, SLCommandException, XMLStreamException, SLRequestException, MarshalException, XMLSignatureException, SLViewerException { + + System.out.println("\n ****************** testDataObject_Detached_LocRefContent \n"); + + List dataObjectInfos = unmarshalDataObjectInfo("DataObjectInfo_Detached_LocRefContent.xml"); + + Signature signature = new Signature(null, new IdValueFactoryImpl(), new AlgorithmMethodFactoryImpl()); + + for (DataObjectInfoType dataObjectInfo : dataObjectInfos) { + signature.addDataObject(dataObjectInfo); + } + + signature.buildXMLSignature(); + + signAndMarshalSignature(signature); + + List references = signature.getReferences(); + assertTrue(references.size() == 2); + + Reference reference = references.get(0); + assertNotNull(reference.getId()); + + List transforms = reference.getTransforms(); + assertTrue(transforms.size() == 0); + + List objects = signature.getXMLObjects(); + assertNotNull(objects); + assertTrue(objects.size() == 1); + + } + // // // TransformsInfo diff --git a/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/impl/DataObjectInfo_Detached_LocRefContent.xml b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/impl/DataObjectInfo_Detached_LocRefContent.xml new file mode 100644 index 00000000..75f45ff0 --- /dev/null +++ b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/impl/DataObjectInfo_Detached_LocRefContent.xml @@ -0,0 +1,13 @@ + + + + + testlocal:DataObject1.bin + + + + application/octet-stream + + + + \ No newline at end of file diff --git a/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/impl/DataObjectInfo_LocRefContent_2.xml b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/impl/DataObjectInfo_LocRefContent_2.xml index 852c115f..a94f51b6 100644 --- a/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/impl/DataObjectInfo_LocRefContent_2.xml +++ b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/impl/DataObjectInfo_LocRefContent_2.xml @@ -6,7 +6,7 @@ - application/octetstream + application/octet-stream diff --git a/utils/src/main/java/at/gv/egiz/slbinding/RedirectEventFilter.java b/utils/src/main/java/at/gv/egiz/slbinding/RedirectEventFilter.java index 14c5ba48..5fe84aae 100644 --- a/utils/src/main/java/at/gv/egiz/slbinding/RedirectEventFilter.java +++ b/utils/src/main/java/at/gv/egiz/slbinding/RedirectEventFilter.java @@ -153,9 +153,6 @@ public class RedirectEventFilter implements EventFilter { private void redirectEvent(XMLEvent event) { try { - if (log.isTraceEnabled()) { - log.trace("redirecting StAX event " + event); - } redirectWriter.add(event); } catch (XMLStreamException ex) { ex.printStackTrace(); diff --git a/utils/src/main/java/at/gv/egiz/slbinding/impl/TransformsInfoType.java b/utils/src/main/java/at/gv/egiz/slbinding/impl/TransformsInfoType.java index 1180e9fa..b1de9406 100644 --- a/utils/src/main/java/at/gv/egiz/slbinding/impl/TransformsInfoType.java +++ b/utils/src/main/java/at/gv/egiz/slbinding/impl/TransformsInfoType.java @@ -22,6 +22,7 @@ package at.gv.egiz.slbinding.impl; import at.gv.egiz.slbinding.*; import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; import java.util.HashSet; import java.util.Set; import javax.xml.bind.annotation.XmlTransient; @@ -62,6 +63,13 @@ public class TransformsInfoType extends at.buergerkarte.namespaces.securitylayer log.debug("disabling event redirection for TransformsInfoType"); filter.flushRedirectStream(); filter.setRedirectStream(null); + if (log.isDebugEnabled()) { + try { + log.debug("redirected events (UTF-8): " + redirectOS.toString("UTF-8")); + } catch (UnsupportedEncodingException ex) { + log.debug("failed to log redirected events", ex); + } + } } @Override diff --git a/utils/src/main/java/at/gv/egiz/slbinding/impl/XMLContentType.java b/utils/src/main/java/at/gv/egiz/slbinding/impl/XMLContentType.java index eb147f88..fd52e378 100644 --- a/utils/src/main/java/at/gv/egiz/slbinding/impl/XMLContentType.java +++ b/utils/src/main/java/at/gv/egiz/slbinding/impl/XMLContentType.java @@ -23,6 +23,8 @@ package at.gv.egiz.slbinding.impl; import at.gv.egiz.slbinding.RedirectCallback; import at.gv.egiz.slbinding.RedirectEventFilter; import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; + import javax.xml.bind.annotation.XmlTransient; import javax.xml.stream.XMLStreamException; import org.apache.commons.logging.Log; @@ -51,6 +53,13 @@ public class XMLContentType extends at.buergerkarte.namespaces.securitylayer._1. log.debug("disabling event redirection for XMLContentType"); filter.flushRedirectStream(); filter.setRedirectStream(null); + if (log.isDebugEnabled()) { + try { + log.debug("redirected events (UTF-8): " + redirectOS.toString("UTF-8")); + } catch (UnsupportedEncodingException ex) { + log.debug("failed to log redirected events", ex); + } + } } @Override -- cgit v1.2.3 From fb20464dc8dc024568b439c460485c700137e0e2 Mon Sep 17 00:00:00 2001 From: clemenso Date: Tue, 29 Dec 2009 09:39:56 +0000 Subject: log level for debug messages git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@562 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- .../main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java') diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java index 6e84081e..a57a11dd 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java @@ -388,7 +388,7 @@ public class DataObject { filename += MimeTypes.getExtension(mimeType); } } else { - log.info("failed to derive filename from URI '" + refURI + "', derive filename from reference ID"); + log.debug("failed to derive filename from URI '" + refURI + "', derive filename from reference ID"); filename = reference.getId() + MimeTypes.getExtension(mimeType); } } catch (URISyntaxException ex) { @@ -396,7 +396,7 @@ public class DataObject { filename = reference.getId() + MimeTypes.getExtension(mimeType); } } else { - log.info("same-document URI, derive filename from reference ID"); + log.debug("same-document URI, derive filename from reference ID"); filename = reference.getId() + MimeTypes.getExtension(mimeType); } } else { -- cgit v1.2.3