summaryrefslogtreecommitdiff
path: root/bkucommon/src/main/java/at/gv/egiz/bku
diff options
context:
space:
mode:
Diffstat (limited to 'bkucommon/src/main/java/at/gv/egiz/bku')
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/AccessControl.java79
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Action.java114
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Chain.java115
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Chains.java86
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Command.java116
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/ObjectFactory.java135
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Param.java109
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Rule.java285
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Rules.java86
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AccessChecker.java23
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AccessCheckerContext.java43
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AccessControllerFactory.java153
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/Action.java35
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AuthenticationClass.java37
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AuthenticationClassifier.java110
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/ChainChecker.java91
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/ChainResult.java49
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/CommandParamChecker.java68
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/InfoboxParamChecker.java74
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/RuleChecker.java203
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/RuleResult.java32
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/SecurityManagerFacade.java118
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/UserAction.java36
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/AbstractBindingProcessor.java89
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/BindingProcessor.java78
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/BindingProcessorManager.java107
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/BindingProcessorManagerImpl.java330
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrl.java111
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnection.java82
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionImpl.java539
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionSPI.java64
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlResponse.java98
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/ExpiryRemover.java67
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/FixedFormParameters.java28
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/FormParameter.java39
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/FormParameterImpl.java93
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/FormParameterStore.java146
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java844
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/HttpUtil.java79
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/Id.java31
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/IdFactory.java106
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/IdImpl.java83
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/InputDecoder.java41
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/InputDecoderFactory.java89
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/MultiPartFormDataInputDecoder.java133
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/ProcessingContext.java59
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/RemovalStrategy.java26
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/SLCommandInvokerImpl.java95
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/XWWWFormUrlInputDecoder.java58
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/XWWWFormUrlInputIterator.java386
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/InputStreamPartSource.java61
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/SLResultPart.java71
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/conf/CertValidator.java13
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/conf/CertValidatorImpl.java107
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/conf/Configuration.java100
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/conf/Configurator.java467
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/conf/IAIKCommonsLog.java144
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/conf/IAIKCommonsLogFactory.java59
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/AccessControlInvocation.java21
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateXMLSignatureCommand.java25
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateXMLSignatureResult.java20
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/ErrorResult.java20
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/GetStatusCommand.java26
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/GetStatusResult.java26
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxReadCommand.java28
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxReadResult.java20
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxUpdateCommand.java23
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxUpdateResult.java21
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InvocationStrategy.java20
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/NullOperationCommand.java20
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/NullOperationResult.java20
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommand.java31
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandContext.java55
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandFactory.java395
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandInvoker.java46
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLMarshallerFactory.java172
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLResult.java45
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLSourceContext.java64
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLTargetContext.java51
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractAssocArrayInfobox.java299
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractBinaryFileInfobox.java66
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractInfoboxCommandImpl.java83
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractInfoboxImpl.java45
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AssocArrayInfobox.java27
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BinaryFileInfobox.java27
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CardChannelInfoboxImpl.java235
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CertificatesInfoboxImpl.java112
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureCommandImpl.java219
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureResultImpl.java107
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java59
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImpl.java67
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/GetStatusCommandImpl.java77
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/GetStatusResultImpl.java52
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/IdentityLinkInfoboxImpl.java290
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/Infobox.java70
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxFactory.java90
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadCommandImpl.java96
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadResultFileImpl.java160
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadResultImpl.java64
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxUpdateCommandImpl.java74
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxUpdateResultImpl.java43
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/NullOperationCommandImpl.java43
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/NullOperationResultImpl.java48
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLCommandImpl.java81
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLResultImpl.java297
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/STALHelper.java242
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImpl.java323
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactory.java79
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactoryImpl.java172
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/ByteArrayDereferencer.java65
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java1289
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/IdValueFactory.java37
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/IdValueFactoryImpl.java127
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/LocRefDereferencer.java112
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALPrivateKey.java128
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALProvider.java71
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALSignature.java184
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALSignatureException.java92
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java995
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureContext.java129
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureLocation.java235
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/SimpleDOMErrorHandler.java98
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/URIDereferncerAdapter.java103
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/XSECTReference.java112
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/XSECTTransforms.java124
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLBindingException.java31
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLCanceledException.java26
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLCommandException.java30
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLException.java88
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLExceptionMessages.java56
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLRequestException.java30
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLRuntimeException.java37
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLVersionException.java28
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLViewerException.java28
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/viewer/ResourceFontLoader.java61
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/viewer/ValidationException.java38
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/viewer/Validator.java25
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/viewer/ValidatorFactory.java178
138 files changed, 16473 insertions, 0 deletions
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/AccessControl.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/AccessControl.java
new file mode 100644
index 00000000..a03505f6
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/AccessControl.java
@@ -0,0 +1,79 @@
+/*
+* 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.accesscontrol.config;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element ref="{}Chains"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "chains"
+})
+@XmlRootElement(name = "AccessControl")
+public class AccessControl {
+
+ @XmlElement(name = "Chains", required = true)
+ protected Chains chains;
+
+ /**
+ * Gets the value of the chains property.
+ *
+ * @return
+ * possible object is
+ * {@link Chains }
+ *
+ */
+ public Chains getChains() {
+ return chains;
+ }
+
+ /**
+ * Sets the value of the chains property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Chains }
+ *
+ */
+ public void setChains(Chains value) {
+ this.chains = value;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Action.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Action.java
new file mode 100644
index 00000000..9b15f0fd
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Action.java
@@ -0,0 +1,114 @@
+/*
+* 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.accesscontrol.config;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;choice>
+ * &lt;element name="ChainRef" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="RuleAction">
+ * &lt;simpleType>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ * &lt;enumeration value="allow"/>
+ * &lt;enumeration value="deny"/>
+ * &lt;/restriction>
+ * &lt;/simpleType>
+ * &lt;/element>
+ * &lt;/choice>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "chainRef",
+ "ruleAction"
+})
+@XmlRootElement(name = "Action")
+public class Action {
+
+ @XmlElement(name = "ChainRef")
+ protected String chainRef;
+ @XmlElement(name = "RuleAction")
+ protected String ruleAction;
+
+ /**
+ * Gets the value of the chainRef property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getChainRef() {
+ return chainRef;
+ }
+
+ /**
+ * Sets the value of the chainRef property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setChainRef(String value) {
+ this.chainRef = value;
+ }
+
+ /**
+ * Gets the value of the ruleAction property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getRuleAction() {
+ return ruleAction;
+ }
+
+ /**
+ * Sets the value of the ruleAction property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setRuleAction(String value) {
+ this.ruleAction = value;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Chain.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Chain.java
new file mode 100644
index 00000000..92975e48
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Chain.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.accesscontrol.config;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlID;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element ref="{}Rules" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;attribute name="Id" type="{http://www.w3.org/2001/XMLSchema}ID" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "rules"
+})
+@XmlRootElement(name = "Chain")
+public class Chain {
+
+ @XmlElement(name = "Rules")
+ protected Rules rules;
+ @XmlAttribute(name = "Id")
+ @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+ @XmlID
+ @XmlSchemaType(name = "ID")
+ protected String id;
+
+ /**
+ * Gets the value of the rules property.
+ *
+ * @return
+ * possible object is
+ * {@link Rules }
+ *
+ */
+ public Rules getRules() {
+ return rules;
+ }
+
+ /**
+ * Sets the value of the rules property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Rules }
+ *
+ */
+ public void setRules(Rules value) {
+ this.rules = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Chains.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Chains.java
new file mode 100644
index 00000000..ea8c36bd
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Chains.java
@@ -0,0 +1,86 @@
+/*
+* 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.accesscontrol.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element ref="{}Chain" maxOccurs="unbounded"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "chain"
+})
+@XmlRootElement(name = "Chains")
+public class Chains {
+
+ @XmlElement(name = "Chain", required = true)
+ protected List<Chain> chain;
+
+ /**
+ * Gets the value of the chain property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the chain property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getChain().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Chain }
+ *
+ *
+ */
+ public List<Chain> getChain() {
+ if (chain == null) {
+ chain = new ArrayList<Chain>();
+ }
+ return this.chain;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Command.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Command.java
new file mode 100644
index 00000000..a2a9ebb4
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Command.java
@@ -0,0 +1,116 @@
+/*
+* 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.accesscontrol.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element ref="{}Param" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;attribute name="Name" use="required" type="{http://www.w3.org/2001/XMLSchema}anySimpleType" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "param"
+})
+@XmlRootElement(name = "Command")
+public class Command {
+
+ @XmlElement(name = "Param")
+ protected List<Param> param;
+ @XmlAttribute(name = "Name", required = true)
+ @XmlSchemaType(name = "anySimpleType")
+ protected String name;
+
+ /**
+ * Gets the value of the param property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the param property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getParam().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Param }
+ *
+ *
+ */
+ public List<Param> getParam() {
+ if (param == null) {
+ param = new ArrayList<Param>();
+ }
+ return this.param;
+ }
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setName(String value) {
+ this.name = value;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/ObjectFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/ObjectFactory.java
new file mode 100644
index 00000000..2c6e2187
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/ObjectFactory.java
@@ -0,0 +1,135 @@
+/*
+* 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.accesscontrol.config;
+
+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.gv.egiz.bku.accesscontrol.config package.
+ * <p>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 _UserInteraction_QNAME = new QName("", "UserInteraction");
+ private final static QName _AuthClass_QNAME = new QName("", "AuthClass");
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: at.gv.egiz.bku.accesscontrol.config
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link Param }
+ *
+ */
+ public Param createParam() {
+ return new Param();
+ }
+
+ /**
+ * Create an instance of {@link AccessControl }
+ *
+ */
+ public AccessControl createAccessControl() {
+ return new AccessControl();
+ }
+
+ /**
+ * Create an instance of {@link Command }
+ *
+ */
+ public Command createCommand() {
+ return new Command();
+ }
+
+ /**
+ * Create an instance of {@link Rules }
+ *
+ */
+ public Rules createRules() {
+ return new Rules();
+ }
+
+ /**
+ * Create an instance of {@link Action }
+ *
+ */
+ public Action createAction() {
+ return new Action();
+ }
+
+ /**
+ * Create an instance of {@link Chains }
+ *
+ */
+ public Chains createChains() {
+ return new Chains();
+ }
+
+ /**
+ * Create an instance of {@link Chain }
+ *
+ */
+ public Chain createChain() {
+ return new Chain();
+ }
+
+ /**
+ * Create an instance of {@link Rule }
+ *
+ */
+ public Rule createRule() {
+ return new Rule();
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
+ *
+ */
+ @XmlElementDecl(namespace = "", name = "UserInteraction")
+ public JAXBElement<String> createUserInteraction(String value) {
+ return new JAXBElement<String>(_UserInteraction_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
+ *
+ */
+ @XmlElementDecl(namespace = "", name = "AuthClass")
+ public JAXBElement<String> createAuthClass(String value) {
+ return new JAXBElement<String>(_AuthClass_QNAME, String.class, null, value);
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Param.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Param.java
new file mode 100644
index 00000000..daffa98d
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Param.java
@@ -0,0 +1,109 @@
+/*
+* 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.accesscontrol.config;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;simpleContent>
+ * &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
+ * &lt;attribute name="Name" use="required" type="{http://www.w3.org/2001/XMLSchema}NCName" />
+ * &lt;/extension>
+ * &lt;/simpleContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "value"
+})
+@XmlRootElement(name = "Param")
+public class Param {
+
+ @XmlValue
+ protected String value;
+ @XmlAttribute(name = "Name", required = true)
+ @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+ @XmlSchemaType(name = "NCName")
+ protected String name;
+
+ /**
+ * Gets the value of the value property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setName(String value) {
+ this.name = value;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Rule.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Rule.java
new file mode 100644
index 00000000..2ad1e660
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Rule.java
@@ -0,0 +1,285 @@
+/*
+* 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.accesscontrol.config;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlID;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element ref="{}AuthClass"/>
+ * &lt;choice minOccurs="0">
+ * &lt;element name="DomainName" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="IPv4Address" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="URL" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;/choice>
+ * &lt;element ref="{}Command" minOccurs="0"/>
+ * &lt;element ref="{}Action"/>
+ * &lt;element ref="{}UserInteraction"/>
+ * &lt;/sequence>
+ * &lt;attribute name="Id" type="{http://www.w3.org/2001/XMLSchema}ID" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "authClass",
+ "domainName",
+ "iPv4Address",
+ "url",
+ "command",
+ "action",
+ "userInteraction"
+})
+@XmlRootElement(name = "Rule")
+public class Rule {
+
+ @XmlElement(name = "AuthClass", required = true)
+ protected String authClass;
+ @XmlElement(name = "DomainName")
+ protected String domainName;
+ @XmlElement(name = "IPv4Address")
+ protected String iPv4Address;
+ @XmlElement(name = "URL")
+ protected String url;
+ @XmlElement(name = "Command")
+ protected Command command;
+ @XmlElement(name = "Action", required = true)
+ protected Action action;
+ @XmlElement(name = "UserInteraction", required = true)
+ protected String userInteraction;
+ @XmlAttribute(name = "Id")
+ @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+ @XmlID
+ @XmlSchemaType(name = "ID")
+ protected String id;
+
+ /**
+ * Gets the value of the authClass property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getAuthClass() {
+ return authClass;
+ }
+
+ /**
+ * Sets the value of the authClass property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setAuthClass(String value) {
+ this.authClass = value;
+ }
+
+ /**
+ * Gets the value of the domainName property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getDomainName() {
+ return domainName;
+ }
+
+ /**
+ * Sets the value of the domainName property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setDomainName(String value) {
+ this.domainName = value;
+ }
+
+ /**
+ * Gets the value of the iPv4Address property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getIPv4Address() {
+ return iPv4Address;
+ }
+
+ /**
+ * Sets the value of the iPv4Address property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setIPv4Address(String value) {
+ this.iPv4Address = value;
+ }
+
+ /**
+ * Gets the value of the url property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getURL() {
+ return url;
+ }
+
+ /**
+ * Sets the value of the url property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setURL(String value) {
+ this.url = value;
+ }
+
+ /**
+ * Gets the value of the command property.
+ *
+ * @return
+ * possible object is
+ * {@link Command }
+ *
+ */
+ public Command getCommand() {
+ return command;
+ }
+
+ /**
+ * Sets the value of the command property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Command }
+ *
+ */
+ public void setCommand(Command value) {
+ this.command = value;
+ }
+
+ /**
+ * Gets the value of the action property.
+ *
+ * @return
+ * possible object is
+ * {@link Action }
+ *
+ */
+ public Action getAction() {
+ return action;
+ }
+
+ /**
+ * Sets the value of the action property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Action }
+ *
+ */
+ public void setAction(Action value) {
+ this.action = value;
+ }
+
+ /**
+ * Gets the value of the userInteraction property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getUserInteraction() {
+ return userInteraction;
+ }
+
+ /**
+ * Sets the value of the userInteraction property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setUserInteraction(String value) {
+ this.userInteraction = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Rules.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Rules.java
new file mode 100644
index 00000000..16150f0c
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontrol/config/Rules.java
@@ -0,0 +1,86 @@
+/*
+* 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.accesscontrol.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element ref="{}Rule" maxOccurs="unbounded"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "rule"
+})
+@XmlRootElement(name = "Rules")
+public class Rules {
+
+ @XmlElement(name = "Rule", required = true)
+ protected List<Rule> rule;
+
+ /**
+ * Gets the value of the rule property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the rule property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getRule().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Rule }
+ *
+ *
+ */
+ public List<Rule> getRule() {
+ if (rule == null) {
+ rule = new ArrayList<Rule>();
+ }
+ return this.rule;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AccessChecker.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AccessChecker.java
new file mode 100644
index 00000000..d930c74e
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AccessChecker.java
@@ -0,0 +1,23 @@
+/*
+* 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.accesscontroller;
+
+import at.gv.egiz.bku.slexceptions.SLException;
+
+public interface AccessChecker {
+ public ChainResult check(AccessCheckerContext checkCtx) throws SLException;
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AccessCheckerContext.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AccessCheckerContext.java
new file mode 100644
index 00000000..60935678
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AccessCheckerContext.java
@@ -0,0 +1,43 @@
+/*
+* 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.accesscontroller;
+
+import at.gv.egiz.bku.slcommands.SLCommand;
+
+public class AccessCheckerContext {
+ private SLCommand command;
+ private AuthenticationClass authenticationClass;
+ private String peerUrl;
+
+ public AccessCheckerContext(SLCommand cmd, AuthenticationClass ac, String url) {
+ this.command = cmd;
+ this.authenticationClass = ac;
+ this.peerUrl = url;
+ }
+
+ public SLCommand getCommand() {
+ return command;
+ }
+
+ public AuthenticationClass getAuthenticationClass() {
+ return authenticationClass;
+ }
+
+ public String getPeerUrl() {
+ return peerUrl;
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AccessControllerFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AccessControllerFactory.java
new file mode 100644
index 00000000..19fec084
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AccessControllerFactory.java
@@ -0,0 +1,153 @@
+/*
+* 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.accesscontroller;
+
+import java.io.InputStream;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.accesscontrol.config.AccessControl;
+import at.gv.egiz.bku.accesscontrol.config.Chain;
+import at.gv.egiz.bku.accesscontrol.config.Command;
+import at.gv.egiz.bku.accesscontrol.config.ObjectFactory;
+import at.gv.egiz.bku.accesscontrol.config.Param;
+import at.gv.egiz.bku.accesscontrol.config.Rule;
+import at.gv.egiz.bku.accesscontroller.RuleChecker.PEER_TYPE;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+
+public class AccessControllerFactory {
+
+ private static AccessControllerFactory instance = new AccessControllerFactory();
+ private static Log log = LogFactory.getLog(AccessControllerFactory.class);
+ private static JAXBContext jaxbContext;
+ public static String INPUT_CHAIN = "InputChain";
+ public static String OUTPUT_CHAIN = "OutputChain";
+
+ static {
+ try {
+ jaxbContext = JAXBContext.newInstance(ObjectFactory.class.getPackage()
+ .getName());
+ } catch (JAXBException e) {
+ log.fatal("Cannot init jaxbContext", e);
+ }
+ }
+
+ private Hashtable<String, ChainChecker> chainTable = new Hashtable<String, ChainChecker>();
+
+ private AccessControllerFactory() {
+ }
+
+ public static AccessControllerFactory getInstance() {
+ return instance;
+ }
+
+ /**
+ *
+ * @param id
+ * @return null if there is no chain with this id.
+ */
+ public ChainChecker getChainChecker(String id) {
+ return chainTable.get(id);
+ }
+
+ public ChainChecker createChainChecker(String id, boolean register) {
+ ChainChecker cc = new ChainChecker(id);
+ if (register) {
+ chainTable.put(id, cc);
+ }
+ return cc;
+ }
+
+ public void registerChainChecker(ChainChecker cc) {
+ chainTable.put(cc.getId(), cc);
+ }
+
+ public CommandParamChecker createParamChecker(String cmd) {
+ if ((cmd != null) && (cmd.startsWith("Infobox"))) {
+ return new InfoboxParamChecker();
+ } else {
+ return null;
+ }
+ }
+
+ public RuleChecker createRuleChecker(Rule rule) {
+ RuleChecker rc;
+ rc = new RuleChecker(rule.getId());
+ Command cmd = rule.getCommand();
+ if (cmd != null) {
+ rc.setCommandName(cmd.getName());
+ for (Param p : cmd.getParam()) {
+ rc.addParameter(p.getName(), p.getValue());
+ }
+ }
+ rc.setAuthenticationClass(rule.getAuthClass());
+ if (rule.getIPv4Address() != null) {
+ rc.setPeerId(rule.getIPv4Address(), PEER_TYPE.IP);
+ } else if (rule.getDomainName() != null) {
+ rc.setPeerId(rule.getDomainName(), PEER_TYPE.HOST);
+ } else if (rule.getURL() != null) {
+ rc.setPeerId(rule.getURL(), PEER_TYPE.URL);
+ }
+ rc.setAction(rule.getAction().getRuleAction());
+ rc.setChainId(rule.getAction().getChainRef());
+ rc.setUserAction(rule.getUserInteraction());
+ return rc;
+ }
+
+ public void init(InputStream is) throws JAXBException {
+ chainTable.clear();
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ AccessControl ac = (AccessControl) unmarshaller.unmarshal(is);
+ List<Chain> chainList = ac.getChains().getChain();
+ log.debug("Found " + chainList.size() + " chains in config");
+ for (Chain chain : chainList) {
+ log.trace("Creating chain: " + chain.getId());
+ ChainChecker cc = createChainChecker(chain.getId(), false);
+ List<Rule> ruleList = chain.getRules().getRule();
+ log
+ .debug("Found " + ruleList.size() + " rules in chain "
+ + chain.getId());
+ for (Rule rule : ruleList) {
+ log.trace("Creating rule: " + rule.getId());
+ cc.addRule(createRuleChecker(rule));
+ }
+ registerChainChecker(cc);
+ }
+ validate();
+ }
+
+ private void validate() {
+ for (ChainChecker chain : chainTable.values()) {
+ for (RuleChecker rule : chain.getRules()) {
+ if (rule.getChainId() != null) {
+ log.trace("Checking reference to chain: "+rule.getChainId());
+ if (getChainChecker(rule.getChainId()) == null) {
+ throw new SLRuntimeException("Invalid reference to unknown chain: "+rule.getChainId());
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/Action.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/Action.java
new file mode 100644
index 00000000..f3d15ad6
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/Action.java
@@ -0,0 +1,35 @@
+/*
+* 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.accesscontroller;
+
+public enum Action {
+ ALLOW("allow"), DENY("deny");
+ private String name;
+
+ Action(String name) {
+ this.name = name;
+ }
+
+ public static Action fromString(String s) {
+ for (Action ac : values()) {
+ if (ac.name.equals(s)) {
+ return ac;
+ }
+ }
+ return null;
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AuthenticationClass.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AuthenticationClass.java
new file mode 100644
index 00000000..3c442a6d
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AuthenticationClass.java
@@ -0,0 +1,37 @@
+/*
+* 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.accesscontroller;
+
+public enum AuthenticationClass {
+ ANONYMOUS("anonymous"), PSEUDO_ANONYMOUS("pseudoanonymous"), CERTIFIED(
+ "certified"), CERTIFIED_GOV_AGENCY("certifiedGovAgency");
+
+ private String name;
+
+ AuthenticationClass(String name) {
+ this.name = name;
+ }
+
+ public static AuthenticationClass fromString(String s) {
+ for (AuthenticationClass ac : values()) {
+ if (ac.name.equals(s)) {
+ return ac;
+ }
+ }
+ return null;
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AuthenticationClassifier.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AuthenticationClassifier.java
new file mode 100644
index 00000000..61d3d7a5
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/AuthenticationClassifier.java
@@ -0,0 +1,110 @@
+/*
+ * 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.accesscontroller;
+
+import static at.gv.egiz.bku.accesscontroller.AuthenticationClass.ANONYMOUS;
+import static at.gv.egiz.bku.accesscontroller.AuthenticationClass.CERTIFIED;
+import static at.gv.egiz.bku.accesscontroller.AuthenticationClass.CERTIFIED_GOV_AGENCY;
+import static at.gv.egiz.bku.accesscontroller.AuthenticationClass.PSEUDO_ANONYMOUS;
+
+import java.net.URL;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class AuthenticationClassifier {
+ private static AuthenticationClassifier instance = new AuthenticationClassifier();
+ private static Log log = LogFactory.getLog(AuthenticationClassifier.class);
+ private final static String GOV_DOMAIN = ".gv.at";
+
+ private AuthenticationClassifier() {
+ }
+
+ public static boolean isGovAgency(X509Certificate cert) {
+ String[] rdns = (cert.getSubjectX500Principal().getName()).split(",");
+ for (String rdn : rdns) {
+ if (rdn.startsWith("CN=")) {
+ String dns = rdn.split("=")[1];
+ log.trace("Analyzing cn dn: " + dns);
+ if (dns.endsWith(GOV_DOMAIN)) {
+ return true;
+ }
+ }
+ }
+ try {
+ Collection<List<?>> sanList = cert.getSubjectAlternativeNames();
+ if (sanList != null) {
+ for (List<?> san : sanList) {
+ log.trace("Analyzing subj. alt name: " + san);
+ if ((Integer) san.get(0) == 2) {
+ String dns = (String) san.get(1);
+ if (dns.endsWith(GOV_DOMAIN)) {
+ return true;
+ }
+ }
+ }
+ }
+ } catch (CertificateParsingException e) {
+ log.error(e);
+ }
+ if ((cert.getExtensionValue("1.2.40.0.10.1.1.1") != null)
+ || (cert.getExtensionValue("1.2.40.0.10.1.1.2") != null)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Client Certificates are currently not supported
+ *
+ */
+ protected AuthenticationClass getMyAuthenticationClass(boolean isDataUrl,
+ URL url, X509Certificate cert) {
+ if (isDataUrl) {
+ if (url.getProtocol().equalsIgnoreCase("https")) {
+ if (isGovAgency(cert)) {
+ return CERTIFIED_GOV_AGENCY;
+ }
+ if (cert.getExtensionValue("1.2.40.0.10.1.1.1") != null) {
+ return CERTIFIED_GOV_AGENCY;
+ }
+ return CERTIFIED;
+ } else {
+ return PSEUDO_ANONYMOUS;
+ }
+ } else {
+ return ANONYMOUS;
+ }
+ }
+
+ /**
+ *
+ * @param isDataUrl
+ * @param url
+ * if the url's protocol is https a cert parameter must be provided.
+ * @param cert
+ * @return
+ */
+ public static AuthenticationClass getAuthenticationClass(boolean isDataUrl,
+ URL url, X509Certificate cert) {
+ return instance.getMyAuthenticationClass(isDataUrl, url, cert);
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/ChainChecker.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/ChainChecker.java
new file mode 100644
index 00000000..716f81e4
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/ChainChecker.java
@@ -0,0 +1,91 @@
+/*
+* 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.accesscontroller;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.slexceptions.SLException;
+
+public class ChainChecker implements AccessChecker {
+ private static Log log = LogFactory.getLog(ChainChecker.class);
+
+ private String id;
+ private List<RuleChecker> rules = new LinkedList<RuleChecker>();
+
+ /**
+ *
+ * @param id must not be null
+ */
+ public ChainChecker(String id) {
+ if (id == null) {
+ throw new NullPointerException("Id argument must not be null");
+ }
+ this.id = id;
+ }
+
+
+ public String getId() {
+ return id;
+ }
+
+ public void addRule(RuleChecker rule) {
+ if (rule != null) {
+ rules.add(rule);
+ }
+ }
+
+ public List<RuleChecker> getRules() {
+ return Collections.unmodifiableList(rules);
+ }
+
+ @Override
+ public ChainResult check(AccessCheckerContext checkCtx) throws SLException {
+ log.debug("Processing chain: "+id);
+ for (RuleChecker rule : rules) {
+ log.trace("Checking rule: "+rule.getId());
+ RuleResult result = rule.check(checkCtx);
+ if (result.matchFound()) {
+ if (result.getDelegateChainId() != null) {
+ // process chain
+ ChainChecker cc = AccessControllerFactory.getInstance().getChainChecker(result.getDelegateChainId());
+ if (cc == null) {
+ log.error("Cannot delegate to chain. Unknown chain id: "+result.getDelegateChainId());
+ throw new SLException(4000);
+ }
+ ChainResult cr = cc.check(checkCtx);
+ if (cr.matchFound()) {
+ return cr;
+ }
+ // if chain does not contain matching rule
+ // cont. here.
+ } else {
+ return result;
+ }
+ }
+ }
+ log.debug("Did not find a matching rule here");
+ return new ChainResult(null, null, false);
+ }
+
+
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/ChainResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/ChainResult.java
new file mode 100644
index 00000000..a5547cab
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/ChainResult.java
@@ -0,0 +1,49 @@
+/*
+* 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.accesscontroller;
+
+/**
+ * Result of the access controller
+ *
+ */
+public class ChainResult {
+ private UserAction userAction;
+ private Action action;
+ private boolean matchFound;
+
+ public ChainResult(Action action, UserAction userAction, boolean matchFound) {
+ this.action = action;
+ this.userAction = userAction;
+ this.matchFound = matchFound;
+ }
+
+ public Action getAction() {
+ return action;
+ }
+
+ public UserAction getUserAction() {
+ return userAction;
+ }
+
+ /**
+ *
+ * @return true if a matching rule has been found
+ */
+ public boolean matchFound() {
+ return matchFound;
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/CommandParamChecker.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/CommandParamChecker.java
new file mode 100644
index 00000000..003eb2f7
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/CommandParamChecker.java
@@ -0,0 +1,68 @@
+/*
+* 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.accesscontroller;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import at.gv.egiz.bku.slcommands.SLCommand;
+
+public abstract class CommandParamChecker {
+
+ protected List<Tupel<String, String>> paramList = new LinkedList<Tupel<String, String>>();
+
+ public static class Tupel<T, Q> {
+ private T key;
+ private Q val;
+
+ public Tupel(T key, Q val) {
+ if ((key == null) || (val == null)) {
+ throw new NullPointerException("Tupel key and value must not be null");
+ }
+ this.key = key;
+ this.val = val;
+ }
+
+ public T getKey() {
+ return key;
+ }
+
+ public Q getVal() {
+ return val;
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean equals(Object other) {
+ if (other instanceof Tupel) {
+ Tupel ot = (Tupel) other;
+ return (key.equals(ot.key) && val.equals(ot.val));
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ return key.hashCode();
+ }
+ }
+
+ public void addParameter(String key, String value) {
+ paramList.add(new Tupel<String, String>(key, value));
+ }
+
+ public abstract boolean checkParameter(SLCommand cmd);
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/InfoboxParamChecker.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/InfoboxParamChecker.java
new file mode 100644
index 00000000..8fa328de
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/InfoboxParamChecker.java
@@ -0,0 +1,74 @@
+/*
+* 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.accesscontroller;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.slcommands.InfoboxReadCommand;
+import at.gv.egiz.bku.slcommands.SLCommand;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+
+public class InfoboxParamChecker extends CommandParamChecker {
+ private static Log log = LogFactory.getLog(InfoboxParamChecker.class);
+
+ public final static String INFOBOX_ID = "InfoboxIdentifier";
+ public final static String PERSON_ID = "PersonIdentifier";
+ public final static String DERIVED = "derived";
+
+ @Override
+ public boolean checkParameter(SLCommand cmd) {
+ if (paramList.size() == 0) {
+ return true;
+ }
+
+ if (cmd instanceof InfoboxReadCommand) {
+ InfoboxReadCommand irc = (InfoboxReadCommand) cmd;
+ for (Tupel<String, String> param : paramList) {
+ if (param.getKey().equals(INFOBOX_ID)) {
+ if (!param.getVal().equals(irc.getInfoboxIdentifier())) {
+ return false;
+ }
+ } else if (param.getKey().equals(PERSON_ID)) {
+ if (param.getVal().equals(DERIVED)) {
+ if (irc.getIdentityLinkDomainId() == null) {
+ return false;
+ }
+ } else {
+ Pattern p = Pattern.compile(param.getVal());
+ Matcher m = p.matcher(irc.getIdentityLinkDomainId());
+ if (!m.matches()) {
+ return false;
+ }
+ }
+
+ } else {
+ throw new SLRuntimeException("Cannot handle parameter "
+ + param.getKey());
+ }
+ }
+ return true;
+ } else {
+ log.error("Cannot handle parameter for command: " + cmd.getName());
+ throw new SLRuntimeException("Cannot handle parameters for command: "
+ + cmd.getName());
+ }
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/RuleChecker.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/RuleChecker.java
new file mode 100644
index 00000000..1cba89ef
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/RuleChecker.java
@@ -0,0 +1,203 @@
+/*
+* 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.accesscontroller;
+
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.slcommands.SLCommand;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+
+public class RuleChecker implements AccessChecker {
+
+ private static Log log = LogFactory.getLog(RuleChecker.class);
+
+ public static enum PEER_TYPE {
+ HOST, IP, URL
+ };
+
+ protected String id;
+ protected AuthenticationClass authenticationClass;
+ protected String commandName;
+ protected Pattern commandNamePattern;
+ protected String peerId;
+ protected Pattern peerIdPattern;
+ protected PEER_TYPE peerType;
+ protected Action action;
+ protected UserAction userAction;
+ protected String chainId;
+ protected CommandParamChecker paramChecker;
+
+ public RuleChecker(String id) {
+ if (id == null) {
+ throw new NullPointerException("Id argument must not be null");
+ }
+ this.id = id;
+ }
+
+ public void setAuthenticationClass(String ac) {
+ if (ac != null) {
+ AuthenticationClass tmp = AuthenticationClass.fromString(ac);
+ if (tmp == null) {
+ throw new SLRuntimeException("Unknown authentication class " + ac);
+ }
+ authenticationClass = tmp;
+ }
+ }
+
+ public void setAction(String ac) {
+ if (ac != null) {
+ Action tmp = Action.fromString(ac);
+ if (tmp == null) {
+ throw new SLRuntimeException("Unknown action " + ac);
+ }
+ action = tmp;
+ }
+ }
+
+ public void setUserAction(String uac) {
+ if (uac != null) {
+ UserAction tmp = UserAction.fromString(uac);
+ if (tmp == null) {
+ throw new SLRuntimeException("Unknown user action " + uac);
+ }
+ userAction = tmp;
+ }
+ }
+
+ public void setChainId(String chainId) {
+ this.chainId = chainId;
+ }
+
+ public void setPeerId(String peerId, PEER_TYPE type) {
+ this.peerType = type;
+ this.peerId = peerId;
+ peerIdPattern = Pattern.compile(peerId);
+ }
+
+ public void setCommandName(String commandName) {
+ this.commandName = commandName;
+ commandNamePattern = Pattern.compile(commandName);
+ paramChecker = AccessControllerFactory.getInstance().createParamChecker(
+ commandName);
+ }
+
+ /**
+ * Make sure to set the commandName first
+ *
+ * @param key
+ * @param value
+ */
+ public void addParameter(String key, String value) {
+ if (paramChecker == null) {
+ throw new IllegalArgumentException("Cannot set parameters for command "
+ + commandName);
+ }
+ paramChecker.addParameter(key, value);
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ protected boolean matchAuthenticationClass(AuthenticationClass cls) {
+ if ((this.authenticationClass == null) || (cls == null)) {
+ return true;
+ }
+ return this.authenticationClass.compareTo(cls) <= 0;
+ }
+
+ protected boolean matchCommandName(SLCommand cmd) {
+ if ((commandName == null) || (cmd == null)) {
+ return true;
+ }
+ Matcher matcher = commandNamePattern.matcher(cmd.getName());
+ if (matcher.matches()) {
+ if (paramChecker != null) {
+ return paramChecker.checkParameter(cmd);
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ protected boolean matchPeerId(String peerUrl) {
+ if ((peerId == null) || (peerUrl == null)) {
+ return true;
+ }
+ if (peerType == PEER_TYPE.URL) {
+ Matcher matcher = peerIdPattern.matcher(peerUrl);
+ return matcher.matches();
+ } else {
+ try {
+ URL url = new URL(peerUrl);
+ if (peerType == PEER_TYPE.HOST) {
+ try {
+ String host = url.getHost();
+ String hostName = InetAddress.getByName(host)
+ .getCanonicalHostName();
+ Matcher matcher = peerIdPattern.matcher(hostName);
+ return matcher.matches();
+ } catch (UnknownHostException e) {
+ log.error("Cannot resolve hostname", e);
+ return false;
+ }
+ } else {
+ try {
+ String hostAddr = InetAddress.getByName(url.getHost())
+ .getHostAddress();
+ Matcher matcher = peerIdPattern.matcher(hostAddr);
+ return matcher.matches();
+ } catch (UnknownHostException e) {
+ log.error("Cannot resolve host address", e);
+ return false;
+ }
+ }
+ } catch (MalformedURLException e) {
+ log.error("Cannot parse url", e);
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public RuleResult check(AccessCheckerContext checkCtx) {
+ log.debug("Processing rule: " + id);
+ if (matchAuthenticationClass(checkCtx.getAuthenticationClass())
+ && matchCommandName(checkCtx.getCommand())
+ && matchPeerId(checkCtx.getPeerUrl())) {
+ log.debug("Match found for rule: " + id);
+ return new RuleResult(action, userAction, true, chainId);
+ }
+ log.debug("No match found for rule: " + id);
+ return new RuleResult(action, userAction, false, chainId);
+ }
+
+ public String getChainId() {
+ return chainId;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/RuleResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/RuleResult.java
new file mode 100644
index 00000000..706615c2
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/RuleResult.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.accesscontroller;
+
+
+public class RuleResult extends ChainResult {
+ private String chainId;
+
+ public RuleResult(Action action, UserAction userAction, boolean matchFound, String chainId) {
+ super(action, userAction, matchFound);
+ this.chainId = chainId;
+ }
+
+ public String getDelegateChainId() {
+ return chainId;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/SecurityManagerFacade.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/SecurityManagerFacade.java
new file mode 100644
index 00000000..482d3ecb
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/SecurityManagerFacade.java
@@ -0,0 +1,118 @@
+/*
+* 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.accesscontroller;
+
+import java.io.InputStream;
+
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.slcommands.SLCommand;
+import at.gv.egiz.bku.slcommands.SLSourceContext;
+import at.gv.egiz.bku.slcommands.SLTargetContext;
+
+/**
+ * Facade for the access controller
+ */
+public class SecurityManagerFacade {
+
+ private static Log log = LogFactory.getLog(SecurityManagerFacade.class);
+
+ private boolean allowUnmatched = false;
+ private ChainChecker inputFilter = null;
+ private ChainChecker outputFilter = null;
+
+ public boolean mayInvokeCommand(SLCommand cmd, SLSourceContext ctx) {
+ if (inputFilter != null) {
+ AuthenticationClass ac = AuthenticationClassifier.getAuthenticationClass(
+ ctx.isSourceIsDataURL(), ctx.getSourceUrl(), ctx
+ .getSourceCertificate());
+ AccessCheckerContext acc = new AccessCheckerContext(cmd, ac, ctx
+ .getSourceUrl().toString());
+ try {
+ ChainResult cr = inputFilter.check(acc);
+ if (cr.matchFound()) {
+ if (cr.getAction() == Action.ALLOW) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return allowUnmatched;
+ }
+ } catch (Exception e) {
+ log.error(e);
+ return false;
+ }
+ } else {
+ log.warn("No input chain defined");
+ return allowUnmatched;
+ }
+ }
+
+ public boolean maySendResult(SLCommand cmd, SLTargetContext ctx) {
+ if (outputFilter != null) {
+ AuthenticationClass ac = AuthenticationClassifier.getAuthenticationClass(
+ ctx.isTargetIsDataURL(), ctx.getTargetUrl(), ctx
+ .getTargetCertificate());
+ AccessCheckerContext acc = new AccessCheckerContext(cmd, ac, ctx
+ .getTargetUrl().toString());
+ try {
+ ChainResult cr = outputFilter.check(acc);
+ if (cr.matchFound()) {
+ if (cr.getAction() == Action.ALLOW) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return allowUnmatched;
+ }
+ } catch (Exception e) {
+ log.error(e);
+ return false;
+ }
+ } else {
+ log.warn("No output chain defined");
+ return allowUnmatched;
+ }
+ }
+
+ /**
+ * Default policy if not match was found
+ *
+ * @param allow
+ */
+ public void setAllowUnmatched(boolean allow) {
+ this.allowUnmatched = allow;
+ }
+
+ public void init(InputStream is) {
+ inputFilter = null;
+ outputFilter = null;
+ AccessControllerFactory fab = AccessControllerFactory.getInstance();
+ try {
+ fab.init(is);
+ } catch (JAXBException e) {
+ log.error(e);
+ }
+ inputFilter = fab.getChainChecker(AccessControllerFactory.INPUT_CHAIN);
+ outputFilter = fab.getChainChecker(AccessControllerFactory.OUTPUT_CHAIN);
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/UserAction.java b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/UserAction.java
new file mode 100644
index 00000000..c1f7028b
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/accesscontroller/UserAction.java
@@ -0,0 +1,36 @@
+/*
+* 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.accesscontroller;
+
+public enum UserAction {
+ NONE("none"), INFO("info"), CONFIRM("confirm"), CONFIRM_WITH_SECRET("confirmWithSecret");
+
+ private String name;
+
+ UserAction(String name) {
+ this.name = name;
+ }
+
+ public static UserAction fromString(String s) {
+ for (UserAction ac : values()) {
+ if (ac.name.equals(s)) {
+ return ac;
+ }
+ }
+ return null;
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/AbstractBindingProcessor.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/AbstractBindingProcessor.java
new file mode 100644
index 00000000..23f62134
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/AbstractBindingProcessor.java
@@ -0,0 +1,89 @@
+/*
+* 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.binding;
+
+import at.gv.egiz.bku.conf.Configuration;
+import java.io.InputStream;
+import java.util.Date;
+
+import at.gv.egiz.bku.slcommands.SLCommandInvoker;
+import at.gv.egiz.stal.STAL;
+
+public abstract class AbstractBindingProcessor implements BindingProcessor {
+ protected Id id;
+ protected Configuration config;
+ protected STAL stal;
+ protected SLCommandInvoker commandInvoker;
+ protected long lastAccessedTime = System.currentTimeMillis();
+
+ public AbstractBindingProcessor(String idString) {
+ this.id = IdFactory.getInstance().createId(idString);
+ }
+
+ /**
+ * @see java.lang.Thread#run()
+ */
+ public abstract void run();
+
+ /**
+ * The caller is advised to check the result in case an error occurred.
+ *
+ * @see #getResult()
+ */
+ public abstract void consumeRequestStream(InputStream aIs);
+
+ public Id getId() {
+ return id;
+ }
+
+ public STAL getSTAL() {
+ return stal;
+ }
+
+ public SLCommandInvoker getCommandInvoker() {
+ return commandInvoker;
+ }
+
+ public void updateLastAccessTime() {
+ lastAccessedTime = System.currentTimeMillis();
+ }
+
+ public Date getLastAccessTime() {
+ return new Date(lastAccessedTime);
+ }
+
+ /**
+ * To be called after object creation.
+ *
+ * @param aStal
+ * must not be null
+ * @param aCommandInvoker
+ * must not be null
+ */
+ public void init(STAL aStal, SLCommandInvoker aCommandInvoker, Configuration conf) {
+ if (aStal == null) {
+ throw new NullPointerException("STAL must not be set to null");
+ }
+ if (aCommandInvoker == null) {
+ throw new NullPointerException("Commandinvoker must not be set to null");
+ }
+ config = conf;
+ stal = aStal;
+ commandInvoker = aCommandInvoker;
+ Thread.currentThread().setName("BPID#"+getId().toString());
+ }
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/BindingProcessor.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/BindingProcessor.java
new file mode 100644
index 00000000..0d978992
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/BindingProcessor.java
@@ -0,0 +1,78 @@
+/*
+* 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.binding;
+
+import at.gv.egiz.bku.conf.Configuration;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Date;
+import java.util.Locale;
+
+import at.gv.egiz.bku.slcommands.SLCommandInvoker;
+import at.gv.egiz.stal.STAL;
+
+/**
+ * Represents an single instance of a SL HTTP binding.
+ *
+ * @author wbauer
+ *
+ */
+public interface BindingProcessor extends Runnable {
+
+ /**
+ * The stream must be read completely within this method.
+ *
+ * The caller is advised to check the result in case an error occurred.
+ *
+ * @see #getResult()
+ */
+ public void consumeRequestStream(InputStream aIs);
+
+ /**
+ * The unique Id of this http binding instance.
+ * @return
+ */
+ public Id getId();
+
+ /**
+ * The used underlying STAL instance
+ * @return
+ */
+ public STAL getSTAL();
+
+ public SLCommandInvoker getCommandInvoker();
+
+ public Date getLastAccessTime();
+
+ public void updateLastAccessTime();
+
+ public String getResultContentType();
+
+ public void writeResultTo(OutputStream os, String encoding) throws IOException;
+
+ public void init(STAL aStal, SLCommandInvoker aCommandInvoker, Configuration config);
+
+ /**
+ * Sets the preferred locale for userinteraction.
+ * If the locale is not set the default locale will be used.
+ * @param locale must not be null.
+ */
+ public void setLocale(Locale locale);
+
+ public boolean isFinished();
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/BindingProcessorManager.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/BindingProcessorManager.java
new file mode 100644
index 00000000..9cad95a4
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/BindingProcessorManager.java
@@ -0,0 +1,107 @@
+/*
+* 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.binding;
+
+import java.net.MalformedURLException;
+import java.util.Locale;
+import java.util.Set;
+
+import at.gv.egiz.bku.slcommands.SLCommandInvoker;
+import at.gv.egiz.stal.STALFactory;
+
+/**
+ * Central player that handles the protocol binding.
+ *
+ * @author wbauer
+ *
+ */
+public interface BindingProcessorManager {
+
+ /**
+ * FactoryMethod creating a new BindingProcessor object.
+ * The created binding processor must be passed to the process method to execute.
+ *
+ * @param urlString
+ * the source url
+ * @param aSessionId
+ * optional an external sessionId (e.g. http session) could be
+ * provided. This parameter may be null.
+ * @param locale the locale used for user interaction, may be null
+ */
+ public BindingProcessor createBindingProcessor(String urlString,
+ String aSessionId, Locale locale) throws MalformedURLException;
+
+ /**
+ * FactoryMethod creating a new BindingProcessor object.
+ * The created binding processor must be passed to the process method to execute.
+ *
+ * @param protcol
+ * the source url
+ * @param aSessionId
+ * optional an external sessionId (e.g. http session) could be
+ * provided. This parameter may be null.
+ */
+ public BindingProcessor createBindingProcessor(String urlString,
+ String aSessionId) throws MalformedURLException;
+
+
+ /**
+ * Gets the binding processor with a certain id. The binding processor must be passed to the
+ * process method before it is managed and thus returned by this method.
+ * @param aId must not be null
+ * @return null if the binding processor was not "processed" before.
+ */
+ public BindingProcessor getBindingProcessor(Id aId);
+
+ /**
+ * Sets the STAL factory that is used for creating STAL objects that are used by BindingProcessor objects.
+ * For each new BindingProcessor a new STAL object is created.
+ * @param aStalFactory the factory to be used. Must not be null.
+ */
+ public void setSTALFactory(STALFactory aStalFactory);
+
+ /**
+ * Sets the invoker to be used.
+ * @param invoker
+ */
+ public void setSLCommandInvoker(SLCommandInvoker invoker);
+
+ /**
+ * Creates a processing context,
+ * schedules the provided binding processor for processing and
+ * immediately returns the context.
+ *
+ * @param aBindingProcessor
+ */
+ public ProcessingContext process(BindingProcessor aBindingProcessor);
+
+ /**
+ * Removes a formerly added (by calling the process method) binding processor.
+ * @param bindingProcessor must not be null
+ */
+ public void removeBindingProcessor(Id sessionId);
+
+ /**
+ * A set of all managed binding processors.
+ * @return
+ */
+ public Set<Id> getManagedIds();
+
+ public void shutdown();
+
+ public void shutdownNow();
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/BindingProcessorManagerImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/BindingProcessorManagerImpl.java
new file mode 100644
index 00000000..bf9a63e2
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/BindingProcessorManagerImpl.java
@@ -0,0 +1,330 @@
+/*
+ * 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.binding;
+
+import at.gv.egiz.bku.conf.Configuration;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.slcommands.SLCommandInvoker;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+import at.gv.egiz.bku.utils.binding.Protocol;
+import at.gv.egiz.stal.STAL;
+import at.gv.egiz.stal.STALFactory;
+
+/**
+ * This class maintains all active BindingProcessor Objects. Currently, only
+ * HTTPBinding is supported.
+ */
+public class BindingProcessorManagerImpl implements BindingProcessorManager {
+
+ public final static Protocol[] SUPPORTED_PROTOCOLS = { Protocol.HTTP,
+ Protocol.HTTPS };
+
+ private static Log log = LogFactory.getLog(BindingProcessorManagerImpl.class);
+
+ /** spring injected config
+ * Passed to created bindingprocessors, to replace their configuration */
+ protected Configuration config;
+
+ protected STALFactory stalFactory;
+ protected SLCommandInvoker commandInvokerClass;
+
+ private RemovalStrategy removalStrategy;
+ private ExecutorService executorService;
+ private Map<Id, ProcessingContext> contextMap = Collections.synchronizedMap(new HashMap<Id, ProcessingContext>());
+// private Map<Id, MapEntityWrapper> bindingProcessorMap = Collections
+// .synchronizedMap(new HashMap<Id, MapEntityWrapper>());
+
+ /**
+ * Container to hold a Future and Bindingprocessor object as map value.
+ *
+ * @author wbauer
+ * @see BindingProcessorManagerImpl#bindingProcessorMap
+ */
+// static class MapEntityWrapper {
+// private Future<?> future;
+// private BindingProcessor bindingProcessor;
+//
+// public MapEntityWrapper(Future<?> future, BindingProcessor bindingProcessor) {
+// if ((bindingProcessor == null) || (future == null)) {
+// throw new NullPointerException("Argument must not be null");
+// }
+// this.bindingProcessor = bindingProcessor;
+// this.future = future;
+// }
+//
+// public Future<?> getFuture() {
+// return future;
+// }
+//
+// public BindingProcessor getBindingProcessor() {
+// return bindingProcessor;
+// }
+//
+// public int hashCode() {
+// return bindingProcessor.getId().hashCode();
+// }
+//
+// public boolean equals(Object other) {
+// if (other instanceof MapEntityWrapper) {
+// MapEntityWrapper o = (MapEntityWrapper) other;
+// return (o.bindingProcessor.getId().equals(bindingProcessor.getId()));
+// } else {
+// return false;
+// }
+// }
+// }
+
+ /**
+ *
+ * @param fab
+ * must not be null
+ * @param ci
+ * must not be null (prototype to generate new instances)
+ */
+ public BindingProcessorManagerImpl(STALFactory fab, SLCommandInvoker ci, Configuration conf) {
+ if (fab == null) {
+ throw new NullPointerException("STALFactory must not be null");
+ }
+ stalFactory = fab;
+ if (ci == null) {
+ throw new NullPointerException("SLCommandInvoker must not be null");
+ }
+ commandInvokerClass = ci;
+ config = conf;
+ executorService = Executors.newCachedThreadPool();
+ }
+
+ /**
+ *
+ * @return the STALFactory currently used.
+ */
+ public STALFactory getStalFactory() {
+ return stalFactory;
+ }
+
+ /**
+ * Sets the STALFactory to be used.
+ *
+ * @param stalFactory
+ */
+ public void setStalFactory(STALFactory stalFactory) {
+ this.stalFactory = stalFactory;
+ }
+
+ /**
+ * Could be used to setup a new executor service during application stratup.
+ *
+ * @param executorService
+ */
+ public void setExecutorService(ExecutorService executorService) {
+ this.executorService = executorService;
+ }
+
+ public void setRemovalStrategy(RemovalStrategy aStrategy) {
+ removalStrategy = aStrategy;
+ }
+
+ public RemovalStrategy getRemovlaStrategy() {
+ return removalStrategy;
+ }
+
+ public void shutdown() {
+ log.info("Shutting down the BindingProcessorManager");
+ executorService.shutdown();
+ }
+
+ public void shutdownNow() {
+ log.info("Shutting down the BindingProcessorManager NOW!");
+ executorService.shutdownNow();
+ log.debug("Number of binding contexts currently managed: "
+ + contextMap.size());
+// + bindingProcessorMap.size());
+ if (log.isDebugEnabled()) {
+ for (ProcessingContext ctx : contextMap.values()) {
+ Id bpId = ctx.getBindingProcessor().getId();
+ Future future = ctx.getFuture();
+ log.debug(bpId + " cancelled: " + future.isCancelled());
+ log.debug(bpId + " done: " + future.isDone());
+ }
+// for (Iterator<MapEntityWrapper> it = bindingProcessorMap.values()
+// .iterator(); it.hasNext();) {
+// MapEntityWrapper entry = it.next();
+// log.debug(entry.getBindingProcessor().getId() + ": isDone: "
+// + entry.getFuture().isDone());
+// log.debug(entry.getBindingProcessor().getId() + ": isCanceled: "
+// + entry.getFuture().isCancelled());
+// }
+ }
+ }
+
+ /**
+ * Uses the default locale
+ */
+ public BindingProcessor createBindingProcessor(String srcUrl,
+ String aSessionId) throws MalformedURLException {
+ return createBindingProcessor(srcUrl, aSessionId, null);
+ }
+
+ /**
+ * FactoryMethod creating a new BindingProcessor object.
+ *
+ * @param protocol
+ * must not be null
+ * @throws MalformedURLException
+ */
+ public BindingProcessor createBindingProcessor(String srcUrl,
+ String aSessionId, Locale locale) throws MalformedURLException {
+ URL url = new URL(srcUrl);
+ String low = url.getProtocol().toLowerCase();
+ Protocol proto = null;
+ for (int i = 0; i < SUPPORTED_PROTOCOLS.length; i++) {
+ if (SUPPORTED_PROTOCOLS[i].toString().equals(low)) {
+ proto = SUPPORTED_PROTOCOLS[i];
+ break;
+ }
+ }
+ if (proto == null) {
+ throw new UnsupportedOperationException();
+ }
+ BindingProcessor bindingProcessor = new HTTPBindingProcessor(aSessionId,
+ commandInvokerClass.newInstance(), url);
+ stalFactory.setLocale(locale);
+ STAL stal = stalFactory.createSTAL();
+ bindingProcessor.init(stal, commandInvokerClass.newInstance(), config);
+ if (locale != null) {
+ bindingProcessor.setLocale(locale);
+// stal.setLocale(locale);
+ }
+ return bindingProcessor;
+ }
+
+ /**
+ * @return the bindingprocessor object for this id or null if no
+ * bindingprocessor was found.
+ */
+ @Override
+ public BindingProcessor getBindingProcessor(Id aId) {
+// if (bindingProcessorMap.get(aId) != null) {
+// return bindingProcessorMap.get(aId).getBindingProcessor();
+ ProcessingContext ctx = contextMap.get(aId);
+ if (ctx != null) {
+ return ctx.getBindingProcessor();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ *
+ */
+ @Override
+ public void setSTALFactory(STALFactory aStalFactory) {
+ if (aStalFactory == null) {
+ throw new NullPointerException("Cannot set STALFactory to null");
+ }
+ stalFactory = aStalFactory;
+ }
+
+ /**
+ * Causes the BindingProcessorManager to manage the provided BindingProcessor
+ * Creates a processing context,
+ * schedules the provided binding processor for processing and
+ * immediately returns the context.
+ *
+ * @param aBindingProcessor
+ * must not be null
+ */
+ @Override
+ public ProcessingContext process(BindingProcessor aBindingProcessor) {
+ if (contextMap.containsKey(aBindingProcessor.getId())) {
+// if (bindingProcessorMap.containsKey(aBindingProcessor.getId())) {
+ log.fatal("Clashing ids, cannot process bindingprocessor with id:"
+ + aBindingProcessor.getId());
+ throw new SLRuntimeException(
+ "Clashing ids, cannot process bindingprocessor with id:"
+ + aBindingProcessor.getId());
+ }
+ log.debug("processing bindingprocessor: " + aBindingProcessor.getId());
+ Future<?> f = executorService.submit(aBindingProcessor);
+ ProcessingContext ctx = new ProcessingContext(aBindingProcessor, f);
+ contextMap.put(aBindingProcessor.getId(), ctx);
+// bindingProcessorMap.put(aBindingProcessor.getId(), new MapEntityWrapper(f,
+// aBindingProcessor));
+ return ctx;
+ }
+
+ @Override
+ public void setSLCommandInvoker(SLCommandInvoker invoker) {
+ commandInvokerClass = invoker;
+ }
+
+ @Override
+ public void removeBindingProcessor(Id sessionId) {
+ log.debug("Removing binding processor: " + sessionId);
+ ProcessingContext ctx = contextMap.get(sessionId);
+ if (ctx == null) {
+ log.warn("no processing context to remove for session " + sessionId);
+ return;
+ }
+ Future f = ctx.getFuture();
+
+// MapEntityWrapper wrapper = bindingProcessorMap.get(sessionId);
+// if (wrapper == null) {
+// return;
+// }
+// Future<?> f = wrapper.getFuture();
+
+ if (!f.isDone()) {
+ log.trace("canceling " + sessionId);
+ f.cancel(true);
+ }
+ contextMap.remove(sessionId);
+// bindingProcessorMap.remove(sessionId);
+ }
+
+ @Override
+ public Set<Id> getManagedIds() {
+ Set<Id> result = new HashSet<Id>();
+ synchronized (contextMap) {
+ for (Id id : contextMap.keySet()) {
+ result.add(id);
+ }
+ }
+// synchronized (bindingProcessorMap) {
+// for (Iterator<Id> it = bindingProcessorMap.keySet().iterator(); it
+// .hasNext();) {
+// result.add(it.next());
+// }
+// }
+ return result;
+ }
+} \ No newline at end of file
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
new file mode 100644
index 00000000..d3945253
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrl.java
@@ -0,0 +1,111 @@
+/*
+ * 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.binding;
+
+import at.gv.egiz.bku.conf.Configurator;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Properties;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+
+/**
+ * Used to handle DataUrl connections as specified in the CCE's HTTP protocol binding.
+ *
+ */
+public class DataUrl {
+
+ private static Log log = LogFactory.getLog(DataUrl.class);
+ private static DataUrlConnectionSPI connection;
+ private static Properties configuration;
+ private static SSLSocketFactory sslSocketFactory;
+ private static HostnameVerifier hostNameVerifier;
+ private URL url;
+
+ /** spring injected config, to replace configuration */
+ //private Configuration config;
+
+ /**
+ * Sets the default DataUrlConnection implementation
+ * @param aClass must not be null
+ */
+ static void setDataUrlConnectionImpl(DataUrlConnectionSPI conn) {
+ if (conn != null) {
+ connection = conn;
+ }
+ }
+
+ public DataUrl(String aUrlString) throws MalformedURLException {
+ url = new URL(aUrlString);
+ if (connection == null) {
+ log.debug("Using default DataURLConnection class");
+ connection = new DataUrlConnectionImpl();
+ }
+ connection.setConfiguration(configuration);
+ connection.setSSLSocketFactory(sslSocketFactory);
+ connection.setHostnameVerifier(hostNameVerifier);
+ }
+
+ public DataUrlConnection openConnection() {
+ try {
+ log.debug("Opening dataurl connection");
+ DataUrlConnectionSPI retVal = connection.newInstance();
+ retVal.init(url);
+ return retVal;
+ } catch (Exception e) {
+ log.error(e);
+ throw new SLRuntimeException("Cannot instantiate a dataurlconnection:", e);
+ }
+ }
+
+
+ /**
+ * set configuration for all subsequently instantiated DataURL objects
+ * @param props
+ */
+ public static void setConfiguration(Properties props) {
+ configuration = props;
+ if (configuration != null) {
+ String className = configuration.getProperty(Configurator.DATAURLCONNECTION_CONFIG_P);
+ if (className != null) {
+ log.warn("Set DataURLConnection class not supported!");
+ }
+ }
+ }
+
+ /**
+ * set SSLSocketFactory for all subsequently instantiated DataURL objects
+ * @param socketFactory
+ */
+ public static void setSSLSocketFactory(SSLSocketFactory socketFactory) {
+ sslSocketFactory = socketFactory;
+ }
+
+ /**
+ * set HostnameVerifier for all subsequently instantiated DataURL objects
+ * @param hostNameVerifier
+ */
+ public static void setHostNameVerifier(HostnameVerifier hostNameVerifier) {
+ DataUrl.hostNameVerifier = hostNameVerifier;
+ }
+} \ No newline at end of file
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
new file mode 100644
index 00000000..384cf71c
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnection.java
@@ -0,0 +1,82 @@
+/*
+* 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.binding;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.security.cert.X509Certificate;
+
+import at.gv.egiz.bku.slcommands.SLResult;
+
+/**
+ * Transmit a security layer result to DataURL via HTTP POST, encoded as multipart/form-data.
+ * The HTTP header user-agent is set to <em>citizen-card-environment/1.2 BKU2 1.0</em>.
+ * The form-parameter ResponseType is set to <em>HTTP-Security-Layer-RESPONSE</em>.
+ * All other headers/parameters are set by the caller.
+ *
+ * @author clemens
+ */
+public interface DataUrlConnection {
+
+ public static final String FORMPARAM_RESPONSETYPE = "ResponseType";
+ public static final String DEFAULT_RESPONSETYPE = "HTTP-Security-Layer-RESPONSE";
+ public static final String FORMPARAM_XMLRESPONSE = "XMLResponse";
+ public static final String FORMPARAM_BINARYRESPONSE = "BinaryResponse";
+
+ public static final String XML_RESPONSE_ENCODING = "UTF-8";
+
+
+ public String getProtocol();
+
+ public URL getUrl();
+
+ /**
+ * Set a HTTP Header.
+ * @param key
+ * @param value multiple values are assumed to have the correct formatting (comma-separated list)
+ */
+ public void setHTTPHeader(String key, String value);
+
+ /**
+ * Set a form-parameter.
+ * @param name
+ * @param data
+ * @param contentType may be null
+ * @param charSet may be null
+ * @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
+ * @throws java.io.IOException
+ */
+ public void connect() throws SocketTimeoutException, IOException;
+
+ public X509Certificate getServerCertificate();
+
+ /**
+ * @pre connection != null
+ * @throws java.io.IOException
+ */
+ public void transmit(SLResult slResult) throws IOException;
+
+ public DataUrlResponse getResponse() throws IOException;
+} \ No newline at end of file
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
new file mode 100644
index 00000000..82c1be53
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionImpl.java
@@ -0,0 +1,539 @@
+/*
+ * 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.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;
+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.httpclient.methods.multipart.FilePart;
+import org.apache.commons.httpclient.methods.multipart.Part;
+import org.apache.commons.httpclient.methods.multipart.StringPart;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.binding.multipart.InputStreamPartSource;
+import at.gv.egiz.bku.binding.multipart.SLResultPart;
+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;
+
+/**
+ * An implementation of the DataUrlConnectionSPI that supports
+ * <code>multipart/form-data</code> encoding and
+ * <code>application/x-www-form-urlencoded</code> 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 <code>application/x-www-form-urlencoded</code> instead of
+ * standard conform <code>application/x-www-form-urlencoded</code>.
+ */
+ 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<String, String> requestHttpHeaders;
+
+ /**
+ * The HTTP form parameters.
+ */
+ protected ArrayList<HTTPFormParameter> 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;
+ }
+ return protocol.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.bku.binding.DataUrlConnection#connect()
+ */
+ public void connect() throws SocketTimeoutException, IOException {
+ connection = (HttpURLConnection) url.openConnection();
+ if (connection instanceof HttpsURLConnection) {
+ log.trace("Detected ssl connection");
+ HttpsURLConnection https = (HttpsURLConnection) connection;
+ if (sslSocketFactory != null) {
+ log.debug("Setting custom ssl socket factory for ssl connection");
+ https.setSSLSocketFactory(sslSocketFactory);
+ } else {
+ log.trace("No custom socket factory set");
+ }
+ if (hostnameVerifier != null) {
+ log.debug("Setting custom hostname verifier");
+ https.setHostnameVerifier(hostnameVerifier);
+ }
+ } else {
+ 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<String> headers = requestHttpHeaders.keySet();
+ Iterator<String> 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];
+ }
+ }
+ }
+
+ /* (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) {
+ // if a content type is specified we have to switch to multipart/formdata encoding
+ if (contentType != null && contentType.length() > 0) {
+ urlEncoded = false;
+ }
+ httpFormParameter.add(new HTTPFormParameter(name, data, contentType,
+ charSet, transferEncoding));
+ }
+
+
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.bku.binding.DataUrlConnection#transmit(at.gv.egiz.bku.slcommands.SLResult)
+ */
+ public void transmit(SLResult slResult) throws IOException {
+ 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()
+ : "UTF-8");
+ // Note, using UTF-8 as fallback for decoding is safe.
+ // If the request was x-www-form-urlencoded,
+ // UTF-8 has been used for encoding of non-ASCII characters.
+ // If the request was multipart/form-data and contains any transfer parameters,
+ // the data URL request is going to be multipart/form-data encoded (see below).
+ while ((len = reader.read(cbuf)) != -1) {
+ urlEnc.write(cbuf, 0, len);
+ }
+ urlEnc.flush();
+ }
+ streamWriter.close();
+
+ } else {
+ //
+ // multipart/form-data (conforming to SL 1.2)
+ //
+
+ ArrayList<Part> parts = new ArrayList<Part>();
+
+ // 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 {
+ is = connection.getInputStream();
+ } catch (IOException iox) {
+ log.info(iox);
+ }
+ log.trace("Reading response");
+ result = new DataUrlResponse(url.toString(), connection.getResponseCode(),
+ is);
+ Map<String, String> responseHttpHeaders = new HashMap<String, String>();
+ Map<String, List<String>> httpHeaders = connection.getHeaderFields();
+ for (Iterator<String> 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;
+ boundary = "--" + IdFactory.getInstance().createId().toString();
+ requestHttpHeaders = new HashMap<String, String>();
+
+ if (config != null) {
+ String version = config.getProperty(Configurator.SIGNATURE_LAYOUT);
+ if ((version != null) && (!"".equals(version.trim()))) {
+ log.debug("setting SignatureLayout header to " + version);
+ requestHttpHeaders.put(Configurator.SIGNATURE_LAYOUT, version);
+ } else {
+ log.debug("do not set SignatureLayout header");
+ }
+ String userAgent = config.getProperty(Configurator.USERAGENT_CONFIG_P, Configurator.USERAGENT_DEFAULT);
+ requestHttpHeaders.put(HttpUtil.HTTP_HEADER_USER_AGENT, userAgent);
+ } else {
+ requestHttpHeaders
+ .put(HttpUtil.HTTP_HEADER_USER_AGENT, Configurator.USERAGENT_DEFAULT);
+
+ }
+
+ httpFormParameter = new ArrayList<HTTPFormParameter>();
+
+ }
+
+ @Override
+ public DataUrlConnectionSPI newInstance() {
+ DataUrlConnectionSPI uc = new DataUrlConnectionImpl();
+ 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;
+ }
+
+ 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/DataUrlConnectionSPI.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionSPI.java
new file mode 100644
index 00000000..f838b919
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlConnectionSPI.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.bku.binding;
+
+import java.net.URL;
+import java.util.Properties;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Prototype of a DataurlconnectionSPI
+ * @author wbauer
+ *
+ */
+public interface DataUrlConnectionSPI extends DataUrlConnection {
+
+ /**
+ * Returns a new instance of this class to handle a dataurl.
+ * Called by the factory each time the openConnection method is called.
+ * @return
+ */
+ public DataUrlConnectionSPI newInstance();
+
+ /**
+ * Initializes the DataUrlConnection
+ * @param url
+ */
+ public void init(URL url);
+
+ /**
+ * Sets configuration parameters for this connection
+ * @param config
+ */
+ public void setConfiguration(Properties config);
+
+ /**
+ * Sets the socketfactory to be used for ssl connections.
+ * @param socketFactory if null the socket factory will not be set explicitly
+ */
+ public void setSSLSocketFactory(SSLSocketFactory socketFactory);
+
+ /**
+ * Sets the hostname verifier to be used,
+ * @param hostnameVerifier if null the default hostname verifier will be used
+ */
+ public void setHostnameVerifier(HostnameVerifier hostnameVerifier);
+
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlResponse.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlResponse.java
new file mode 100644
index 00000000..b75cb0f3
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/DataUrlResponse.java
@@ -0,0 +1,98 @@
+/*
+* 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.binding;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.util.Iterator;
+import java.util.Map;
+
+import at.gv.egiz.bku.utils.urldereferencer.StreamData;
+
+/**
+ * The response of a dataurl server.
+ * Additionally holds return code and response headers.
+ */
+public class DataUrlResponse extends StreamData {
+
+ public final static String OK = "<ok/>";
+
+ protected Map<String, String> responseHttpHeaders;
+
+ protected int responseCode = -1;
+
+ public DataUrlResponse(String url, int responseCode, InputStream stream) {
+ super(url, null, new PushbackInputStream(stream, 10));
+ this.responseCode = responseCode;
+ }
+
+ public String getContentType() {
+ if (contentType != null) {
+ return contentType;
+ }
+ if (responseHttpHeaders == null) {
+ return null;
+ }
+ for (Iterator<String> keyIt = responseHttpHeaders.keySet().iterator(); keyIt
+ .hasNext();) {
+ String key = keyIt.next();
+ if (HttpUtil.HTTP_HEADER_CONTENT_TYPE.equalsIgnoreCase(key)) {
+ contentType = responseHttpHeaders.get(key);
+ return contentType;
+ }
+ }
+ return contentType;
+ }
+
+ public void setResponseHttpHeaders(Map<String, String> responseHttpHeaders) {
+ this.responseHttpHeaders = responseHttpHeaders;
+ }
+
+ public Map<String, String> getResponseHeaders() {
+ return responseHttpHeaders;
+ }
+
+ public int getResponseCode() {
+ return responseCode;
+ }
+
+ /**
+ * Checks if the http response equals "<ok/>"
+ *
+ * @throws IOException
+ */
+ public boolean isHttpResponseXMLOK() throws IOException {
+ String charset = HttpUtil.getCharset(contentType, true);
+ byte[] buffer = new byte[10];
+ int i = 0;
+ int read = 0;
+ while ((i < 10) && (read != -1)) {
+ read = inputStream.read(buffer, i, 10 - i);
+ if (read != -1) {
+ i += read;
+ }
+ }
+ PushbackInputStream pbis = (PushbackInputStream) inputStream;
+ pbis.unread(buffer, 0, i);
+ if (i < 5) {
+ return false;
+ }
+ String ok = new String(buffer, 0, i, charset);
+ return (OK.equals(ok));
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/ExpiryRemover.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/ExpiryRemover.java
new file mode 100644
index 00000000..d17a27c2
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/ExpiryRemover.java
@@ -0,0 +1,67 @@
+/*
+* 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.binding;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class can be used to check the BindingProcessorManager for expired entries and remove them.
+ * Should be run periodically.
+ *
+ */
+public class ExpiryRemover implements RemovalStrategy {
+
+ private static Log log = LogFactory.getLog(ExpiryRemover.class);
+
+ protected BindingProcessorManager bindingProcessorManager;
+ // keep max 5 min.
+ protected long maxAcceptedAge = 1000 * 60 * 5;
+
+ @Override
+ public void execute() {
+ log.debug("Triggered Expiry Remover");
+ if (bindingProcessorManager == null) {
+ log.warn("Bindingprocessor not set, skipping removal");
+ return;
+ }
+ Set<Id> managedIds = bindingProcessorManager.getManagedIds();
+ for (Iterator<Id> it = managedIds.iterator(); it.hasNext();) {
+ Id bindId = it.next();
+ BindingProcessor bp = bindingProcessorManager.getBindingProcessor(bindId);
+ if (bp != null) {
+ if (bp.getLastAccessTime().getTime() < (System.currentTimeMillis() - maxAcceptedAge)) {
+ log.debug("Removing binding processor: " + bp.getId());
+ bindingProcessorManager.removeBindingProcessor(bp.getId());
+ }
+ }
+ }
+ }
+
+ public void setMaxAcceptedAge(long maxAcceptedAge) {
+ this.maxAcceptedAge = maxAcceptedAge;
+ }
+
+ @Override
+ public void setBindingProcessorManager(BindingProcessorManager bp) {
+ bindingProcessorManager = bp;
+ }
+
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/FixedFormParameters.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/FixedFormParameters.java
new file mode 100644
index 00000000..cce3d720
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/FixedFormParameters.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.bku.binding;
+
+/**
+ * Form parameters with special meaning as defined in the CCE's http binding.
+ *
+ */
+public interface FixedFormParameters {
+ String XMLREQUEST = "XMLRequest";
+ String REDIRECTURL = "RedirectURL";
+ String DATAURL = "DataURL";
+ String STYLESHEETURL = "StylesheetURL";
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/FormParameter.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/FormParameter.java
new file mode 100644
index 00000000..93339451
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/FormParameter.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.binding;
+
+import java.io.InputStream;
+import java.util.Iterator;
+
+/**
+ * Interface to access form control contents from the http request.
+ * It's designed to be used for URL encoded and multipart-formdata requests.
+ * @author wbauer
+ *
+ */
+public interface FormParameter {
+
+ String getFormParameterName();
+
+ InputStream getFormParameterValue();
+
+ String getFormParameterContentType();
+
+ Iterator<String> getHeaderNames();
+
+ String getHeaderValue(String headerName);
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/FormParameterImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/FormParameterImpl.java
new file mode 100644
index 00000000..45aa9be6
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/FormParameterImpl.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.binding;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.apache.commons.fileupload.FileItemHeaders;
+
+/**
+ * Simple wrapper to read data while consuming an stream within the http
+ * processor.
+ *
+ *
+ */
+public class FormParameterImpl implements FormParameter {
+
+ protected InputStream dataStream;
+ protected String contentType;
+ protected String formName;
+ protected FileItemHeaders headers;
+
+ public FormParameterImpl(String contentType, String formName, InputStream is,
+ FileItemHeaders header) {
+ this.contentType = contentType;
+ this.formName = formName;
+ this.dataStream = is;
+ this.headers = header;
+ }
+
+ @Override
+ public String getFormParameterContentType() {
+ return contentType;
+ }
+
+ @Override
+ public String getFormParameterName() {
+ return formName;
+ }
+
+ @Override
+ public InputStream getFormParameterValue() {
+ return dataStream;
+ }
+
+ @Override
+ public String getHeaderValue(String headerName) {
+ if (headers == null) {
+ return null;
+ }
+ return headers.getHeader(headerName);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Iterator<String> getHeaderNames() {
+ if (headers == null) {
+ return Collections.EMPTY_LIST.iterator();
+ }
+ return headers.getHeaderNames();
+ }
+
+ public FileItemHeaders getHeaders() {
+ return headers;
+ }
+
+ public boolean equals(Object other) {
+ if (other instanceof FormParameter) {
+ FormParameter fp = (FormParameter) other;
+ return fp.getFormParameterName().equals(getFormParameterName());
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ return getFormParameterName().hashCode();
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/FormParameterStore.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/FormParameterStore.java
new file mode 100644
index 00000000..8b6cd4b2
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/FormParameterStore.java
@@ -0,0 +1,146 @@
+/*
+* 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.binding;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.apache.commons.fileupload.FileItemHeaders;
+import org.apache.commons.fileupload.util.FileItemHeadersImpl;
+
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+import at.gv.egiz.bku.utils.StreamUtil;
+
+/**
+ * Simple store for form parameters based on a byte[]
+ *
+ * @author wbauer
+ *
+ */
+public class FormParameterStore implements FormParameter {
+
+ private byte[] dataBuffer;
+ private String contentType;
+ private String parameterName;
+ private boolean initialized = false;
+ protected FileItemHeaders headers;
+
+ /**
+ * Make sure to call init after creating a new instance.
+ */
+ public FormParameterStore() {
+ }
+
+ public void init(InputStream dataSource, String paramName,
+ String contentType, FileItemHeaders header) throws IOException {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ StreamUtil.copyStream(dataSource, os);
+ this.dataBuffer = os.toByteArray();
+ this.parameterName = paramName;
+ this.contentType = contentType;
+ initialized = true;
+ this.headers = header;
+ }
+
+ public void init(byte[] dataSource, String paramName,
+ String contentType, FileItemHeaders header) throws IOException {
+ this.dataBuffer = dataSource;
+ this.parameterName = paramName;
+ this.contentType = contentType;
+ initialized = true;
+ this.headers = header;
+ }
+
+ public void init(FormParameter fp) throws IOException {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ StreamUtil.copyStream(fp.getFormParameterValue(), os);
+ this.dataBuffer = os.toByteArray();
+ this.parameterName = fp.getFormParameterName();
+ this.contentType = fp.getFormParameterContentType();
+ if (fp instanceof FormParameterImpl) {
+ headers = ((FormParameterImpl) fp).getHeaders();
+ } else {
+ FileItemHeadersImpl headersImpl = new FileItemHeadersImpl();
+ for (Iterator<String> i = fp.getHeaderNames(); i.hasNext();) {
+ String headerName = i.next();
+ headersImpl.addHeader(headerName, fp.getHeaderValue(headerName));
+ }
+ }
+ initialized = true;
+ }
+
+ protected void ensureInitialized() {
+ if (!initialized) {
+ throw new SLRuntimeException("FormParameterStore not initialized");
+ }
+ }
+
+ /**
+ * Reads all data from the stream and stores it internally. The stream will
+ * not be closed.
+ *
+ * @param datSource
+ * @param formName
+ * @param contentType
+ */
+ @Override
+ public String getFormParameterContentType() {
+ ensureInitialized();
+ return contentType;
+ }
+
+ @Override
+ public String getFormParameterName() {
+ ensureInitialized();
+ return parameterName;
+ }
+
+ /**
+ * May be called more than once.
+ */
+ @Override
+ public InputStream getFormParameterValue() {
+ return new ByteArrayInputStream(dataBuffer);
+ }
+
+ @Override
+ public String getHeaderValue(String name) {
+ if (headers == null) {
+ return null;
+ }
+ return headers.getHeader(name);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Iterator<String> getHeaderNames() {
+ if (headers == null) {
+ return Collections.EMPTY_LIST.iterator();
+ }
+ return headers.getHeaderNames();
+ }
+
+ public boolean isEmpty() {
+ ensureInitialized();
+ return dataBuffer.length == 0;
+ }
+
+}
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
new file mode 100644
index 00000000..e39addb5
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java
@@ -0,0 +1,844 @@
+/*
+ * 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.binding;
+
+import iaik.utils.Base64InputStream;
+
+import java.io.IOException;
+import java.io.InputStream;
+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;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.net.ssl.SSLHandshakeException;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.stream.StreamResult;
+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;
+import at.gv.egiz.bku.slcommands.SLCommandInvoker;
+import at.gv.egiz.bku.slcommands.SLResult;
+import at.gv.egiz.bku.slcommands.SLSourceContext;
+import at.gv.egiz.bku.slcommands.SLTargetContext;
+import at.gv.egiz.bku.slcommands.impl.ErrorResultImpl;
+import at.gv.egiz.bku.slexceptions.SLBindingException;
+import at.gv.egiz.bku.slexceptions.SLException;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+import at.gv.egiz.bku.utils.StreamUtil;
+import at.gv.egiz.bku.utils.binding.Protocol;
+import at.gv.egiz.bku.utils.urldereferencer.FormDataURLSupplier;
+import at.gv.egiz.bku.utils.urldereferencer.SimpleFormDataContextImpl;
+import at.gv.egiz.bku.utils.urldereferencer.StreamData;
+import at.gv.egiz.bku.utils.urldereferencer.URIResolverAdapter;
+import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer;
+import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerContext;
+import at.gv.egiz.stal.QuitRequest;
+import at.gv.egiz.stal.STALRequest;
+
+/**
+ * Class performing the HTTP binding as defined by the CCE specification.
+ * Currently a huge monolithic class.
+ *
+ * @TODO refactor
+ */
+@SuppressWarnings("unchecked")
+public class HTTPBindingProcessor extends AbstractBindingProcessor implements
+ FormDataURLSupplier {
+
+ private static Log log = LogFactory.getLog(HTTPBindingProcessor.class);
+
+ private static enum State {
+ INIT, PROCESS, DATAURL, TRANSFORM, FINISHED
+ };
+
+ public final static Collection<String> XML_REQ_TRANSFER_ENCODING = Arrays
+ .asList(new String[] { "binary" });
+
+ protected static String XML_MIME_TYPE = "text/xml";
+ protected static String BINARY_MIME_TYPE = "application/octet-stream";
+
+ /**
+ * If null everything is ok and the result is taken from the command invoker.
+ */
+ protected SLException bindingProcessorError;
+ protected SLCommandInvoker commandInvoker;
+ protected DataUrlResponse dataUrlResponse;
+ protected Map<String, String> headerMap = Collections.EMPTY_MAP;
+ protected SLCommand slCommand;
+ protected Map<String, FormParameter> formParameterMap = new HashMap<String, FormParameter>();
+ protected SLSourceContext srcContex = new SLSourceContext();
+ protected SLTargetContext targetContext = new SLTargetContext();
+ protected URL srcUrl;
+ protected State currentState = State.INIT;
+ protected Templates templates = null;
+ protected String resultContentType = null;
+ protected SLResult slResult = null;
+ protected int responseCode = 200;
+ protected Map<String, String> responseHeaders = Collections.EMPTY_MAP;
+ protected Locale locale = Locale.getDefault();
+ protected boolean finished = false;
+
+ /**
+ *
+ * @param id
+ * may be null. In this case a new session id will be created.
+ * @param cmdInvoker
+ * must not be null;
+ */
+ public HTTPBindingProcessor(String id, SLCommandInvoker cmdInvoker, URL source) {
+ super(id);
+ this.srcUrl = source;
+ Protocol protocol = Protocol.fromString(source.getProtocol());
+ if ((protocol != Protocol.HTTP) && (protocol != Protocol.HTTPS)) {
+ throw new SLRuntimeException("Protocol not supported: " + protocol);
+ }
+ if (cmdInvoker == null) {
+ throw new NullPointerException("Commandinvoker cannot be set to null");
+ }
+ commandInvoker = cmdInvoker;
+ srcContex.setSourceUrl(source);
+ srcContex.setSourceIsDataURL(false);
+ }
+
+ //----------------------------------------------------------------------------
+ // ----------- BEGIN CONVENIENCE METHODS -----------
+
+ protected void sendSTALQuit() {
+ log.info("Sending QUIT command to STAL");
+ List<STALRequest> quit = new ArrayList<STALRequest>(1);
+ quit.add(new QuitRequest());
+ getSTAL().handleRequest(quit);
+ }
+
+ protected String getFormParameterAsString(String formParameterName) {
+ FormParameter fp = formParameterMap.get(formParameterName);
+ return getFormParameterAsString(fp);
+ }
+
+ protected String getFormParameterAsString(FormParameter fp) {
+ if (fp == null) {
+ return null;
+ }
+ try {
+ return StreamUtil.asString(fp.getFormParameterValue(), HttpUtil
+ .getCharset(fp.getFormParameterContentType(), true));
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ protected String getDataUrl() {
+ return getFormParameterAsString(FixedFormParameters.DATAURL);
+ }
+
+ protected String getStyleSheetUrl() {
+ return getFormParameterAsString(FixedFormParameters.STYLESHEETURL);
+ }
+
+ protected List<FormParameter> getFormParameters(String parameterNamePostfix) {
+ List<FormParameter> resultList = new ArrayList<FormParameter>();
+ for (Iterator<String> fpi = formParameterMap.keySet().iterator(); fpi
+ .hasNext();) {
+ String paramName = fpi.next();
+ if (paramName.endsWith(parameterNamePostfix)) {
+ resultList.add(formParameterMap.get(paramName));
+ }
+ }
+ return resultList;
+ }
+
+ protected List<FormParameter> getTransferHeaders() {
+ return getFormParameters("__");
+ }
+
+ protected List<FormParameter> getTransferForms() {
+ List<FormParameter> resultList = new ArrayList<FormParameter>();
+ for (Iterator<String> fpi = formParameterMap.keySet().iterator(); fpi
+ .hasNext();) {
+ String paramName = fpi.next();
+ if ((paramName.endsWith("_")) && (!paramName.endsWith("__"))) {
+ resultList.add(formParameterMap.get(paramName));
+ }
+ }
+ return resultList;
+ }
+
+ protected void closeDataUrlConnection() {
+ log.debug("Closing data url input stream");
+ if (dataUrlResponse == null) {
+ return;
+ }
+ InputStream is = dataUrlResponse.getStream();
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ log.info("Error closing input stream to dataurl server:" + e);
+ }
+ }
+ }
+
+ //----------------------------------------------------------------------------
+ // ----------- END CONVENIENCE METHODS -----------
+
+ //----------------------------------------------------------------------------
+ // -- BEGIN Methods that handle the http binding activities as defined in the
+ // activity diagram --
+
+ protected void init() {
+ log.info("Starting Bindingprocessor in Thread: "
+ + Thread.currentThread().getId());
+ if (bindingProcessorError != null) {
+ log.debug("Detected binding processor error, sending quit command");
+ // sendSTALQuit();
+ currentState = State.FINISHED;
+ } else if (slCommand == null) {
+ log.error("SLCommand not set (consumeRequest not called ??)");
+ bindingProcessorError = new SLException(2000);
+ // sendSTALQuit();
+ currentState = State.FINISHED;
+ } else {
+ currentState = State.PROCESS;
+ }
+ }
+
+ protected void processRequest() {
+ log.debug("Entered State: " + State.PROCESS);
+ log.debug("Processing command: " + slCommand);
+ commandInvoker.setCommand(slCommand);
+ responseCode = 200;
+ responseHeaders = Collections.EMPTY_MAP;
+ dataUrlResponse = null;
+ try {
+ commandInvoker.invoke(srcContex);
+ } catch (SLException e) {
+ log.info("Caught exception: " + e);
+ bindingProcessorError = e;
+ currentState = State.TRANSFORM;
+ }
+ if (getDataUrl() != null) {
+ log.debug("Data Url set to: " + getDataUrl());
+ currentState = State.DATAURL;
+ } else {
+ log.debug("No data url set");
+ currentState = State.TRANSFORM;
+ }
+ }
+
+ protected void handleDataUrl() {
+ log.debug("Entered State: " + State.DATAURL);
+ try {
+ DataUrl dataUrl = new DataUrl(getDataUrl());
+ DataUrlConnection conn = dataUrl.openConnection();
+
+ // set transfer headers
+ for (FormParameter fp : getTransferHeaders()) {
+ String paramString = getFormParameterAsString(fp);
+ if (paramString == null) {
+ log.error("Got empty transfer header, ignoring this");
+ } else {
+ String[] keyVal = paramString.split(":", 2);
+ String key = keyVal[0];
+ String val = null;
+ if (keyVal.length == 2) {
+ val = keyVal[1];
+ val = val.trim();
+ } else {
+ log.error("Invalid transfer header encoding: "+paramString);
+ throw new SLBindingException(2005);
+ }
+ log.debug("Setting header " + key + " to value " + val);
+ conn.setHTTPHeader(key, val);
+ }
+ }
+
+ // set transfer form parameters
+ for (FormParameter fp : getTransferForms()) {
+ String contentTransferEncoding = null;
+ String contentType = fp.getFormParameterContentType();
+ String charSet = HttpUtil.getCharset(contentType, false);
+ if (charSet != null) {
+ contentType = contentType.substring(0, contentType
+ .lastIndexOf(HttpUtil.SEPERATOR[0]));
+ }
+ for (Iterator<String> header = fp.getHeaderNames(); header.hasNext();) {
+ if (HttpUtil.CONTENT_TRANSFER_ENCODING
+ .equalsIgnoreCase(header.next())) {
+ contentTransferEncoding = getFormParameterAsString(fp);
+ }
+ }
+ log.debug("Setting form: " + fp.getFormParameterName()
+ + " contentType: " + contentType + " charset: " + charSet
+ + " contentTransferEncoding: " + contentTransferEncoding);
+ conn.setHTTPFormParameter(fp.getFormParameterName(), fp
+ .getFormParameterValue(), contentType, charSet,
+ contentTransferEncoding);
+ }
+
+ // connect
+ conn.connect();
+ // fetch and set SL result
+ targetContext.setTargetIsDataURL(true);
+ targetContext.setTargetCertificate(conn.getServerCertificate());
+ targetContext.setTargetUrl(conn.getUrl());
+ SLResult result = commandInvoker.getResult(targetContext);
+
+ // transfer result
+ conn.transmit(result);
+
+ // process Dataurl response
+ dataUrlResponse = conn.getResponse();
+ log.debug("Received data url response code: "
+ + dataUrlResponse.getResponseCode());
+
+ switch (dataUrlResponse.getResponseCode()) {
+ case 200:
+ String contentType = dataUrlResponse.getContentType();
+ log.debug("Got dataurl response content type: " + contentType);
+ if (contentType != null) {
+ if ((contentType.startsWith(HttpUtil.APPLICATION_URL_ENCODED))
+ || (contentType.startsWith(HttpUtil.MULTIPART_FOTMDATA))) {
+ log.debug("Detected SL Request in dataurl response");
+ // process headers and request
+ setHTTPHeaders(dataUrlResponse.getResponseHeaders());
+ consumeRequestStream(dataUrlResponse.getStream());
+ //TODO check for bindingProcessorError
+ closeDataUrlConnection();
+ srcContex.setSourceCertificate(conn.getServerCertificate());
+ srcContex.setSourceIsDataURL(true);
+ srcContex.setSourceUrl(conn.getUrl());
+ currentState = State.PROCESS;
+ } else if (((contentType.startsWith(HttpUtil.TXT_HTML))
+ || (contentType.startsWith(HttpUtil.TXT_PLAIN))
+ || (contentType.startsWith(HttpUtil.TXT_XML)))
+ && (dataUrlResponse.isHttpResponseXMLOK())) {
+ log.info("Dataurl response matches <ok/> with content type: "
+ + contentType);
+ currentState = State.TRANSFORM;
+
+ } else if ((contentType.startsWith(HttpUtil.TXT_XML))
+ && (!dataUrlResponse.isHttpResponseXMLOK())) {
+ log
+ .debug("Detected text/xml dataurl response with content != <ok/>");
+ headerMap.put(HttpUtil.HTTP_HEADER_CONTENT_TYPE, contentType);
+ assignXMLRequest(dataUrlResponse.getStream(), HttpUtil.getCharset(
+ contentType, true));
+ closeDataUrlConnection();
+ srcContex.setSourceCertificate(conn.getServerCertificate());
+ srcContex.setSourceIsDataURL(true);
+ srcContex.setSourceUrl(conn.getUrl());
+ currentState = State.PROCESS;
+ // just to be complete, actually not used
+ srcContex.setSourceHTTPReferer(dataUrlResponse.getResponseHeaders()
+ .get(HttpUtil.HTTP_HEADER_REFERER));
+ } else {
+ resultContentType = contentType;
+ responseHeaders = dataUrlResponse.getResponseHeaders();
+ responseCode = dataUrlResponse.getResponseCode();
+ currentState = State.FINISHED;
+ }
+ } else {
+ log.debug("Content type not set in dataurl response");
+ closeDataUrlConnection();
+ throw new SLBindingException(2007);
+ }
+
+ break;
+ case 307:
+ contentType = dataUrlResponse.getContentType();
+ if ((contentType != null) && (contentType.startsWith(HttpUtil.TXT_XML))) {
+ log.debug("Received dataurl response code 307 with XML content");
+ String location = dataUrlResponse.getResponseHeaders().get(
+ HttpUtil.HTTP_HEADER_LOCATION);
+ if (location == null) {
+ log
+ .error("Did not get a location header for a 307 data url response");
+ throw new SLBindingException(2003);
+ }
+ // consumeRequestStream(dataUrlResponse.getStream());
+ FormParameterStore fp = new FormParameterStore();
+ fp.init(location.getBytes(HttpUtil.DEFAULT_CHARSET),
+ FixedFormParameters.DATAURL, null, null);
+ formParameterMap.put(FixedFormParameters.DATAURL, fp);
+ headerMap.put(HttpUtil.HTTP_HEADER_CONTENT_TYPE, contentType);
+ assignXMLRequest(dataUrlResponse.getStream(), HttpUtil.getCharset(
+ dataUrlResponse.getContentType(), true));
+ closeDataUrlConnection();
+ srcContex.setSourceCertificate(conn.getServerCertificate());
+ srcContex.setSourceIsDataURL(true);
+ srcContex.setSourceUrl(conn.getUrl());
+ currentState = State.PROCESS;
+ // just to be complete, actually not used
+ srcContex.setSourceHTTPReferer(dataUrlResponse.getResponseHeaders()
+ .get(HttpUtil.HTTP_HEADER_REFERER));
+
+ } else {
+ log.debug("Received dataurl response code 307 non XML content: "
+ + dataUrlResponse.getContentType());
+ resultContentType = dataUrlResponse.getContentType();
+ currentState = State.FINISHED;
+ }
+ responseHeaders = dataUrlResponse.getResponseHeaders();
+ responseCode = dataUrlResponse.getResponseCode();
+ break;
+
+ case 301:
+ case 302:
+ case 303:
+ responseHeaders = dataUrlResponse.getResponseHeaders();
+ responseCode = dataUrlResponse.getResponseCode();
+ resultContentType = dataUrlResponse.getContentType();
+ currentState = State.FINISHED;
+ break;
+
+ default:
+ // issue error
+ log.info("Unexpected response code from dataurl server: "
+ + dataUrlResponse.getResponseCode());
+ throw new SLBindingException(2007);
+ }
+
+ } catch (SLException slx) {
+ bindingProcessorError = slx;
+ log.error("Error during dataurl communication");
+ resultContentType = HttpUtil.TXT_XML;
+ currentState = State.TRANSFORM;
+ } catch (SSLHandshakeException hx) {
+ bindingProcessorError = new SLException(2010);
+ log.info("Error during dataurl communication", hx);
+ resultContentType = HttpUtil.TXT_XML;
+ currentState = State.TRANSFORM;
+ } catch (IOException e) {
+ bindingProcessorError = new SLBindingException(2001);
+ log.error("Error while data url handling", e);
+ resultContentType = HttpUtil.TXT_XML;
+ currentState = State.TRANSFORM;
+ return;
+ }
+ }
+
+ protected void transformResult() {
+ log.debug("Entered State: " + State.TRANSFORM);
+ if (bindingProcessorError != null) {
+ resultContentType = HttpUtil.TXT_XML;
+ } else if (dataUrlResponse != null) {
+ resultContentType = dataUrlResponse.getContentType();
+ } else {
+ targetContext.setTargetIsDataURL(false);
+ targetContext.setTargetUrl(srcUrl);
+ try {
+ slResult = commandInvoker.getResult(targetContext);
+ resultContentType = slResult.getMimeType();
+ log
+ .debug("Successfully got SLResult from commandinvoker, setting mimetype to: "
+ + resultContentType);
+ } catch (SLException e) {
+ log.info("Cannot get result from invoker:", e);
+ bindingProcessorError = new SLException(6002);
+ resultContentType = HttpUtil.TXT_XML;
+ }
+ }
+ templates = getTemplates(getStyleSheetUrl());
+ if (templates != null) {
+ log.debug("Output transformation required");
+ resultContentType = templates.getOutputProperties().getProperty("media-type");
+ log.debug("Got media type from stylesheet: " + resultContentType);
+ if (resultContentType == null) {
+ log.debug("Setting to default text/xml result conent type");
+ resultContentType = "text/xml";
+ }
+ log.debug("Deferring sytylesheet processing");
+ }
+ currentState = State.FINISHED;
+ }
+
+ protected void finished() {
+ log.debug("Entered State: " + State.FINISHED);
+ if (bindingProcessorError != null) {
+ log.debug("Binding processor error, sending quit command");
+ resultContentType = HttpUtil.TXT_XML;
+ }
+ sendSTALQuit();
+ log.info("Terminating Bindingprocessor; Thread: "
+ + Thread.currentThread().getId());
+ finished = true;
+ }
+
+ // -- END Methods that handle the http binding activities as defined in the
+ // activity diagram --
+ //----------------------------------------------------------------------------
+
+ /**
+ * Sets the headers of the SL Request. IMPORTANT: make sure to set all headers
+ * before invoking {@link #consumeRequestStream(InputStream)}
+ *
+ * @param aHeaderMap
+ * if null all header will be cleared.
+ */
+ public void setHTTPHeaders(Map<String, String> aHeaderMap) {
+ headerMap = new HashMap<String, String>();
+ // ensure lowercase keys
+ if (aHeaderMap != null) {
+ for (String s : aHeaderMap.keySet()) {
+ if (s != null) {
+ headerMap.put(s.toLowerCase(), aHeaderMap.get(s));
+ if (s.equalsIgnoreCase(HttpUtil.HTTP_HEADER_REFERER)) {
+ String referer = aHeaderMap.get(s);
+ log.debug("Got referer header: " + referer);
+ srcContex.setSourceHTTPReferer(referer);
+ }
+ }
+ }
+ }
+ }
+
+ public void setSourceCertificate(X509Certificate aCert) {
+ srcContex.setSourceCertificate(aCert);
+ }
+
+ /**
+ * The HTTPBindingProcessor does not handle redirect URLs. It only provides
+ * the parameter.
+ *
+ * @return null if redirect url is not set.
+ */
+ public String getRedirectURL() {
+ return getFormParameterAsString(FixedFormParameters.REDIRECTURL);
+ }
+
+ public String getFormDataContentType(String aParameterName) {
+ FormParameter fp = formParameterMap.get(aParameterName);
+ if (fp != null) {
+ return fp.getFormParameterContentType();
+ }
+ return null;
+ }
+
+ public InputStream getFormData(String aParameterName) {
+ FormParameter fp = formParameterMap.get(aParameterName);
+ if (fp != null) {
+ final String enc = fp.getHeaderValue("Content-Transfer-Encoding");
+ if (enc == null || "binary".equals(enc)) {
+ return fp.getFormParameterValue();
+ } else if ("base64".equals(enc)) {
+ return new Base64InputStream(fp.getFormParameterValue());
+ } else {
+ return new InputStream() {
+ @Override
+ public int read() throws IOException {
+ throw new IOException("Content-Transfer-Encoding : " + enc
+ + " is not supported.");
+ }
+ };
+ }
+ }
+ return null;
+ }
+
+ protected void assignXMLRequest(InputStream is, String charset)
+ throws IOException, SLException {
+ Reader r = new InputStreamReader(is, charset);
+ StreamSource source = new StreamSource(r);
+ SLCommandContext commandCtx = new SLCommandContext();
+ commandCtx.setSTAL(getSTAL());
+ commandCtx.setURLDereferencerContext(new SimpleFormDataContextImpl(this));
+ commandCtx.setLocale(locale);
+ slCommand = SLCommandFactory.getInstance().createSLCommand(source,
+ commandCtx);
+ log.debug("Created new command: " + slCommand);
+ }
+
+ @Override
+ public void run() {
+ boolean done = false;
+ int hopcounter = 0;
+ if (bindingProcessorError != null) {
+ currentState = State.FINISHED;
+ }
+ try {
+ while (!done) {
+ try {
+ switch (currentState) {
+ case INIT:
+ init();
+ break;
+ case PROCESS:
+ processRequest();
+ break;
+ case DATAURL:
+ handleDataUrl();
+ if (++hopcounter > config.getMaxDataUrlHops()) {
+ log.error("Maximum number of dataurl hops reached");
+ bindingProcessorError = new SLBindingException(2000);
+ currentState = State.FINISHED;
+ }
+ break;
+ case TRANSFORM:
+ transformResult();
+ break;
+ case FINISHED:
+ done = true;
+ finished();
+ break;
+ }
+ } catch (RuntimeException rte) {
+ throw rte;
+ } catch (Exception t) {
+ log.error("Caught unexpected exception", t);
+ responseCode = 200;
+ resultContentType = HttpUtil.TXT_XML;
+ responseHeaders = Collections.EMPTY_MAP;
+ bindingProcessorError = new SLException(2000);
+ currentState = State.FINISHED;
+ }
+ }
+ } catch (Throwable t) {
+ log.error("Caught unexpected exception", t);
+ responseCode = 200;
+ resultContentType = HttpUtil.TXT_XML;
+ responseHeaders = Collections.EMPTY_MAP;
+ bindingProcessorError = new SLException(2000);
+ currentState = State.FINISHED;
+ }
+ log.debug("Terminated http binding processor");
+ finished = true;
+ }
+
+ @Override
+ public void consumeRequestStream(InputStream is) {
+ try {
+ log.debug("Start consuming request stream");
+ formParameterMap.clear();
+ String cl = headerMap
+ .get(HttpUtil.HTTP_HEADER_CONTENT_TYPE.toLowerCase());
+ if (cl == null) {
+ log.info("No content type set in http header");
+ throw new SLBindingException(2006);
+ }
+ InputDecoder id = InputDecoderFactory.getDecoder(cl, is);
+ if (id == null) {
+ log.error("Cannot get inputdecoder for is");
+ throw new SLException(2006);
+ }
+ for (Iterator<FormParameter> fpi = id.getFormParameterIterator(); fpi
+ .hasNext();) {
+ FormParameter fp = fpi.next();
+ log.debug("Got request parameter with name: "
+ + fp.getFormParameterName());
+ if (fp.getFormParameterName().equals(FixedFormParameters.XMLREQUEST)) {
+ log.debug("Creating XML Request");
+ for (Iterator<String> headerIterator = fp.getHeaderNames(); headerIterator
+ .hasNext();) {
+ String headerName = headerIterator.next();
+ if (HttpUtil.CONTENT_TRANSFER_ENCODING.equalsIgnoreCase(headerName)) {
+ String transferEncoding = fp.getHeaderValue(headerName);
+ log.debug("Got transfer encoding for xmlrequest: "
+ + transferEncoding);
+ if (XML_REQ_TRANSFER_ENCODING.contains(transferEncoding)) {
+ log.debug("Supported transfer encoding: " + transferEncoding);
+ } else {
+ log
+ .error("Transferencoding not supported: "
+ + transferEncoding);
+ throw new SLBindingException(2005);
+ }
+ }
+ }
+ String charset = HttpUtil.getCharset(cl, true);
+ assignXMLRequest(fp.getFormParameterValue(), charset);
+ } else {
+ FormParameterStore fps = new FormParameterStore();
+ fps.init(fp);
+ //if (!fps.isEmpty()) {
+ log.debug("Setting form parameter: " + fps.getFormParameterName());
+ formParameterMap.put(fps.getFormParameterName(), fps);
+ //}
+ }
+ }
+ if (slCommand == null) {
+ throw new SLBindingException(2004);
+ }
+ } catch (SLException slx) {
+ log.info("Error while consuming input stream " + slx);
+ bindingProcessorError = slx;
+ } catch (Throwable t) {
+ log.info("Error while consuming input stream " + t, t);
+ bindingProcessorError = new SLException(2000);
+ } finally {
+ try {
+ if (is.read() != -1) {
+ log.warn("Request input stream not completely read.");
+ while (is.read() != -1);
+ }
+ } catch (IOException e) {
+ log.error(e);
+ }
+ }
+ }
+
+ @Override
+ public String getResultContentType() {
+ return resultContentType;
+ }
+
+ protected Templates getTemplates(String styleSheetURL) {
+ if (styleSheetURL == null) {
+ log.debug("Stylesheet URL not set");
+ return null;
+ }
+ try {
+ URLDereferencerContext urlCtx = new SimpleFormDataContextImpl(this);
+ URIResolver resolver = new URIResolverAdapter(URLDereferencer
+ .getInstance(), urlCtx);
+ TransformerFactory factory = TransformerFactory.newInstance();
+ factory.setURIResolver(resolver);
+ StreamData sd = URLDereferencer.getInstance().dereference(styleSheetURL,
+ urlCtx);
+ return factory.newTemplates(new StreamSource(sd.getStream()));
+ } catch (Exception ex) {
+ log.info("Cannot instantiate transformer", ex);
+ bindingProcessorError = new SLException(2002);
+ return null;
+ }
+ }
+
+ protected void handleBindingProcessorError(OutputStream os, String encoding,
+ Templates templates) throws IOException {
+ log.debug("Writing error as result");
+ ErrorResultImpl error = new ErrorResultImpl(bindingProcessorError, locale);
+ 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("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
+ writer.write("<?xml-stylesheet type=\"text/css\" href=\"errorresponse.css\"?>\n");
+ return writer;
+ }
+
+ @Override
+ public void writeResultTo(OutputStream os, String encoding)
+ throws IOException {
+ if (encoding == null) {
+ encoding = HttpUtil.DEFAULT_CHARSET;
+ }
+ if (bindingProcessorError != null) {
+ log.debug("Detected error in binding processor, writing error as result");
+ handleBindingProcessorError(os, encoding, templates);
+ return;
+ } else if (dataUrlResponse != null) {
+ log.debug("Writing data url response as result");
+ String charEnc = HttpUtil.getCharset(dataUrlResponse.getContentType(),
+ true);
+ InputStreamReader isr = new InputStreamReader(
+ dataUrlResponse.getStream(), charEnc);
+ OutputStreamWriter osw = new OutputStreamWriter(os, encoding);
+ if (templates == null) {
+ StreamUtil.copyStream(isr, osw);
+ } else {
+ try {
+ Transformer transformer = templates.newTransformer();
+ transformer.transform(new StreamSource(isr), new StreamResult(osw));
+ } catch (TransformerException e) {
+ log.fatal("Exception occured during result transformation", e);
+ // bindingProcessorError = new SLException(2008);
+ // handleBindingProcessorError(os, encoding, null);
+ return;
+ }
+ }
+ osw.flush();
+ isr.close();
+ } else if (slResult == null) {
+ // result not yet assigned -> must be a cancel
+ bindingProcessorError = new SLException(6001);
+ handleBindingProcessorError(os, encoding, templates);
+ return;
+ } else {
+ log.debug("Getting result from invoker");
+ 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();
+ }
+ }
+
+ /**
+ * The response code from the dataurl server or 200 if no dataurl server
+ * created the result
+ *
+ * @return
+ */
+ public int getResponseCode() {
+ return responseCode;
+ }
+
+ /**
+ * All headers from the data url server in case of a direct forward from the
+ * dataurl server.
+ *
+ * @return
+ */
+ public Map<String, String> getResponseHeaders() {
+ return responseHeaders;
+ }
+
+ @Override
+ public void setLocale(Locale locale) {
+ if (locale == null) {
+ throw new NullPointerException("Locale must not be set to null");
+ }
+ this.locale = locale;
+ }
+
+ @Override
+ public boolean isFinished() {
+ return finished;
+ }
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/HttpUtil.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/HttpUtil.java
new file mode 100644
index 00000000..5ea7b25e
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/HttpUtil.java
@@ -0,0 +1,79 @@
+/*
+* 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.binding;
+
+import java.util.Map;
+
+import org.apache.commons.fileupload.ParameterParser;
+
+/**
+ * Placeholder for some HTTP related constants and helper method to extract the charset for a request.
+ *
+ */
+public class HttpUtil {
+
+ public final static String CHAR_SET = "charset";
+ public final static String DEFAULT_CHARSET = "ISO-8859-1";
+ public final static String HTTP_HEADER_CONTENT_TYPE = "Content-Type";
+ public static final String HTTP_HEADER_USER_AGENT = "User-Agent";
+ public static final String HTTP_HEADER_SERVER = "Server";
+ public final static String HTTP_HEADER_REFERER = "Referer";
+ public final static String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
+ public final static String MULTIPART_FOTMDATA = "multipart/form-data";
+ public final static String MULTIPART_FOTMDATA_BOUNDARY = "boundary";
+ public final static String TXT_XML = "text/xml";
+ public final static String TXT_PLAIN = "text/plain";
+ public final static String TXT_HTML = "text/html";
+ public final static String APPLICATION_URL_ENCODED = "application/x-www-form-urlencoded";
+ public final static String HTTP_HEADER_LOCATION = "Location";
+
+ public final static char[] SEPERATOR = { ';' };
+
+ /**
+ * Extracts charset from a content type header.
+ *
+ * @param contentType
+ * @param replaceNullWithDefault
+ * if true the method return the default charset if not set
+ * @return charset String or null if not present
+ */
+ @SuppressWarnings("unchecked")
+ public static String getCharset(String contentType,
+ boolean replaceNullWithDefault) {
+ ParameterParser pf = new ParameterParser();
+ pf.setLowerCaseNames(true);
+ Map map = pf.parse(contentType, SEPERATOR);
+ String retVal = (String) map.get(CHAR_SET);
+ if ((retVal == null) && (replaceNullWithDefault)) {
+ if (map.containsKey(APPLICATION_URL_ENCODED)) {
+ // default charset for url encoded data
+ return "UTF-8";
+ }
+ retVal = getDefaultCharset();
+ }
+ return retVal;
+ }
+
+ /**
+ *
+ * Not to be used for url encoded requests.
+ */
+ public static String getDefaultCharset() {
+ return DEFAULT_CHARSET;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/Id.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/Id.java
new file mode 100644
index 00000000..fc7c35c3
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/Id.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.bku.binding;
+
+/**
+ * The unique identifier for a BindingProcessor
+ * @author wbauer
+ *
+ */
+public interface Id {
+
+ @Override
+ public String toString();
+
+ @Override
+ public boolean equals(Object id);
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/IdFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/IdFactory.java
new file mode 100644
index 00000000..60bf69a4
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/IdFactory.java
@@ -0,0 +1,106 @@
+/*
+* 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.binding;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Creates or converts Ids for BindingProcessors.
+ * @author wbauer
+ *
+ */
+public class IdFactory {
+
+ public static int DEFAULT_NUMBER_OF_BITS = 168;
+
+ private static Log log = LogFactory.getLog(IdFactory.class);
+
+ private static IdFactory instance = new IdFactory();
+
+ private SecureRandom random;
+ private int numberOfBits = DEFAULT_NUMBER_OF_BITS;
+
+ private IdFactory() {
+ try {
+ random = SecureRandom.getInstance("SHA1PRNG");
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Cannot instantiate secure random" + e);
+ }
+ }
+
+ public static IdFactory getInstance() {
+ return instance;
+ }
+
+
+ /**
+ * set the secure random number generator to create secure ids.
+ *
+ * @param random
+ * must not be null
+ */
+ public void setSecureRandom(SecureRandom random) {
+ if (random == null) {
+ throw new NullPointerException("Cannot set secure random to null");
+ }
+ this.random = random;
+ }
+
+ /**
+ * Don't use this method unless you know exactly what you do !
+ * Be sure to use a sufficient large entropy
+ * @param numberOfBits >=1 (although this small entropy does not make sense)
+ */
+ public void setNumberOfBits(int numberOfBits) {
+ if (numberOfBits <1) {
+ throw new IllegalArgumentException("Cannot set number of bits < 1");
+ }
+ this.numberOfBits = numberOfBits;
+ }
+
+ public int getNumberOfBits() {
+ return numberOfBits;
+ }
+
+ /**
+ * Creates a new Id object with the factory's secure RNG and the set number of
+ * bits.
+ *
+ * @return
+ */
+ public Id createId() {
+ return new IdImpl(numberOfBits, random);
+ }
+
+ /**
+ * Creates an Id object for the provided String
+ *
+ * @param idString
+ * may be null in this case the method call creates a new Id.
+ * @return
+ */
+ public Id createId(String idString) {
+ if (idString == null) {
+ return createId();
+ }
+ return new IdImpl(idString);
+ }
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/IdImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/IdImpl.java
new file mode 100644
index 00000000..c8a76823
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/IdImpl.java
@@ -0,0 +1,83 @@
+/*
+* 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.binding;
+
+import iaik.utils.Base64OutputStream;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.SecureRandom;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Implementation that uses a Base64 representation for self generated Ids.
+ * @author wbauer
+ *
+ */
+public class IdImpl implements at.gv.egiz.bku.binding.Id {
+ private static Log log = LogFactory.getLog(IdImpl.class);
+
+ private String idString;
+
+ public IdImpl(int bitNumber, SecureRandom random) {
+ int byteSize = bitNumber/8;
+ if (bitNumber % 8 != 0) {
+ byteSize++;
+ }
+ byte[] randomBytes = new byte[byteSize];
+ random.nextBytes(randomBytes);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Base64OutputStream b64 = new Base64OutputStream(baos);
+ try {
+ b64.write(randomBytes);
+ b64.flush();
+ b64.close();
+ idString = new String(baos.toByteArray());
+ } catch (IOException e) {
+ log.error("Cannot create secure id: "+e);
+ }
+ }
+
+ public IdImpl(String idString) {
+ if (idString == null) {
+ throw new NullPointerException("Provided idstring must not be null");
+ }
+ this.idString = idString;
+ }
+
+ @Override
+ public String toString() {
+ return idString;
+ }
+
+ @Override
+ public int hashCode() {
+ return idString.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof Id) {
+ Id otherId = (Id)other;
+ return otherId.toString().equals(idString);
+ } else {
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/InputDecoder.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/InputDecoder.java
new file mode 100644
index 00000000..e22e54f2
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/InputDecoder.java
@@ -0,0 +1,41 @@
+/*
+* 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.binding;
+
+import java.io.InputStream;
+import java.util.Iterator;
+
+/**
+ * Decodes http input stream (either url encoded or multipart formdata)
+ * @author wbauer
+ *
+ */
+public interface InputDecoder {
+ /**
+ * Called from Factory.
+ * @param contentType
+ */
+ void setContentType(String contentType);
+
+ /**
+ * Called from Factory.
+ * @param is the input must not be null
+ */
+ void setInputStream(InputStream is);
+
+ Iterator<FormParameter> getFormParameterIterator();
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/InputDecoderFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/InputDecoderFactory.java
new file mode 100644
index 00000000..211deee7
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/InputDecoderFactory.java
@@ -0,0 +1,89 @@
+/*
+* 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.binding;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Factory to get a matching instance for a encoded input stream when reading a http request.
+ *
+ */
+public class InputDecoderFactory {
+
+ public final static String MULTIPART_FORMDATA = "multipart/form-data";
+ public final static String URL_ENCODED = "application/x-www-form-urlencoded";
+
+ private static InputDecoderFactory instance = new InputDecoderFactory();
+ private static Log log = LogFactory.getLog(InputDecoderFactory.class);
+
+ private String defaultEncoding = URL_ENCODED;
+ private Map<String, Class<? extends InputDecoder>> decoderMap = new HashMap<String, Class<? extends InputDecoder>>();
+
+ private InputDecoderFactory() {
+ decoderMap.put(MULTIPART_FORMDATA, MultiPartFormDataInputDecoder.class);
+ decoderMap.put(URL_ENCODED, XWWWFormUrlInputDecoder.class);
+ }
+
+ public static InputDecoder getDefaultDecoder(InputStream is) {
+ return getDecoder(instance.defaultEncoding, is);
+ }
+
+ /**
+ *
+ * @param contentType
+ * @param is
+ * @return null if the content type is not supported
+ */
+ public static InputDecoder getDecoder(String contentType, InputStream is) {
+ String prefix = contentType.split(";")[0].trim().toLowerCase();
+ Class<? extends InputDecoder> dec = instance.decoderMap.get(prefix);
+ if (dec == null) {
+ log.info("Unknown encoding prefix " + contentType);
+ return null;
+ }
+ InputDecoder id;
+ try {
+ id = dec.newInstance();
+ id.setContentType(contentType);
+ id.setInputStream(is);
+ return id;
+ } catch (InstantiationException e) {
+ log.error(e);
+ throw new IllegalArgumentException(
+ "Cannot get an input decoder for content type: " + contentType);
+ } catch (IllegalAccessException e) {
+ log.error(e);
+ throw new IllegalArgumentException(
+ "Cannot get an input decoder for content type: " + contentType);
+ }
+ }
+
+ /**
+ * Allows to register decoders for special mime types.
+ * @param mimeType
+ * @param decoder
+ */
+ public static void registerDecoder(String mimeType,
+ Class<? extends InputDecoder> decoder) {
+ instance.decoderMap.put(mimeType.toLowerCase(), decoder);
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/MultiPartFormDataInputDecoder.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/MultiPartFormDataInputDecoder.java
new file mode 100644
index 00000000..f8b13553
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/MultiPartFormDataInputDecoder.java
@@ -0,0 +1,133 @@
+/*
+* 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.binding;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+
+import org.apache.commons.fileupload.FileItemIterator;
+import org.apache.commons.fileupload.FileItemStream;
+import org.apache.commons.fileupload.FileUpload;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.RequestContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+
+/**
+ * The code to detect the multipart boundary is based on
+ * org.apache.commons.fileupload.FileUploadBase of
+ * http://commons.apache.org/fileupload/
+ *
+ * @author wbauer
+ *
+ */
+public class MultiPartFormDataInputDecoder implements InputDecoder,
+ RequestContext {
+
+ private static Log log = LogFactory
+ .getLog(MultiPartFormDataInputDecoder.class);
+
+ private String contentType;
+ private InputStream stream;
+
+ @Override
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ @Override
+ public int getContentLength() {
+ return 0;
+ }
+
+ @Override
+ public String getContentType() {
+ return contentType;
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return stream;
+ }
+
+ @Override
+ public Iterator<FormParameter> getFormParameterIterator() {
+ try {
+ FileUpload fup = new FileUpload();
+ FileItemIterator fit = fup.getItemIterator(this);
+ return new IteratorDelegator(fit);
+ } catch (Exception iox) {
+ log.error("Cannot decode multipart form data stream " + iox);
+ throw new SLRuntimeException(iox);
+ }
+ }
+
+ @Override
+ public void setInputStream(InputStream is) {
+ stream = is;
+ }
+
+ static class IteratorDelegator implements Iterator<FormParameter> {
+
+ private FileItemIterator fileItemIterator;
+
+ public IteratorDelegator(FileItemIterator fit) {
+ fileItemIterator = fit;
+ }
+
+ @Override
+ public boolean hasNext() {
+ try {
+ return fileItemIterator.hasNext();
+ } catch (FileUploadException e) {
+ log.error(e);
+ throw new SLRuntimeException(e);
+ } catch (IOException e) {
+ log.error(e);
+ throw new SLRuntimeException(e);
+ }
+ }
+
+ @Override
+ public FormParameter next() {
+ try {
+ FileItemStream item = fileItemIterator.next();
+ return new FormParameterImpl(item.getContentType(),
+ item.getFieldName(), item.openStream(), item.getHeaders());
+ } catch (FileUploadException e) {
+ log.error(e);
+ throw new SLRuntimeException(e);
+ } catch (IOException e) {
+ log.error(e);
+ throw new SLRuntimeException(e);
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Remove not supported");
+ }
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/ProcessingContext.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/ProcessingContext.java
new file mode 100644
index 00000000..913259f6
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/ProcessingContext.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.binding;
+
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.Future;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class ProcessingContext {
+
+ public static final String BINDING_PROCESSOR = "binding.processor";
+ public static final String FUTURE = "future";
+
+ protected static final Log log = LogFactory.getLog(ProcessingContext.class);
+
+ protected Map<String, Object> properties = new Hashtable<String, Object>();
+
+ public ProcessingContext(BindingProcessor bp, Future future) {
+ properties.put(BINDING_PROCESSOR, bp);
+ properties.put(FUTURE, future);
+ }
+
+ public BindingProcessor getBindingProcessor() {
+ return (BindingProcessor) properties.get(BINDING_PROCESSOR);
+ }
+
+ public Future getFuture() {
+ return (Future) properties.get(FUTURE);
+ }
+
+ public Object get(String key) {
+ return properties.get(key);
+ }
+
+ public void put(String key, Object value) {
+ properties.put(key, value);
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/RemovalStrategy.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/RemovalStrategy.java
new file mode 100644
index 00000000..6c2dcb9f
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/RemovalStrategy.java
@@ -0,0 +1,26 @@
+/*
+* 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.binding;
+
+/**
+ * Could be used to remove expired BindingProcessor objects from a BindingProcessorManager.
+ *
+ */
+public interface RemovalStrategy {
+ public void execute();
+ public void setBindingProcessorManager(BindingProcessorManager bp);
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/SLCommandInvokerImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/SLCommandInvokerImpl.java
new file mode 100644
index 00000000..a23d96e8
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/SLCommandInvokerImpl.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.binding;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.accesscontroller.SecurityManagerFacade;
+import at.gv.egiz.bku.slcommands.SLCommand;
+import at.gv.egiz.bku.slcommands.SLCommandInvoker;
+import at.gv.egiz.bku.slcommands.SLResult;
+import at.gv.egiz.bku.slcommands.SLSourceContext;
+import at.gv.egiz.bku.slcommands.SLTargetContext;
+import at.gv.egiz.bku.slexceptions.SLException;
+
+/**
+ * This class implements the entry point for the CCEs security management.
+ *
+ */
+public class SLCommandInvokerImpl implements SLCommandInvoker {
+
+ private static Log log = LogFactory.getLog(SLCommandInvokerImpl.class);
+
+ protected SLCommand command;
+ protected SLResult result;
+ protected SecurityManagerFacade securityManager;
+
+ /**
+ * Invokes a sl command.
+ *
+ * @throws SLException
+ */
+ public void invoke(SLSourceContext aContext) throws SLException {
+ if (securityManager == null) {
+ log.warn("Security policy not implemented yet, invoking command: "
+ + command);
+ result = command.execute();
+ } else {
+ if (securityManager.mayInvokeCommand(command, aContext)) {
+ result = command.execute();
+ } else {
+ throw new SLException(6002);
+ }
+ }
+ }
+
+ public SLResult getResult(SLTargetContext aContext) throws SLException {
+ if (securityManager == null) {
+ log
+ .warn("Security policy not implemented yet, getting result of command: "
+ + command);
+ return result;
+ } else {
+ if (securityManager.maySendResult(command, aContext)) {
+ return result;
+ } else {
+ throw new SLException(6002);
+ }
+ }
+ }
+
+ public void setCommand(SLCommand aCmd) {
+ command = aCmd;
+ }
+
+ @Override
+ public SLCommandInvoker newInstance() {
+ SLCommandInvokerImpl cmdInv = new SLCommandInvokerImpl();
+ cmdInv.setSecurityManager(securityManager);
+ return cmdInv;
+ }
+
+ public SecurityManagerFacade getSecurityManager() {
+ return securityManager;
+ }
+
+ public void setSecurityManager(SecurityManagerFacade securityManager) {
+ this.securityManager = securityManager;
+ }
+
+} \ 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
new file mode 100644
index 00000000..69c659e1
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/XWWWFormUrlInputDecoder.java
@@ -0,0 +1,58 @@
+/*
+* 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.binding;
+
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.commons.fileupload.ParameterParser;
+
+public class XWWWFormUrlInputDecoder implements InputDecoder {
+
+ /**
+ * 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<String, String> params = pp.parse(contentType, new char[] { ':', ';' });
+ if (!params.containsKey(CONTENT_TYPE)) {
+ throw new IllegalArgumentException(
+ "not a url encoded content type specification: " + contentType);
+ }
+ }
+
+ @Override
+ public Iterator<FormParameter> getFormParameterIterator() {
+ return iterator;
+ }
+
+ @Override
+ public void setInputStream(InputStream 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..9279130d
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/XWWWFormUrlInputIterator.java
@@ -0,0 +1,386 @@
+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<FormParameter> {
+
+ 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 <code>in</code> 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;
+ }
+ try {
+ if (currentParameter != null) {
+ // we have to disconnect the current parameter
+ // to look for further parameters
+ 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 to be able to report error
+ return true;
+ }
+ return true;
+ }
+
+ @Override
+ public FormParameter next() {
+ if (hasNext()) {
+ // skip separator
+ if (buf[pos] == PARAM_SEP) {
+ 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<String> 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<String> 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) {
+ 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);
+ 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/InputStreamPartSource.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/InputStreamPartSource.java
new file mode 100644
index 00000000..1a22f787
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/InputStreamPartSource.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.binding.multipart;
+
+import java.io.IOException;
+import java.io.InputStream;
+import org.apache.commons.httpclient.methods.multipart.PartSource;
+
+/**
+ * InputStream source for FilePart.
+ * DOES NOT RETURN A CORRECT LENGTH OF THE INPUT DATA. (but we don't care, since we use chunked encoding)
+ *
+ * @author clemens
+ */
+public class InputStreamPartSource implements PartSource {
+
+ protected String name;
+ protected InputStream data;
+
+ public InputStreamPartSource(String name, InputStream data) {
+ this.name = name;
+ this.data = data;
+ }
+
+ /**
+ * Just a dummy value to make Part work
+ * @return 42
+ */
+ @Override
+ public long getLength() {
+ //System.out.println("***********GETLENGTH");
+ return 42;
+ }
+
+ @Override
+ public String getFileName() {
+ return name;
+ }
+
+ @Override
+ public InputStream createInputStream() throws IOException {
+ if (data == null)
+ throw new IOException("Failed to get stream for part: no data was set.");
+ return data;
+ }
+
+}
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
new file mode 100644
index 00000000..d896ea9f
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/multipart/SLResultPart.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.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.FilePart;
+import org.apache.commons.httpclient.methods.multipart.PartSource;
+
+public class SLResultPart extends FilePart {
+
+ protected SLResult slResult;
+ protected String encoding;
+
+ public SLResultPart(SLResult slResult, String encoding) {
+ 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)), false);
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/conf/CertValidator.java b/bkucommon/src/main/java/at/gv/egiz/bku/conf/CertValidator.java
new file mode 100644
index 00000000..6a95b369
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/conf/CertValidator.java
@@ -0,0 +1,13 @@
+package at.gv.egiz.bku.conf;
+
+import iaik.x509.X509Certificate;
+
+import java.io.File;
+
+public interface CertValidator {
+
+ public abstract void init(File certDir, File caDir);
+
+ public abstract boolean isCertificateValid(String transactionId, X509Certificate[] certs);
+
+} \ No newline at end of file
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
new file mode 100644
index 00000000..3b2d1b99
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/conf/CertValidatorImpl.java
@@ -0,0 +1,107 @@
+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;
+import iaik.pki.PKIException;
+import iaik.pki.PKIFactory;
+import iaik.pki.PKIModule;
+import iaik.pki.PKIProfile;
+import iaik.pki.store.certstore.CertStoreParameters;
+import iaik.pki.store.certstore.directory.DefaultDirectoryCertStoreParameters;
+import iaik.pki.store.truststore.DefaultTrustStoreProfile;
+import iaik.pki.store.truststore.TrustStoreProfile;
+import iaik.pki.store.truststore.TrustStoreTypes;
+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;
+
+public class CertValidatorImpl implements CertValidator {
+
+ private static Log log = LogFactory.getLog(CertValidatorImpl.class);
+
+ private PKIFactory pkiFactory;
+ private PKIProfile profile;
+
+ public CertValidatorImpl() {
+
+ }
+
+ /* (non-Javadoc)
+ * @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) };
+
+ // create a new PKI configuration using the certstore parameters
+ PKIConfiguration pkiConfig = new DefaultPKIConfiguration(
+ certStoreParameters);
+
+ // Transaction ID for logging
+ TransactionId tid = new TransactionIdImpl("Configure-PKI");
+ // get PKI factory for creating PKI module(s)
+ pkiFactory = PKIFactory.getInstance();
+ // configure the factory
+ try {
+ pkiFactory.configure(pkiConfig, tid);
+ } catch (PKIException e) {
+ log.error("Cannot configure PKI module", e);
+ }
+ // the truststore to be used
+ TrustStoreProfile trustProfile = new DefaultTrustStoreProfile("TS-001",
+ TrustStoreTypes.DIRECTORY, caDir.getAbsolutePath());
+ profile = new DefaultPKIProfile(trustProfile);
+ ((DefaultPKIProfile)profile).setAutoAddCertificates(true);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.bku.conf.CertValidator#isCertificateValid(java.lang.String, iaik.x509.X509Certificate[])
+ */
+ public boolean isCertificateValid(String transactionId,
+ X509Certificate[] certs) {
+ // Transaction ID for logging
+ TransactionId tid = new TransactionIdImpl(transactionId);
+ // get a PKIModule
+ PKIModule pkiModule;
+ try {
+ pkiModule = pkiFactory.getPKIModule(profile);
+ return pkiModule.validateCertificate(new Date(), certs[0], certs, null,
+ tid).isCertificateValid();
+ } catch (PKIException e) {
+ log.error("Cannot validate certificate", e);
+ }
+ return false;
+ }
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/conf/Configuration.java b/bkucommon/src/main/java/at/gv/egiz/bku/conf/Configuration.java
new file mode 100644
index 00000000..f813b14d
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/conf/Configuration.java
@@ -0,0 +1,100 @@
+/*
+ * 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.conf;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * BKU Common Configuration
+ *
+ * Injected to BKU Common classes as defined in mocca-conf.xml
+ *
+ * Replace at.gv.egiz.bku.conf.Configurator,
+ * currently only few configuration options are supported.
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class Configuration {
+
+ public static final int MAX_DATAURL_HOPS_DEFAULT = 50;
+ public static final String IMPLEMENTATION_NAME_DEFAULT = "MOCCA";
+ public static final String IMPLEMENTATION_VERSION_DEFAULT = "UNKNOWN";
+
+ private static final Log log = LogFactory.getLog(Configuration.class);
+
+ private int maxDataUrlHops = -1;
+ private String implementationName;
+ private String implementationVersion;
+
+ public void setMaxDataUrlHops(int maxDataUrlHops) {
+ this.maxDataUrlHops = maxDataUrlHops;
+ }
+
+ /**
+ * Defines the maximum number of dataurl connects that are allowed within a
+ * single SL Request processing.
+ */
+ public int getMaxDataUrlHops() {
+ if (maxDataUrlHops < 0) {
+ log.warn("maxDataUrlHops not configured, using default: " + MAX_DATAURL_HOPS_DEFAULT);
+ return MAX_DATAURL_HOPS_DEFAULT;
+ }
+ return maxDataUrlHops;
+ }
+
+ /**
+ * @return the implementationName
+ */
+ public String getImplementationName() {
+ if (implementationName == null) {
+ log.info("implementationName not configured, using default: " + IMPLEMENTATION_NAME_DEFAULT);
+ return "MOCCA";
+ }
+ return implementationName;
+ }
+
+ /**
+ * @param implementationName the implementationName to set
+ */
+ public void setImplementationName(String implementationName) {
+ this.implementationName = implementationName;
+ }
+
+ /**
+ * @return the implementationVersion
+ */
+ public String getImplementationVersion() {
+ if (implementationName == null) {
+ log.info("implementationName not configured, using default: " + IMPLEMENTATION_VERSION_DEFAULT);
+ return IMPLEMENTATION_VERSION_DEFAULT;
+ }
+ return implementationVersion;
+ }
+
+ /**
+ * @param implementationVersion the implementationVersion to set
+ */
+ public void setImplementationVersion(String implementationVersion) {
+ this.implementationVersion = implementationVersion;
+ }
+
+
+
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/conf/Configurator.java b/bkucommon/src/main/java/at/gv/egiz/bku/conf/Configurator.java
new file mode 100644
index 00000000..50f5d2b4
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/conf/Configurator.java
@@ -0,0 +1,467 @@
+package at.gv.egiz.bku.conf;
+
+import iaik.security.ecc.provider.ECCProvider;
+import iaik.security.provider.IAIK;
+import iaik.xml.crypto.XSecProvider;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Security;
+import java.security.Provider.Service;
+import java.security.cert.CertStore;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.LDAPCertStoreParameters;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.binding.DataUrl;
+import at.gv.egiz.bku.slcommands.impl.xsect.DataObject;
+import at.gv.egiz.bku.slcommands.impl.xsect.STALProvider;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer;
+import javax.net.ssl.SSLSocketFactory;
+
+public abstract class Configurator {
+
+ private Log log = LogFactory.getLog(Configurator.class);
+
+ public final static String USERAGENT_CONFIG_P = "UserAgent";
+ public static final String DATAURLCONNECTION_CONFIG_P = "DataURLConnectionImplClass";
+
+ public static final String USERAGENT_DEFAULT = "citizen-card-environment/1.2 MOCCA/UNKNOWN";
+ public static final String USERAGENT_BASE = "citizen-card-environment/1.2 MOCCA/";
+
+ public static final String SIGNATURE_LAYOUT = "SignatureLayout";
+
+ protected Properties properties;
+
+ protected CertValidator certValidator;
+ protected String signaturLayoutVersion;
+
+ protected Configurator() {
+ }
+
+ protected abstract File getCertDir();
+
+ protected abstract File getCADir();
+
+ protected abstract InputStream getManifest();
+
+ private X509Certificate[] getCACerts() throws IOException,
+ CertificateException {
+ List<X509Certificate> caCerts = new ArrayList<X509Certificate>();
+ File caDir = getCADir();
+ if (caDir != null) {
+ if (!caDir.isDirectory()) {
+ log.error("Expecting directory as SSL.caDirectory parameter");
+ throw new SLRuntimeException(
+ "Expecting directory as SSL.caDirectory parameter");
+ }
+ log.info("loading trustStore from " + caDir.getAbsolutePath());
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ for (File f : caDir.listFiles()) {
+ try {
+ FileInputStream fis = new FileInputStream(f);
+ X509Certificate cert = (X509Certificate) cf.generateCertificate(fis);
+ fis.close();
+ log.debug("Adding trusted cert " + cert.getSubjectDN());
+ caCerts.add(cert);
+ } catch (Exception e) {
+ log.error("Cannot add trusted ca", e);
+ }
+ }
+ return caCerts.toArray(new X509Certificate[caCerts.size()]);
+ } else {
+ log.warn("No CA certificates configured");
+ }
+ return null;
+ }
+
+ protected List<CertStore> getCertstore() throws IOException,
+ CertificateException, InvalidAlgorithmParameterException,
+ NoSuchAlgorithmException {
+ List<CertStore> resultList = new ArrayList<CertStore>();
+ File certDir = getCertDir();
+ if (certDir != null) {
+ if (!certDir.isDirectory()) {
+ log.error("Expecting directory as SSL.certDirectory parameter");
+ throw new SLRuntimeException(
+ "Expecting directory as SSL.certDirectory parameter");
+ }
+ log.info("loading certStore from " + certDir.getAbsolutePath());
+ List<X509Certificate> certCollection = new LinkedList<X509Certificate>();
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ for (File f : certDir.listFiles()) {
+ try {
+ FileInputStream fis = new FileInputStream(f);
+ X509Certificate cert = (X509Certificate) cf.generateCertificate(fis);
+ certCollection.add(cert);
+ fis.close();
+ log
+ .trace("Added following cert to certstore: "
+ + cert.getSubjectDN());
+ } catch (Exception ex) {
+ log.error("Cannot add certificate", ex);
+ }
+ }
+ CollectionCertStoreParameters csp = new CollectionCertStoreParameters(
+ certCollection);
+ resultList.add(CertStore.getInstance("Collection", csp));
+ log.info("Added collection certstore");
+ } else {
+ log.warn("No certstore directory configured");
+ }
+ String ldapHost = getProperty("SSL.ldapServer");
+ if ((ldapHost != null) && (!"".equals(ldapHost))) {
+ String ldapPortString = getProperty("SSL.ldapPort");
+ int ldapPort = 389;
+ if (ldapPortString != null) {
+ try {
+ ldapPort = Integer.parseInt(ldapPortString);
+ } catch (NumberFormatException nfe) {
+ log.error("Invalid ldap port, using default 389");
+ }
+ } else {
+ log.warn("ldap port not specified, using default 389");
+ }
+ LDAPCertStoreParameters ldapParams = new LDAPCertStoreParameters(
+ ldapHost, ldapPort);
+ resultList.add(CertStore.getInstance("LDAP", ldapParams));
+ log.info("Added LDAP certstore");
+ }
+ return resultList;
+ }
+
+ protected void configUrlConnections() {
+ HttpsURLConnection.setFollowRedirects(false);
+ HttpURLConnection.setFollowRedirects(false);
+ }
+
+ protected void configureProviders() {
+ log.debug("Registering security providers");
+
+ IAIK iaikProvider = new IAIK();
+ if (Security.getProvider(iaikProvider.getName()) == null) {
+ // register IAIK provider at first position
+ Security.insertProviderAt(iaikProvider, 1);
+ } else {
+ // IAIK provider already registered
+ log.info("Provider " + iaikProvider.getName() + " already registered.");
+ }
+
+ ECCProvider eccProvider = new ECCProvider(false);
+ if (Security.getProvider(eccProvider.getName()) == null) {
+ // register ECC Provider at second position
+ Security.insertProviderAt(eccProvider, 2);
+ } else {
+ // ECC Provider already registered
+ log.info("Provider " + eccProvider.getName() + " already registered.");
+ }
+
+ // registering STALProvider as delegation provider for XSECT
+ STALProvider stalProvider = new STALProvider();
+ if (Security.getProvider(stalProvider.getName()) == null) {
+ // register STAL provider
+ Set<Service> services = stalProvider.getServices();
+ StringBuilder sb = new StringBuilder();
+ for (Service service : services) {
+ String algorithm = service.getType() + "." + service.getAlgorithm();
+ XSecProvider.setDelegationProvider(algorithm, stalProvider.getName());
+ sb.append("\n" + algorithm);
+ }
+ log
+ .debug("Registered STALProvider as XSecProvider delegation provider for the following services : "
+ + sb.toString());
+
+ Security.addProvider(stalProvider);
+ } else {
+ // STAL Provider already registered
+ log.info("Provider " + stalProvider.getName() + " already registered.");
+ }
+
+ if (Security.getProvider(XSecProvider.NAME) == null) {
+ // register XML Security provider
+ XSecProvider.addAsProvider(false);
+ } else {
+ log.info("Provider " + XSecProvider.NAME + " already registered.");
+ }
+
+ if (log.isDebugEnabled()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Registered providers: ");
+ int i = 1;
+ for (Provider prov : Security.getProviders()) {
+ sb.append((i++) + ". : " + prov);
+ }
+ log.debug(sb.toString());
+ }
+ }
+
+ protected void configViewer() {
+ String bv = properties.getProperty("ValidateHashDataInputs");
+ if (bv != null) {
+ DataObject.enableHashDataInputValidation(Boolean.parseBoolean(bv));
+ } else {
+ log.warn("ValidateHashDataInputs not set, falling back to default");
+ }
+ }
+
+ public void configureSingatureLayoutVersion() {
+ if (properties.get(SIGNATURE_LAYOUT) == null) {
+ try {
+ String classContainer = Configurator.class.getProtectionDomain()
+ .getCodeSource().getLocation().toString();
+ URL manifestUrl = new URL("jar:" + classContainer
+ + "!/META-INF/MANIFEST.MF");
+ Manifest manifest = new Manifest(manifestUrl.openStream());
+ Attributes att = manifest.getMainAttributes();
+ String layout = null;
+ if (att != null) {
+ layout = att.getValue(SIGNATURE_LAYOUT);
+ }
+ if (layout != null) {
+ log.info("setting SignatureLayout header to " + layout);
+ properties.put(SIGNATURE_LAYOUT, layout);
+ } else {
+ log.warn("no SignatureLayout version defined");
+ }
+ } catch (Exception ex) {
+ log.warn("Cannot read manifest", ex);
+ }
+ }
+ }
+
+ public void configureNetwork() {
+ String proxy = getProperty("HTTPProxyHost");
+ String portString = getProperty("HTTPProxyPort");
+ if ((proxy == null) || (proxy.equals(""))) {
+ log.info("No proxy configured");
+ } else {
+ log.info("Setting proxy to: " + proxy + ":" + portString);
+ System.setProperty("proxyHost", proxy);
+ System.setProperty("proxyPort", portString);
+ }
+ String timeout = getProperty("DefaultSocketTimeout");
+ if ((timeout != null) && (!timeout.equals(""))) {
+ System.setProperty("sun.net.client.defaultConnectTimeout", timeout);
+ }
+ }
+
+ public void configureVersion() {
+ if (properties.getProperty(USERAGENT_CONFIG_P) == null) {
+ Properties p = new Properties();
+ try {
+ InputStream is = getManifest();
+ if (is != null) {
+ p.load(getManifest());
+ String version = p.getProperty("Implementation-Build");
+ if (version == null) {
+ version="UNKNOWN";
+ }
+ properties.setProperty(USERAGENT_CONFIG_P, USERAGENT_BASE + version);
+ log.debug("Setting user agent to: "
+ + properties.getProperty(USERAGENT_CONFIG_P));
+ } else {
+ log.warn("Failed to read manifest, setting user-agent to " + USERAGENT_DEFAULT);
+ properties.setProperty(USERAGENT_CONFIG_P, USERAGENT_DEFAULT);
+ }
+ } catch (IOException e) {
+ log.error(e);
+ }
+ } else {
+ log.info("using configured user agent " + properties.getProperty(USERAGENT_CONFIG_P));
+ }
+ }
+
+ /**
+ * TODO cleanup configuration (read MANIFEST, DataURLconfig,...)
+ */
+ public void configure() {
+ configureProviders();
+ configUrlConnections();
+ configViewer();
+ configureSSL();
+ configureVersion();
+ configureSingatureLayoutVersion();
+ configureNetwork();
+ //after configureVersion() and configureSignatureLayoutVersion()
+ DataUrl.setConfiguration(properties);
+ }
+
+ public void setConfiguration(Properties props) {
+ this.properties = props;
+ }
+
+ public String getProperty(String key) {
+ if (properties != null) {
+ return properties.getProperty(key);
+ }
+ return null;
+ }
+
+ public void configureSSL() {
+ X509Certificate[] caCerts = null;
+ try {
+ caCerts = getCACerts();
+ } catch (Exception e1) {
+ log.error("Cannot load CA certificates", e1);
+ }
+ String disableAll = getProperty("SSL.disableAllChecks");
+ String disableHostnameVerification = getProperty("SSL.disableHostnameVerification");
+ try {
+ KeyManager[] km = null;
+ SSLContext sslCtx = SSLContext
+ .getInstance(getProperty("SSL.sslProtocol"));
+ if ((disableAll != null) && (Boolean.parseBoolean(disableAll))) {
+ log.warn("--------------------------------------");
+ log.warn(" Disabling SSL Certificate Validation ");
+ log.warn("--------------------------------------");
+
+ sslCtx.init(km,
+ new TrustManager[] { new MyAlwaysTrustManager(caCerts) }, null);
+ } else {
+ MyPKITrustManager pkixTM = new MyPKITrustManager(certValidator,
+ getCertDir(), getCADir(), caCerts);
+ sslCtx.init(km, new TrustManager[] { pkixTM }, null);
+ }
+ DataUrl.setSSLSocketFactory(sslCtx.getSocketFactory());
+ URLDereferencer.getInstance().setSSLSocketFactory(
+ sslCtx.getSocketFactory());
+ } catch (Exception e) {
+ log.error("Cannot configure SSL", e);
+ }
+ if ((disableAll != null && Boolean.parseBoolean(disableAll))
+ || (disableHostnameVerification != null && Boolean
+ .parseBoolean(disableHostnameVerification))) {
+ log.warn("---------------------------------");
+ log.warn(" Disabling Hostname Verification ");
+ log.warn("---------------------------------");
+ DataUrl.setHostNameVerifier(new HostnameVerifier() {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ });
+ URLDereferencer.getInstance().setHostnameVerifier(new HostnameVerifier() {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ });
+ }
+ }
+
+ public void setCertValidator(CertValidator certValidator) {
+ this.certValidator = certValidator;
+ }
+
+ private static class MyPKITrustManager implements X509TrustManager {
+ private static Log log = LogFactory.getLog(MyPKITrustManager.class);
+
+ private CertValidator certValidator;
+ private X509Certificate[] trustedCerts;
+
+ public MyPKITrustManager(CertValidator cv, File certStore, File trustStore,
+ X509Certificate[] trustedCerts) {
+ certValidator = cv;
+ certValidator.init(certStore, trustStore);
+ this.trustedCerts = trustedCerts;
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ log.error("Did not expect this method to get called");
+ throw new CertificateException("Method not implemented");
+ }
+
+ private static iaik.x509.X509Certificate[] convertCerts(
+ X509Certificate[] certs) throws GeneralSecurityException {
+ iaik.x509.X509Certificate[] retVal = new iaik.x509.X509Certificate[certs.length];
+ int i = 0;
+ for (X509Certificate cert : certs) {
+ if (cert instanceof iaik.x509.X509Certificate) {
+ retVal[i++] = (iaik.x509.X509Certificate) cert;
+ } else {
+ retVal[i++] = new iaik.x509.X509Certificate(cert.getEncoded());
+ }
+ }
+ return retVal;
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ try {
+ boolean valid = certValidator.isCertificateValid(Thread.currentThread()
+ .getName(), convertCerts(chain));
+ if (!valid) {
+ throw new CertificateException("Certificate not valid");
+ }
+ } catch (GeneralSecurityException e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return trustedCerts;
+ }
+ }
+
+ private static class MyAlwaysTrustManager implements X509TrustManager {
+ private static Log log = LogFactory.getLog(MyAlwaysTrustManager.class);
+ private X509Certificate[] trustedCerts;
+
+ public MyAlwaysTrustManager(X509Certificate[] trustedCerts) {
+ this.trustedCerts = trustedCerts;
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] arg0, String arg1)
+ throws CertificateException {
+ log.error("Did not expect this method to get called");
+ throw new CertificateException("Method not implemented");
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] certs, String arg1)
+ throws CertificateException {
+ log.warn("-------------------------------------");
+ log.warn("SSL Certificate Validation Disabled !");
+ log.warn("-------------------------------------");
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return trustedCerts;
+ }
+ }
+}
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/AccessControlInvocation.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/AccessControlInvocation.java
new file mode 100644
index 00000000..014b7fd7
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/AccessControlInvocation.java
@@ -0,0 +1,21 @@
+/*
+* 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;
+
+public class AccessControlInvocation implements
+ at.gv.egiz.bku.slcommands.InvocationStrategy {
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateXMLSignatureCommand.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateXMLSignatureCommand.java
new file mode 100644
index 00000000..2d87c39f
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateXMLSignatureCommand.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.slcommands;
+
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.bku.slexceptions.SLRequestException;
+
+public interface CreateXMLSignatureCommand extends SLCommand {
+
+ public void prepareXMLSignature() throws SLCommandException, SLRequestException;
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateXMLSignatureResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateXMLSignatureResult.java
new file mode 100644
index 00000000..4bc2820b
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateXMLSignatureResult.java
@@ -0,0 +1,20 @@
+/*
+* 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;
+
+public interface CreateXMLSignatureResult extends SLResult {
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/ErrorResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/ErrorResult.java
new file mode 100644
index 00000000..5d52c0ea
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/ErrorResult.java
@@ -0,0 +1,20 @@
+/*
+* 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;
+
+public interface ErrorResult extends SLResult {
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/GetStatusCommand.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/GetStatusCommand.java
new file mode 100644
index 00000000..19099b63
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/GetStatusCommand.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public interface GetStatusCommand extends SLCommand {
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/GetStatusResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/GetStatusResult.java
new file mode 100644
index 00000000..c5518f51
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/GetStatusResult.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public interface GetStatusResult extends SLResult {
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxReadCommand.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxReadCommand.java
new file mode 100644
index 00000000..73fddf1f
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxReadCommand.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.bku.slcommands;
+
+public interface InfoboxReadCommand extends SLCommand {
+ public String getInfoboxIdentifier();
+
+ /**
+ * Convenience method to get the domain identifier if the infobox
+ * referes to a Identitylink.
+ * @return the domain id or null if the Infobox is not of type Identitylink or no domain parameter was specified
+ */
+ public String getIdentityLinkDomainId();
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxReadResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxReadResult.java
new file mode 100644
index 00000000..c6a51362
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxReadResult.java
@@ -0,0 +1,20 @@
+/*
+* 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;
+
+public interface InfoboxReadResult extends SLResult {
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxUpdateCommand.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxUpdateCommand.java
new file mode 100644
index 00000000..c2974785
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxUpdateCommand.java
@@ -0,0 +1,23 @@
+/*
+* 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;
+
+public interface InfoboxUpdateCommand extends SLCommand {
+
+ public String getInfoboxIdentifier();
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxUpdateResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxUpdateResult.java
new file mode 100644
index 00000000..d180facf
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InfoboxUpdateResult.java
@@ -0,0 +1,21 @@
+/*
+* 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;
+
+public interface InfoboxUpdateResult extends SLResult {
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InvocationStrategy.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InvocationStrategy.java
new file mode 100644
index 00000000..6b410fac
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/InvocationStrategy.java
@@ -0,0 +1,20 @@
+/*
+* 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;
+
+public interface InvocationStrategy {
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/NullOperationCommand.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/NullOperationCommand.java
new file mode 100644
index 00000000..0651f882
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/NullOperationCommand.java
@@ -0,0 +1,20 @@
+/*
+* 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;
+
+public interface NullOperationCommand extends SLCommand {
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/NullOperationResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/NullOperationResult.java
new file mode 100644
index 00000000..c36c879e
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/NullOperationResult.java
@@ -0,0 +1,20 @@
+/*
+* 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;
+
+public interface NullOperationResult extends SLResult {
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommand.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommand.java
new file mode 100644
index 00000000..a8625946
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommand.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.bku.slcommands;
+
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+
+public interface SLCommand {
+
+ public final String NAMESPACE_URI = "http://www.buergerkarte.at/namespaces/securitylayer/1.2#";
+
+ public String getName();
+
+ public void init(SLCommandContext aCtx, Object aUnmarshalledRequest) throws SLCommandException;
+
+ public SLResult execute();
+
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandContext.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandContext.java
new file mode 100644
index 00000000..5af2afac
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandContext.java
@@ -0,0 +1,55 @@
+/*
+* 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;
+
+import java.util.Locale;
+
+import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerContext;
+import at.gv.egiz.stal.STAL;
+
+public class SLCommandContext {
+
+ private STAL stal;
+ private URLDereferencerContext urlDerefCtx;
+
+ private Locale locale;
+
+ public void setSTAL(STAL aStal) {
+ this.stal = aStal;
+ }
+
+ public void setURLDereferencerContext(URLDereferencerContext aCtx) {
+ this.urlDerefCtx = aCtx;
+ }
+
+ public STAL getSTAL() {
+ return stal;
+ }
+
+ public URLDereferencerContext getURLDereferencerContext() {
+ return urlDerefCtx;
+ }
+
+ public Locale getLocale() {
+ return locale;
+ }
+
+ public void setLocale(Locale locale) {
+ this.locale = locale;
+ }
+
+} \ No newline at end of file
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
new file mode 100644
index 00000000..6e84867e
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandFactory.java
@@ -0,0 +1,395 @@
+/*
+* 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;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+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;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+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.ReportingValidationEventHandler;
+
+public class SLCommandFactory {
+
+ /**
+ * Schema files required for Security Layer command validation.
+ */
+ 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.20020225.xsd",
+ "at/gv/egiz/bku/slcommands/schema/Core.20020831.xsd"
+ };
+ /**
+ * Logging facility.
+ */
+ static Log log = LogFactory.getLog(SLCommandFactory.class);
+ /**
+ * The instance returned by {@link #getInstance()}.
+ */
+ private static SLCommandFactory instance;
+ /**
+ * Schema for Security Layer command validation.
+ */
+ private Schema slSchema;
+ /**
+ * The JAXBContext.
+ */
+ private JAXBContext jaxbContext;
+ /**
+ * The map of <namespaceURI>:<localName> to implementation class of the
+ * corresponding {@link SLCommand}.
+ */
+ private Map<String, Class<? extends SLCommand>> slRequestTypeMap = new HashMap<String, Class<? extends SLCommand>>();
+
+ /**
+ * The mapping of a requests's qualified name to a concrete command factories.
+ */
+ private Map<QName, AbstractSLCommandFactory> slCommandFactories = new HashMap<QName, AbstractSLCommandFactory>();
+
+ /**
+ * Configures the singleton instance with command implementations
+ * @param commandImplMap
+ * @throws ClassNotFoundException
+ */
+ @SuppressWarnings("unchecked")
+ public void setCommandImpl(Map<String, String> commandImplMap) throws ClassNotFoundException {
+ ClassLoader cl = getClass().getClassLoader();
+ for (String key : commandImplMap.keySet()) {
+ Class<? extends SLCommand> impl = (Class<? extends SLCommand>) cl.loadClass(commandImplMap.get(key));
+ log.debug("Registering sl command implementation for :"+key+ "; implementation class: "+impl.getCanonicalName());
+ slRequestTypeMap.put(key, impl);
+ }
+ }
+
+ public void setConcreteFactories(Map<QName, AbstractSLCommandFactory> factories) {
+ if (log.isDebugEnabled()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Registered sl command factory for");
+ for (QName qname : factories.keySet()) {
+ sb.append("\n " + qname + " : " + factories.get(qname).getClass());
+ }
+ log.debug(sb);
+ }
+ slCommandFactories = factories;
+ }
+
+ /**
+ * Register an {@link SLCommand} implementation class of a Security Layer
+ * command with the given <code>namespaceUri</code> and <code>localname</code>
+ * .
+ *
+ * @param namespaceUri
+ * the namespace URI of the Security Layer command
+ * @param localname
+ * the localname of the Security Layer command
+ * @param slCommandClass
+ * the implementation class, or <code>null</code> to deregister a
+ * currently registered class
+ */
+ public void setImplClass(String namespaceUri, String localname,
+ Class<? extends SLCommand> slCommandClass) {
+ if (slCommandClass != null) {
+ slRequestTypeMap.put(namespaceUri + ":" + localname, slCommandClass);
+ } else {
+ slRequestTypeMap.remove(namespaceUri + ":" + localname);
+ }
+ }
+
+ /**
+ * Returns the implementation class of an {@link SLCommand} with the given
+ * <code>name</code>, or <code>null</code> if no such class is registered.
+ *
+ * @param name
+ * the <code>QName</code> of the Security Layer command
+ * @return the implementation class, or <code>null</code> if no class is
+ * registered for the given <code>name</code>
+ */
+ public Class<? extends SLCommand> getImplClass(QName name) {
+ String namespaceURI = name.getNamespaceURI();
+ String localPart = name.getLocalPart();
+ return slRequestTypeMap.get(namespaceURI + ":" + localPart);
+ }
+
+ /**
+ * Sets the schema to validate Security Layer commands with.
+ *
+ * @param slSchema the schema to validate Security Layer commands with
+ */
+ public void setSLSchema(Schema slSchema) {
+ this.slSchema = slSchema;
+ }
+
+ /**
+ * @return the jaxbContext
+ */
+ public JAXBContext getJaxbContext() {
+ ensureJaxbContext();
+ return jaxbContext;
+ }
+
+ /**
+ * @param jaxbContext the jaxbContext to set
+ */
+ public void setJaxbContext(JAXBContext jaxbContext) {
+ this.jaxbContext = jaxbContext;
+ }
+
+ /**
+ * Initialize the JAXBContext.
+ */
+ private synchronized void ensureJaxbContext() {
+ if (jaxbContext == null) {
+ 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();
+ 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);
+ }
+ }
+ }
+
+ /**
+ * Initialize the security layer schema.
+ */
+ private synchronized void ensureSchema() {
+ if (slSchema == null) {
+ try {
+ SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ ClassLoader cl = SLCommandFactory.class.getClassLoader();
+ Source[] sources = new Source[SCHEMA_FILES.length];
+ for (int i = 0; i < SCHEMA_FILES.length; i++) {
+ String schemaFile = SCHEMA_FILES[i];
+ URL schemaURL = cl.getResource(schemaFile);
+ if (schemaURL == null) {
+ throw new SLRuntimeException("Failed to load schema file " + schemaFile + ".");
+ }
+ log.debug("Schema location: " + schemaURL);
+ sources[i] = new StreamSource(schemaURL.openStream());
+ }
+ Schema schema = schemaFactory.newSchema(sources);
+ log.debug("Schema successfully created.");
+ setSLSchema(schema);
+ } catch (SAXException e) {
+ log.error("Failed to load security layer schema.", e);
+ throw new SLRuntimeException("Failed to load security layer schema.", e);
+ } catch (IOException e) {
+ log.error("Failed to load security layer schema.", e);
+ throw new SLRuntimeException("Failed to load security layer schema.", e);
+ }
+
+ }
+ }
+
+ /**
+ * Get an instance of the <code>SLCommandFactory</code>.
+ */
+ public synchronized static SLCommandFactory getInstance() {
+ if (instance == null) {
+ instance = new SLCommandFactory();
+ instance.ensureJaxbContext();
+ instance.ensureSchema();
+ }
+ return instance;
+ }
+
+ /**
+ * Private constructor used by {@link #getInstance()}.
+ */
+ private SLCommandFactory() {
+ }
+
+ /**
+ * Unmarshalls from the given <code>source</code>.
+ *
+ * @see Unmarshaller#unmarshal(Source)
+ *
+ * <em>Note:</em>Could replace JAXB's unmarshal-time validation engine (see commented code), however,
+ * we need a redirect filter.
+ *
+ * @param source
+ * the source to unmarshal from
+ * @return the object returned by {@link Unmarshaller#unmarshal(Source)}
+ * @throws SLRequestException
+ * if unmarshalling fails
+ * @throws SLRuntimeException
+ * if an unexpected error occurs configuring the unmarshaller or if
+ * unmarshalling fails with an unexpected error
+ */
+ protected Object unmarshal(Source source) throws SLRuntimeException,
+ SLRequestException {
+
+ Object object;
+ ReportingValidationEventHandler validationEventHandler = new ReportingValidationEventHandler();
+ try {
+
+ XMLInputFactory inputFactory = XMLInputFactory.newInstance();
+ XMLEventReader eventReader = inputFactory.createXMLEventReader(source);
+ RedirectEventFilter redirectEventFilter = new RedirectEventFilter();
+ XMLEventReader filteredReader = inputFactory.createFilteredReader(eventReader, redirectEventFilter);
+
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ unmarshaller.setListener(new RedirectUnmarshallerListener(redirectEventFilter));
+ if (slSchema != null) {
+ unmarshaller.setSchema(slSchema);
+ }
+ log.trace("Before unmarshal().");
+ unmarshaller.setEventHandler(validationEventHandler);
+ object = unmarshaller.unmarshal(filteredReader);
+ log.trace("After unmarshal().");
+ } catch (UnmarshalException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Failed to unmarshall security layer request.", e);
+ } 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,
+ SLExceptionMessages.EC3000_UNCLASSIFIED, new Object[]{cause.getMessage()});
+ } else {
+ throw new SLRequestException(3000,
+ SLExceptionMessages.EC3000_UNCLASSIFIED, new Object[]{e});
+ }
+ } catch (JAXBException e) {
+ // unexpected error
+ log.error("Failed to unmarshall security layer request.", e);
+ throw new SLRuntimeException(e);
+ } catch (XMLStreamException e) {
+ // unexpected error
+ log.error("Failed to unmarshall security layer request.", e);
+ throw new SLRuntimeException(e);
+ }
+
+ return object;
+
+ }
+
+ /**
+ * Creates a new <code>SLCommand</code> from the given <code>source</code> and
+ * <code>context</code>.
+ *
+ * @param source
+ * the <code>Source</code> to unmarshall from
+ * @param context
+ * the context for the created <code>SLCommand</code>
+ * @return the <code>SLCommand</code> unmarshalled from the given
+ * <code>source</code>
+ * @throws SLRequestException
+ * if unmarshalling fails
+ * @throws SLCommandException
+ * if command ist not supported
+ * @throws SLRuntimeException
+ * if an unexpected error occurs configuring the unmarshaller, if
+ * unmarshalling fails with an unexpected error or if the
+ * corresponding <code>SLCommand</code> could not be instantiated
+ * @throws SLVersionException
+ */
+ @SuppressWarnings("unchecked")
+ public SLCommand createSLCommand(Source source, SLCommandContext context)
+ throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException {
+
+ DebugReader dr = null;
+ if (log.isTraceEnabled() && source instanceof StreamSource) {
+ StreamSource streamSource = (StreamSource) source;
+ if (streamSource.getReader() != null) {
+ dr = new DebugReader(streamSource.getReader(), "SLCommand unmarshalled from:\n");
+ streamSource.setReader(dr);
+ }
+ }
+
+ Object object;
+ try {
+ object = unmarshal(source);
+ } catch (SLRequestException e) {
+ throw e;
+ } finally {
+ if (dr != null) {
+ log.trace(dr.getCachedString());
+ }
+ }
+
+ if (!(object instanceof JAXBElement)) {
+ // invalid request
+ log.info("Invalid security layer request. " + object.toString());
+ throw new SLRequestException(3002, SLExceptionMessages.EC3002_INVALID,
+ new Object[]{object.toString()});
+ }
+
+ 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());
+ }
+
+ AbstractSLCommandFactory concreteFactory = slCommandFactories.get(qName);
+ if (concreteFactory == null) {
+ // command not supported
+ log.info("Unsupported command received: " + qName.toString());
+ throw new SLCommandException(4011,
+ SLExceptionMessages.EC4011_NOTIMPLEMENTED, new Object[]{qName.toString()});
+ }
+
+ return concreteFactory.createSLCommand(context, (JAXBElement<?>) object);
+
+ }
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandInvoker.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandInvoker.java
new file mode 100644
index 00000000..c28288c9
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandInvoker.java
@@ -0,0 +1,46 @@
+/*
+* 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;
+
+import at.gv.egiz.bku.slexceptions.SLCanceledException;
+import at.gv.egiz.bku.slexceptions.SLException;
+
+public interface SLCommandInvoker {
+
+ /**
+ *
+ * @param aContext
+ * @throws SLCanceledException if the security management prevents execution of this command
+ */
+ public void invoke(SLSourceContext aContext) throws SLException;
+
+ /**
+ *
+ * @param aContext
+ * @return
+ * @throws SLCanceledException if the security management prevents execution of this command
+ */
+ public SLResult getResult(SLTargetContext aContext) throws SLException;
+
+ public void setCommand(at.gv.egiz.bku.slcommands.SLCommand aCmd);
+
+ /**
+ * Prototype creation
+ * @return
+ */
+ public SLCommandInvoker newInstance();
+} \ No newline at end of file
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.
+ * <p>
+ * 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.
+ * </p>
+ * @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 <code>SLMarshallerFactory</code>.
+ */
+ 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
+ * <code>true</code> if the marshaller should produce formated
+ * output, <code>false</code> otherwise
+ * @return an SL marshaller
+ */
+ public Marshaller createMarshaller(boolean formattedOutput) {
+ return createMarshaller(formattedOutput, false);
+ }
+
+ /**
+ * Creates an SL marshaller.
+ *
+ * @param formattedOutput
+ * <code>true</code> if the marshaller should produce formated
+ * output, <code>false</code> otherwise
+ * @param fragment
+ * <code>true</code> if the marshaller should produce a XML fragment
+ * (omit XML declaration), <code>false</code> 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
+ * <code>true</code> if the marshaller should produce formated
+ * output, <code>false</code> otherwise
+ * @return a legacy SL marshaller
+ */
+ public Marshaller createLegacyMarshaller(boolean formattedOutput) {
+ return createLegacyMarshaller(formattedOutput, false);
+ }
+
+ /**
+ * Creates a legacy SL marshaller.
+ *
+ * @param formattedOutput
+ * <code>true</code> if the marshaller should produce formated
+ * output, <code>false</code> otherwise
+ * @param fragment
+ * <code>true</code> if the marshaller should produce a XML fragment
+ * (omit XML declaration), <code>false</code> 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
new file mode 100644
index 00000000..e9e483c5
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLResult.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.slcommands;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Templates;
+
+public interface SLResult {
+
+ public static enum SLResultType {BINARY, XML};
+
+ public SLResultType getResultType();
+
+ /**
+ * The MIME Type of the Result.
+ *
+ * @return may result null if unknown.
+ */
+ public String getMimeType();
+
+ public void writeTo(Result aResult, boolean fragment);
+
+ /**
+ *
+ * @param result
+ * @param fragment TODO
+ * @param transformer may be null.
+ */
+ 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/SLSourceContext.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLSourceContext.java
new file mode 100644
index 00000000..f25a0ea4
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLSourceContext.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.bku.slcommands;
+
+import java.net.URL;
+import java.security.cert.X509Certificate;
+
+import at.gv.egiz.bku.utils.binding.Protocol;
+
+
+public class SLSourceContext {
+
+ private URL sourceUrl;
+ private boolean sourceIsDataURL;
+ private X509Certificate sourceCertificate;
+ private String sourceHTTPReferer;
+
+ public URL getSourceUrl() {
+ return sourceUrl;
+ }
+
+ public void setSourceUrl(URL sourceProtocol) {
+ this.sourceUrl = sourceProtocol;
+ }
+
+ public boolean isSourceIsDataURL() {
+ return sourceIsDataURL;
+ }
+
+ public void setSourceIsDataURL(boolean sourceIsDataURL) {
+ this.sourceIsDataURL = sourceIsDataURL;
+ }
+
+ public X509Certificate getSourceCertificate() {
+ return sourceCertificate;
+ }
+
+ public void setSourceCertificate(X509Certificate sourceCertificate) {
+ this.sourceCertificate = sourceCertificate;
+ }
+
+ public String getSourceHTTPReferer() {
+ return sourceHTTPReferer;
+ }
+
+ public void setSourceHTTPReferer(String sourceHTTPReferer) {
+ this.sourceHTTPReferer = sourceHTTPReferer;
+ }
+
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLTargetContext.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLTargetContext.java
new file mode 100644
index 00000000..f9df3ced
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLTargetContext.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.slcommands;
+
+import java.net.URL;
+import java.security.cert.X509Certificate;
+
+public class SLTargetContext {
+ private URL targetUrl;
+ private boolean targetIsDataURL;
+ private X509Certificate targetCertificate;
+
+ public URL getTargetUrl() {
+ return targetUrl;
+ }
+
+ public void setTargetUrl(URL targetUrl) {
+ this.targetUrl = targetUrl;
+ }
+
+ public boolean isTargetIsDataURL() {
+ return targetIsDataURL;
+ }
+
+ public void setTargetIsDataURL(boolean targetIsDataURL) {
+ this.targetIsDataURL = targetIsDataURL;
+ }
+
+ public X509Certificate getTargetCertificate() {
+ return targetCertificate;
+ }
+
+ public void setTargetCertificate(X509Certificate targetCertificate) {
+ this.targetCertificate = targetCertificate;
+ }
+
+} \ 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
new file mode 100644
index 00000000..9a4536e6
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractAssocArrayInfobox.java
@@ -0,0 +1,299 @@
+/*
+ * 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;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxAssocArrayPairType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadDataAssocArrayType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadParamsAssocArrayType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadRequestType;
+import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory;
+import at.buergerkarte.namespaces.securitylayer._1.XMLContentType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadParamsAssocArrayType.ReadKeys;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadParamsAssocArrayType.ReadPairs;
+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.SLMarshallerFactory;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+
+/**
+ * An abstract base class for {@link Infobox} implementations of type associative array.
+ *
+ * @author mcentner
+ */
+public abstract class AbstractAssocArrayInfobox extends AbstractInfoboxImpl
+ implements AssocArrayInfobox {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(AbstractAssocArrayInfobox.class);
+
+ /**
+ * The search string pattern.
+ */
+ public static final String SEARCH_STRING_PATTERN = "(.&&[^/])+(/.&&[^/])*";
+
+ /**
+ * @return the keys available in this infobox.
+ */
+ public abstract String[] getKeys();
+
+ /**
+ * @return <code>true</code> if the values are XML entities, or <code>false</code> otherwise.
+ */
+ public abstract boolean isValuesAreXMLEntities();
+
+ /**
+ * Returns a key to value mapping for the given <code>keys</code>.
+ *
+ * @param keys a list of keys
+ * @param cmdCtx the command context
+ *
+ * @return a key to value mapping for the given <code>keys</code>.
+ *
+ * @throws SLCommandException if obtaining the values fails
+ */
+ public abstract Map<String, Object> getValues(List<String> keys, SLCommandContext cmdCtx) throws SLCommandException;
+
+ /**
+ * Returns all keys that match the given <code>searchString</code>.
+ *
+ * @param searchString the search string
+ *
+ * @return all keys that match the given <code>searchString</code>
+ *
+ * @throws SLCommandException if the given search string is invalid
+ */
+ protected List<String> selectKeys(String searchString) throws SLCommandException {
+
+ if ("*".equals(searchString) || "**".equals(searchString)) {
+ return Arrays.asList(getKeys());
+ }
+
+ if (!searchString.contains("*")) {
+ Arrays.asList(getKeys()).contains(searchString);
+ return Collections.singletonList(searchString);
+ }
+
+ if (Pattern.matches(SEARCH_STRING_PATTERN, searchString)) {
+
+// for (int i = 0; i < searchString.length(); i++) {
+// int codePoint = searchString.codePointAt(i);
+//
+// }
+
+ // TODO : build pattern
+ return Collections.emptyList();
+ } else {
+ log.info("Got invalid search string '" + searchString + "'");
+ throw new SLCommandException(4010);
+ }
+
+ }
+
+ /**
+ * Read all keys specified by <code>readKeys</code>.
+ *
+ * @param readKeys
+ * the ReadKeys element
+ * @param cmdCtx
+ * the command context
+ * @return a corresponding InfoboxReadResult
+ *
+ * @throws SLCommandException
+ * if the ReadKeys element is invalid or obtaining the corresponding
+ * values fails
+ */
+ protected InfoboxReadResult readKeys(ReadKeys readKeys, SLCommandContext cmdCtx) throws SLCommandException {
+
+ List<String> selectedKeys = selectKeys(readKeys.getSearchString());
+
+ if (readKeys.isUserMakesUnique() && selectedKeys.size() > 1) {
+ log.info("UserMakesUnique not supported");
+ // TODO: give more specific error message
+ throw new SLCommandException(4010);
+ }
+
+ ObjectFactory objectFactory = new ObjectFactory();
+
+ InfoboxReadDataAssocArrayType infoboxReadDataAssocArrayType = objectFactory
+ .createInfoboxReadDataAssocArrayType();
+
+ List<String> keys = infoboxReadDataAssocArrayType.getKey();
+ keys.addAll(selectedKeys);
+
+ return new InfoboxReadResultImpl(infoboxReadDataAssocArrayType);
+
+ }
+
+ /**
+ * Read all pairs specified by <code>readPairs</code>.
+ *
+ * @param readPairs
+ * the readPairs element
+ * @param cmdCtx
+ * the command context
+ * @return a corresponding InfoboxReadResult
+ *
+ * @throws SLCommandException
+ * if the ReadPairs element is invalid or obtaining the corresponding
+ * values fails
+ */
+ protected InfoboxReadResult readPairs(ReadPairs readPairs, SLCommandContext cmdCtx) throws SLCommandException {
+
+ if (readPairs.isValuesAreXMLEntities() && !isValuesAreXMLEntities()) {
+ log.info("Got valuesAreXMLEntities=" + readPairs.isValuesAreXMLEntities() + " but infobox type is binary.");
+ throw new SLCommandException(4010);
+ }
+
+ List<String> selectedKeys = selectKeys(readPairs.getSearchString());
+
+ if (readPairs.isUserMakesUnique() && selectedKeys.size() > 1) {
+ log.info("UserMakesUnique not supported");
+ // TODO: give more specific error message
+ throw new SLCommandException(4010);
+ }
+
+ return new InfoboxReadResultImpl(marshallPairs(selectedKeys, getValues(
+ selectedKeys, cmdCtx), readPairs.isValuesAreXMLEntities()));
+ }
+
+ /**
+ * Read the value specified by <code>readPairs</code>.
+ *
+ * @param readValue
+ * the readValue element
+ * @param cmdCtx
+ * the command context
+ * @return a corresponding InfoboxReadResult
+ *
+ * @throws SLCommandException
+ * if the ReadValue element is invalid or obtaining the corresponding
+ * values fails
+ */
+ protected InfoboxReadResult readValue(ReadValue readValue, SLCommandContext cmdCtx) throws SLCommandException {
+
+ if (readValue.isValueIsXMLEntity() && !isValuesAreXMLEntities()) {
+ log.info("Got valuesAreXMLEntities=" + readValue.isValueIsXMLEntity() + " but infobox type is binary.");
+ throw new SLCommandException(4010);
+ }
+
+ List<String> selectedKeys;
+
+ if (Arrays.asList(getKeys()).contains(readValue.getKey())) {
+ selectedKeys = Collections.singletonList(readValue.getKey());
+ } else {
+ selectedKeys = Collections.emptyList();
+ }
+
+ return new InfoboxReadResultImpl(marshallPairs(selectedKeys, getValues(
+ selectedKeys, cmdCtx), readValue.isValueIsXMLEntity()));
+
+ }
+
+ protected InfoboxReadDataAssocArrayType marshallPairs(List<String> selectedKeys, Map<String, Object> values, boolean areXMLEntities) throws SLCommandException {
+
+ ObjectFactory objectFactory = new ObjectFactory();
+
+ InfoboxReadDataAssocArrayType infoboxReadDataAssocArrayType = objectFactory.createInfoboxReadDataAssocArrayType();
+
+ for (String key : selectedKeys) {
+ InfoboxAssocArrayPairType infoboxAssocArrayPairType = objectFactory.createInfoboxAssocArrayPairType();
+ infoboxAssocArrayPairType.setKey(key);
+
+ Object value = values.get(key);
+ if (areXMLEntities) {
+ if (value instanceof byte[]) {
+ log.info("Got valuesAreXMLEntities=" + areXMLEntities + " but infobox type is binary.");
+ throw new SLCommandException(4122);
+ } else {
+ XMLContentType contentType = objectFactory.createXMLContentType();
+ contentType.getContent().add(value);
+ infoboxAssocArrayPairType.setXMLContent(contentType);
+ }
+ } else {
+ infoboxAssocArrayPairType.setBase64Content((value instanceof byte[]) ? (byte[]) value : marshallValue(value));
+ }
+
+ infoboxReadDataAssocArrayType.getPair().add(infoboxAssocArrayPairType);
+ }
+
+ return infoboxReadDataAssocArrayType;
+
+ }
+
+ protected byte[] marshallValue(Object jaxbElement) throws SLCommandException {
+
+ Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(false);
+ ByteArrayOutputStream result = new ByteArrayOutputStream();
+ try {
+ marshaller.marshal(jaxbElement, result);
+ } catch (JAXBException e) {
+ log.info("Failed to marshall infobox content.", e);
+ throw new SLCommandException(4122);
+ }
+
+ return result.toByteArray();
+
+ }
+
+ @Override
+ public InfoboxReadResult read(InfoboxReadRequestType req,
+ SLCommandContext cmdCtx) throws SLCommandException {
+
+ InfoboxReadParamsAssocArrayType assocArrayParameters = req
+ .getAssocArrayParameters();
+
+ if (assocArrayParameters == null) {
+ log.info("Infobox type is AssocArray but got no AssocArrayParameters.");
+ throw new SLCommandException(4010);
+ }
+
+ if (assocArrayParameters.getReadKeys() != null) {
+ return readKeys(assocArrayParameters.getReadKeys(), cmdCtx);
+ }
+
+ if (assocArrayParameters.getReadPairs() != null) {
+ return readPairs(assocArrayParameters.getReadPairs(), cmdCtx);
+ }
+
+ // ReadValue
+ if (assocArrayParameters.getReadValue() != null) {
+ return readValue(assocArrayParameters.getReadValue(), cmdCtx);
+ }
+
+ log
+ .info("Infobox type is AssocArray but got invalid AssocArrayParameters.");
+ throw new SLCommandException(4010);
+
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractBinaryFileInfobox.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractBinaryFileInfobox.java
new file mode 100644
index 00000000..23394bd5
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractBinaryFileInfobox.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.slcommands.impl;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadParamsBinaryFileType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadRequestType;
+
+/**
+ * An abstract base class for {@link Infobox} implementations of type binary file.
+ *
+ * @author mcentner
+ */
+public abstract class AbstractBinaryFileInfobox extends AbstractInfoboxImpl implements BinaryFileInfobox {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(AbstractBinaryFileInfobox.class);
+
+ /**
+ * Is this infobox' content an XML entity?
+ */
+ protected boolean isXMLEntity = false;
+
+ /**
+ * @return <code>true</code> if this infobox' content is an XML entity or <code>false</code> otherwise.
+ */
+ public boolean isXMLEntity() {
+ return isXMLEntity;
+ }
+
+ /**
+ * Sets the value returned by {@link #isXMLEntity()} according to the given
+ * <code>request</code>.
+ *
+ * @param request the InfoboxReadRequest
+ */
+ public void setIsXMLEntity(InfoboxReadRequestType request) {
+
+ InfoboxReadParamsBinaryFileType binaryFileParameters = request.getBinaryFileParameters();
+ if (binaryFileParameters != null) {
+ isXMLEntity = binaryFileParameters.isContentIsXMLEntity();
+ log.debug("Got ContentIsXMLEntity=" + isXMLEntity + ".");
+ }
+
+ }
+
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractInfoboxCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractInfoboxCommandImpl.java
new file mode 100644
index 00000000..b8e4030d
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractInfoboxCommandImpl.java
@@ -0,0 +1,83 @@
+/*
+* 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;
+
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+
+/**
+ * An abstract base class for implementations of security layer infobox requests.
+ *
+ * @author mcentner
+ *
+ * @param <T>
+ */
+public abstract class AbstractInfoboxCommandImpl<T> extends SLCommandImpl<T> {
+
+ /**
+ * The infobox implementation.
+ */
+ protected Infobox infobox;
+
+ /**
+ * The infobox factory.
+ */
+ protected InfoboxFactory infoboxFactory;
+
+ /**
+ * @return the infoboxFactory
+ */
+ public InfoboxFactory getInfoboxFactory() {
+ return infoboxFactory;
+ }
+
+ /**
+ * @param infoboxFactory the infoboxFactory to set
+ */
+ public void setInfoboxFactory(InfoboxFactory infoboxFactory) {
+ this.infoboxFactory = infoboxFactory;
+ }
+
+ @Override
+ public void init(SLCommandContext ctx, Object request)
+ throws SLCommandException {
+ super.init(ctx, request);
+
+ String infoboxIdentifier = getInfoboxIdentifier(getRequestValue());
+
+ infobox = infoboxFactory.createInfobox(infoboxIdentifier);
+ }
+
+ /**
+ * Returns the infobox identifier given in <code>request</code>.
+ *
+ * @param request the request value
+ *
+ * @return the infobox identifier givne in <code>request</code>
+ */
+ protected abstract String getInfoboxIdentifier(T request);
+
+
+ public String getInfoboxIdentifier() {
+ if (infobox != null) {
+ return infobox.getIdentifier();
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractInfoboxImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractInfoboxImpl.java
new file mode 100644
index 00000000..564cb8ff
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AbstractInfoboxImpl.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.slcommands.impl;
+
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadRequestType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxUpdateRequestType;
+import at.gv.egiz.bku.slcommands.InfoboxReadResult;
+import at.gv.egiz.bku.slcommands.InfoboxUpdateResult;
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+
+/**
+ * An abstract base class for {@link Infobox} implementations.
+ *
+ * @author mcentner
+ */
+public abstract class AbstractInfoboxImpl implements Infobox {
+
+ @Override
+ public InfoboxReadResult read(InfoboxReadRequestType request,
+ SLCommandContext cmdCtx) throws SLCommandException {
+ throw new SLCommandException(4011);
+ }
+
+ @Override
+ public InfoboxUpdateResult update(InfoboxUpdateRequestType request,
+ SLCommandContext cmdCtx) throws SLCommandException {
+ throw new SLCommandException(4011);
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AssocArrayInfobox.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AssocArrayInfobox.java
new file mode 100644
index 00000000..908d95da
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/AssocArrayInfobox.java
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+/**
+ * An {@link Infobox} of type associative array as defined in Security Layer
+ * 1.2.
+ *
+ * @author mcentner
+ */
+public interface AssocArrayInfobox extends Infobox {
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BinaryFileInfobox.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BinaryFileInfobox.java
new file mode 100644
index 00000000..c27f9446
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BinaryFileInfobox.java
@@ -0,0 +1,27 @@
+/*
+* 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;
+
+/**
+ * An {@link Infobox} of type binary file as defined in Security Layer
+ * 1.2.
+ *
+ * @author mcentner
+ */
+public interface BinaryFileInfobox extends Infobox {
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CardChannelInfoboxImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CardChannelInfoboxImpl.java
new file mode 100644
index 00000000..19b84ac7
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CardChannelInfoboxImpl.java
@@ -0,0 +1,235 @@
+/*
+* 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;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.WeakHashMap;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.buergerkarte.namespaces.cardchannel.ATRType;
+import at.buergerkarte.namespaces.cardchannel.CommandAPDUType;
+import at.buergerkarte.namespaces.cardchannel.ObjectFactory;
+import at.buergerkarte.namespaces.cardchannel.ResetType;
+import at.buergerkarte.namespaces.cardchannel.ResponseAPDUType;
+import at.buergerkarte.namespaces.cardchannel.ResponseType;
+import at.buergerkarte.namespaces.cardchannel.ScriptType;
+import at.buergerkarte.namespaces.cardchannel.VerifyAPDUType;
+import at.buergerkarte.namespaces.securitylayer._1.Base64XMLContentType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadRequestType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxUpdateRequestType;
+import at.buergerkarte.namespaces.securitylayer._1.XMLContentType;
+import at.gv.egiz.bku.slcommands.InfoboxReadResult;
+import at.gv.egiz.bku.slcommands.InfoboxUpdateResult;
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+import at.gv.egiz.stal.STAL;
+import at.gv.egiz.stal.ext.APDUScriptRequest;
+import at.gv.egiz.stal.ext.APDUScriptResponse;
+import at.gv.egiz.stal.ext.APDUScriptRequest.RequestScriptElement;
+import at.gv.egiz.stal.ext.APDUScriptResponse.ResponseScriptElement;
+
+public class CardChannelInfoboxImpl extends AbstractBinaryFileInfobox {
+
+ private static Log log = LogFactory.getLog(CardChannelInfoboxImpl.class);
+
+ private static WeakHashMap<STAL, JAXBElement<ResponseType>> scriptResults = new WeakHashMap<STAL, JAXBElement<ResponseType>>();
+
+ private static JAXBContext jaxbContext;
+
+ static {
+ try {
+ jaxbContext = JAXBContext.newInstance(ObjectFactory.class.getPackage().getName());
+ } catch (JAXBException e) {
+ throw new SLRuntimeException("Failed to initalize CardChannel infobox.", e);
+ }
+ }
+
+ public CardChannelInfoboxImpl() {
+ isXMLEntity = true;
+ }
+
+ @Override
+ public String getIdentifier() {
+ return "CardChannel";
+ }
+
+ @Override
+ public InfoboxReadResult read(InfoboxReadRequestType request,
+ SLCommandContext cmdCtx) throws SLCommandException {
+
+ at.buergerkarte.namespaces.securitylayer._1.ObjectFactory objectFactory
+ = new at.buergerkarte.namespaces.securitylayer._1.ObjectFactory();
+
+ Base64XMLContentType content = objectFactory.createBase64XMLContentType();
+ XMLContentType xmlContent = objectFactory.createXMLContentType();
+ content.setXMLContent(xmlContent);
+
+ JAXBElement<ResponseType> response = scriptResults.get(cmdCtx.getSTAL());
+ if (response != null) {
+ xmlContent.getContent().add(response);
+ }
+
+ return new InfoboxReadResultImpl(content);
+
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public InfoboxUpdateResult update(InfoboxUpdateRequestType request,
+ SLCommandContext cmdCtx) throws SLCommandException {
+
+ Base64XMLContentType binaryFileParameters = request.getBinaryFileParameters();
+
+ if (binaryFileParameters.getBase64Content() != null) {
+ log.info("Got Base64Content but ContentIsXMLEntity is true.");
+ throw new SLCommandException(4010);
+ }
+
+ XMLContentType content = binaryFileParameters.getXMLContent();
+ if (content instanceof at.gv.egiz.slbinding.impl.XMLContentType) {
+
+ ByteArrayOutputStream redirectedStream = ((at.gv.egiz.slbinding.impl.XMLContentType) content).getRedirectedStream();
+ if (redirectedStream != null) {
+
+ if (log.isDebugEnabled()) {
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("CardChannel script:\n");
+ try {
+ sb.append(new String(redirectedStream.toByteArray(), "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ sb.append(e.getMessage());
+ }
+ log.debug(sb.toString());
+ }
+
+ Object object;
+ try {
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ object = unmarshaller.unmarshal(new ByteArrayInputStream(redirectedStream.toByteArray()));
+ } catch (JAXBException e) {
+ log.info("Failed to parse CardChannel script.", e);
+ throw new SLCommandException(4011);
+ }
+
+ if (object instanceof JAXBElement) {
+ executeCardChannelScript(((JAXBElement<ScriptType>) object).getValue(), cmdCtx);
+ return new InfoboxUpdateResultImpl();
+ }
+
+ }
+
+
+ }
+ log.info("Infobox identifier is '" + getIdentifier() + "' but XMLContent does not contain 'Script'.");
+ throw new SLCommandException(4010);
+
+ }
+
+ protected void executeCardChannelScript(ScriptType script,
+ SLCommandContext cmdCtx) throws SLCommandException {
+
+ List<Object> resetOrCommandAPDUOrVerifyAPDU = script.getResetOrCommandAPDUOrVerifyAPDU();
+ List<RequestScriptElement> requestScript = new ArrayList<RequestScriptElement>();
+
+ for (Object element : resetOrCommandAPDUOrVerifyAPDU) {
+
+ if (element instanceof ResetType) {
+
+ requestScript.add(new APDUScriptRequest.Reset());
+
+ } else if (element instanceof CommandAPDUType) {
+
+ CommandAPDUType commandAPDU = (CommandAPDUType) element;
+ int sequence = (commandAPDU.getSequence() != null)
+ ? commandAPDU.getSequence().intValue()
+ : 0;
+
+ requestScript.add(
+ new APDUScriptRequest.Command(
+ sequence,
+ commandAPDU.getValue(),
+ commandAPDU.getExpectedSW()));
+
+ } else if (element instanceof VerifyAPDUType) {
+ log.warn("CardChannel script command 'VerifyAPDU' not implemented.");
+ throw new SLCommandException(4011);
+ }
+ }
+
+ APDUScriptRequest scriptRequest = new APDUScriptRequest(requestScript);
+
+ STAL stal = cmdCtx.getSTAL();
+ STALHelper helper = new STALHelper(stal);
+
+ helper.transmitSTALRequest(Collections.singletonList(scriptRequest));
+
+ List<ResponseScriptElement> responseScript = ((APDUScriptResponse) helper
+ .nextResponse(APDUScriptResponse.class)).getScript();
+
+ ObjectFactory objectFactory = new ObjectFactory();
+
+ ResponseType responseType = objectFactory.createResponseType();
+
+
+ for (ResponseScriptElement element : responseScript) {
+
+ if (element instanceof APDUScriptResponse.ATR) {
+
+ byte[] atr = ((APDUScriptResponse.ATR) element).getAtr();
+
+ ATRType atrType = objectFactory.createATRType();
+ atrType.setValue(atr);
+ atrType.setRc(BigInteger.ZERO);
+ responseType.getATROrResponseAPDU().add(atrType);
+
+ } else if (element instanceof APDUScriptResponse.Response) {
+
+ APDUScriptResponse.Response response = (APDUScriptResponse.Response) element;
+
+ ResponseAPDUType responseAPDUType = objectFactory.createResponseAPDUType();
+ responseAPDUType.setSequence(BigInteger.valueOf(response.getSequence()));
+// if (response.getRc() != 0) {
+ responseAPDUType.setRc(BigInteger.valueOf(response.getRc()));
+// }
+ responseAPDUType.setSw(response.getSw());
+ responseAPDUType.setValue(response.getApdu());
+
+ responseType.getATROrResponseAPDU().add(responseAPDUType);
+ }
+
+ }
+
+ scriptResults.put(stal, objectFactory.createResponse(responseType));
+ }
+
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CertificatesInfoboxImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CertificatesInfoboxImpl.java
new file mode 100644
index 00000000..0208f137
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CertificatesInfoboxImpl.java
@@ -0,0 +1,112 @@
+/*
+* 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;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+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;
+
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.stal.InfoboxReadRequest;
+import at.gv.egiz.stal.STALRequest;
+
+/**
+ * An implementation of the {@link Infobox} <em>Certificates</em> as
+ * specified in Security Layer 1.2.
+ *
+ * @author mcentner
+ */
+public class CertificatesInfoboxImpl extends AbstractAssocArrayInfobox {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(CertificatesInfoboxImpl.class);
+
+ /**
+ * The valid keys.
+ */
+ public static final String[] CERTIFICATES_KEYS = new String[] {
+ "SecureSignatureKeypair",
+ "CertifiedKeypair" };
+
+ @Override
+ public String getIdentifier() {
+ return "Certificates";
+ }
+
+ @Override
+ public String[] getKeys() {
+ return CERTIFICATES_KEYS;
+ }
+
+ @Override
+ public boolean isValuesAreXMLEntities() {
+ return false;
+ }
+
+ @Override
+ public Map<String, Object> getValues(List<String> certificates, SLCommandContext cmdCtx) throws SLCommandException {
+
+ STALHelper stalHelper = new STALHelper(cmdCtx.getSTAL());
+
+ if (certificates != null && !certificates.isEmpty()) {
+
+ List<STALRequest> stalRequests = new ArrayList<STALRequest>();
+
+ // get certificates
+ InfoboxReadRequest infoboxReadRequest;
+ for (int i = 0; i < certificates.size(); i++) {
+ infoboxReadRequest = new InfoboxReadRequest();
+ infoboxReadRequest.setInfoboxIdentifier(certificates.get(i));
+ stalRequests.add(infoboxReadRequest);
+ }
+
+ stalHelper.transmitSTALRequest(stalRequests);
+
+ List<X509Certificate> x509Certs = stalHelper.getCertificatesFromResponses();
+
+ Map<String, Object> values = new HashMap<String, Object>();
+
+ for (int i = 0; i < certificates.size(); i++) {
+ try {
+ values.put(certificates.get(i), x509Certs.get(i).getEncoded());
+ } catch (CertificateEncodingException e) {
+ log.error("Failed to encode certificate.", e);
+ throw new SLCommandException(4000);
+ }
+ }
+
+ return values;
+
+ } else {
+
+ return new HashMap<String, Object>();
+
+ }
+
+
+ }
+
+}
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
new file mode 100644
index 00000000..01686641
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureCommandImpl.java
@@ -0,0 +1,219 @@
+/*
+ * 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;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.crypto.MarshalException;
+import javax.xml.crypto.URIReferenceException;
+import javax.xml.crypto.dsig.XMLSignatureException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.ls.DOMImplementationLS;
+import org.w3c.dom.ls.LSSerializer;
+
+import at.buergerkarte.namespaces.securitylayer._1.CreateXMLSignatureRequestType;
+import at.buergerkarte.namespaces.securitylayer._1.DataObjectInfoType;
+import at.gv.egiz.bku.slcommands.CreateXMLSignatureCommand;
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slcommands.SLResult;
+import at.gv.egiz.bku.slcommands.impl.xsect.AlgorithmMethodFactory;
+import at.gv.egiz.bku.slcommands.impl.xsect.AlgorithmMethodFactoryImpl;
+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.STALRequest;
+
+/**
+ * This class implements the security layer command
+ * <code>CreateXMLSignatureRequest</code>.
+ *
+ * @author mcentner
+ */
+public class CreateXMLSignatureCommandImpl extends
+ SLCommandImpl<CreateXMLSignatureRequestType> implements
+ CreateXMLSignatureCommand {
+
+ /**
+ * Logging facility.
+ */
+ protected static Log log = LogFactory
+ .getLog(CreateXMLSignatureCommandImpl.class);
+
+ /**
+ * The signing certificate.
+ */
+ protected X509Certificate signingCertificate;
+
+ /**
+ * The keybox identifier of the key used for signing.
+ */
+ protected String keyboxIdentifier;
+
+ /**
+ * The to-be signed signature.
+ */
+ protected Signature signature;
+
+ @Override
+ public void init(SLCommandContext ctx, Object unmarshalledRequest)
+ throws SLCommandException {
+ super.init(ctx, unmarshalledRequest);
+ }
+
+ @Override
+ public void prepareXMLSignature() throws SLCommandException,
+ SLRequestException {
+
+ CreateXMLSignatureRequestType request = getRequestValue();
+
+ // TODO: make configurable?
+ IdValueFactory idValueFactory = new IdValueFactoryImpl();
+
+ // TODO: make configurable?
+ AlgorithmMethodFactory algorithmMethodFactory;
+ try {
+ algorithmMethodFactory = new AlgorithmMethodFactoryImpl(
+ signingCertificate);
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Failed to get DigestMethod.", e);
+ throw new SLCommandException(4006);
+ }
+
+ signature = new Signature(getCmdCtx().getURLDereferencerContext(),
+ idValueFactory, algorithmMethodFactory);
+
+ // SigningTime
+ signature.setSigningTime(new Date());
+
+ // SigningCertificate
+ signature.setSignerCeritifcate(signingCertificate);
+
+ // SignatureInfo
+ if (request.getSignatureInfo() != null) {
+ signature.setSignatureInfo(request.getSignatureInfo());
+ }
+
+ // DataObjects
+ for (DataObjectInfoType dataObjectInfo : request.getDataObjectInfo()) {
+ signature.addDataObject(dataObjectInfo);
+ }
+
+ signature.buildXMLSignature();
+
+ }
+
+ /**
+ * Gets the signing certificate from STAL.
+ *
+ * @throws SLCommandException
+ * if getting the singing certificate fails
+ */
+ private void getSigningCertificate() throws SLCommandException {
+
+ CreateXMLSignatureRequestType request = getRequestValue();
+ keyboxIdentifier = request.getKeyboxIdentifier();
+
+ InfoboxReadRequest stalRequest = new InfoboxReadRequest();
+ stalRequest.setInfoboxIdentifier(keyboxIdentifier);
+
+ stalHelper.transmitSTALRequest(Collections.singletonList((STALRequest) stalRequest));
+ List<X509Certificate> certificates = stalHelper.getCertificatesFromResponses();
+ if (certificates == null || certificates.size() != 1) {
+ log.info("Got an unexpected number of certificates from STAL.");
+ throw new SLCommandException(4000);
+ }
+ signingCertificate = certificates.get(0);
+
+ }
+
+ /**
+ * Signs the signature.
+ *
+ * @throws SLCommandException
+ * if signing the signature fails
+ * @throws SLViewerException
+ */
+ private void signXMLSignature() throws SLCommandException, SLViewerException {
+
+ try {
+ signature.sign(getCmdCtx().getSTAL(), keyboxIdentifier);
+ } catch (MarshalException e) {
+ log.error("Failed to marshall XMLSignature.", e);
+ throw new SLCommandException(4000);
+ } catch (XMLSignatureException e) {
+ if (e.getCause() instanceof URIReferenceException) {
+ URIReferenceException uriReferenceException = (URIReferenceException) e
+ .getCause();
+ if (uriReferenceException.getCause() instanceof SLCommandException) {
+ throw (SLCommandException) uriReferenceException.getCause();
+ }
+ }
+ log.error("Failed to sign XMLSignature.", e);
+ throw new SLCommandException(4000);
+ }
+
+ }
+
+ @Override
+ public SLResult execute() {
+ try {
+
+ // get certificate in order to select appropriate algorithms for hashing
+ // and signing
+ getSigningCertificate();
+
+ // prepare the XMLSignature for signing
+ prepareXMLSignature();
+
+ // sign the XMLSignature
+ signXMLSignature();
+
+ if (log.isTraceEnabled()) {
+
+ DOMImplementationLS domImplLS = DOMUtils.getDOMImplementationLS();
+ LSSerializer serializer = domImplLS.createLSSerializer();
+ String debugString = serializer.writeToString(signature.getDocument());
+
+ log.trace(debugString);
+
+ }
+
+ return new CreateXMLSignatureResultImpl(signature.getDocument());
+
+ } catch (SLException e) {
+ return new ErrorResultImpl(e, cmdCtx.getLocale());
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "CreateXMLSignatureRequest";
+ }
+
+}
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
new file mode 100644
index 00000000..19df4334
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureResultImpl.java
@@ -0,0 +1,107 @@
+/*
+* 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;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.transform.Result;
+import javax.xml.transform.Templates;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+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.SLMarshallerFactory;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+
+/**
+ * This calls implements the result of the security layer command <code>CreateXMLSignature</code>.
+ *
+ * @author mcentner
+ */
+public class CreateXMLSignatureResultImpl extends SLResultImpl {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(CreateXMLSignatureResultImpl.class);
+
+ /**
+ * The document containing the XMLSignature.
+ */
+ protected Document doc;
+
+ /**
+ * Creates a new instance of this CreateXMLSignatureResultImpl with the given
+ * signature <code>document</code>.
+ *
+ * @param document the signature document
+ *
+ * @throws NullPointerException if <code>document</code> is <code>null</code>
+ */
+ public CreateXMLSignatureResultImpl(Document document) {
+ super();
+
+ if (document == null) {
+ throw new NullPointerException("Argument 'document' must not be null.");
+ }
+
+ this.doc = document;
+
+ marshallCreateXMLSignatureResponse();
+ }
+
+ /**
+ * Marshalls the <code>CreateXMLSignatureResponse</code>.
+ */
+ private void marshallCreateXMLSignatureResponse() {
+
+ ObjectFactory factory = new ObjectFactory();
+
+ CreateXMLSignatureResponseType createCreateXMLSignatureResponseType = factory.createCreateXMLSignatureResponseType();
+ JAXBElement<CreateXMLSignatureResponseType> createCreateXMLSignatureResponse = factory.createCreateXMLSignatureResponse(createCreateXMLSignatureResponseType);
+
+ DocumentFragment fragment = doc.createDocumentFragment();
+
+ Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(false);
+ try {
+ marshaller.marshal(createCreateXMLSignatureResponse, fragment);
+ } catch (JAXBException e) {
+ log.error("Failed to marshall 'CreateXMLSignatureResponse'", e);
+ throw new SLRuntimeException(e);
+ }
+
+ Node child = fragment.getFirstChild();
+ if (child instanceof Element) {
+ Node node = doc.replaceChild(child, doc.getDocumentElement());
+ child.appendChild(node);
+ }
+
+ }
+
+ @Override
+ 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/DataObjectHashDataInput.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java
new file mode 100644
index 00000000..57358ba0
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java
@@ -0,0 +1,59 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.gv.egiz.bku.slcommands.impl;
+
+import at.gv.egiz.bku.binding.HttpUtil;
+import at.gv.egiz.bku.slcommands.impl.xsect.DataObject;
+import at.gv.egiz.stal.HashDataInput;
+import java.io.InputStream;
+
+/**
+ * DataObject-backed HashDataInput
+ * If <a href="XMLSignContext.html#Supported Properties">reference caching</a> is enabled,
+ * the hashdata input stream can be obtained repeatedly.
+ * @author clemens
+ */
+public class DataObjectHashDataInput implements HashDataInput {
+
+ protected DataObject dataObject;
+
+ public DataObjectHashDataInput(DataObject dataObject) {
+ if (dataObject.getReference() == null)
+ throw new NullPointerException("DataObject reference must not be null");
+ this.dataObject = dataObject;
+ }
+
+ @Override
+ public String getReferenceId() {
+ return dataObject.getReference().getId();
+ }
+
+ @Override
+ public String getMimeType() {
+ String contentType = dataObject.getMimeType();
+ return contentType.split(";")[0].trim();
+ }
+
+ /**
+ * may be called repeatedly
+ * @return the pre-digested input stream if reference caching is enabled, null otherwise
+ */
+ @Override
+ public InputStream getHashDataInput() {
+ return dataObject.getReference().getDigestInputStream();
+ }
+
+ @Override
+ public String getEncoding() {
+ 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/ErrorResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImpl.java
new file mode 100644
index 00000000..aedde238
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImpl.java
@@ -0,0 +1,67 @@
+/*
+* 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;
+
+import java.util.Locale;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Templates;
+
+import at.gv.egiz.bku.slcommands.ErrorResult;
+import at.gv.egiz.bku.slexceptions.SLException;
+
+/**
+ * This class implements the security layer result <code>ErrorResponse</code>.
+ *
+ * @author mcentner
+ */
+public class ErrorResultImpl extends SLResultImpl implements ErrorResult {
+
+ /**
+ * The exception containing information provided in the <code>ErrorResponse</code>.
+ */
+ protected SLException slException;
+
+ /**
+ * The locale to be used for rendering an <code>ErrorResponse</code>.
+ */
+ protected Locale locale;
+
+ /**
+ * Creates a new instance of this ErrorResultImpl with the given
+ * <code>slException</code> containing information provided in the
+ * <code>ErrorResponse</code> and the <code>locale</code> for rendering
+ * the <code>ErrorResponse</code>.
+ *
+ * @param slException the exception
+ * @param locale the locale
+ */
+ public ErrorResultImpl(SLException slException, Locale locale) {
+ this.slException = slException;
+ this.locale = locale;
+ }
+
+ @Override
+ public void writeTo(Result result, Templates templates, boolean fragment) {
+ if (locale == null) {
+ writeErrorTo(slException, result, templates, fragment);
+ } else {
+ writeErrorTo(slException, result, templates, locale, fragment);
+ }
+ }
+
+} \ No newline at end of file
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
new file mode 100644
index 00000000..0c2b96f9
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/GetStatusCommandImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+import at.buergerkarte.namespaces.securitylayer._1.GetStatusRequestType;
+import at.gv.egiz.bku.slcommands.GetStatusCommand;
+import at.gv.egiz.bku.slcommands.SLResult;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.stal.ErrorResponse;
+import at.gv.egiz.stal.STAL;
+import at.gv.egiz.stal.STALResponse;
+import at.gv.egiz.stal.StatusRequest;
+import at.gv.egiz.stal.StatusResponse;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class GetStatusCommandImpl extends SLCommandImpl<GetStatusRequestType> implements GetStatusCommand {
+
+ protected static Log log = LogFactory.getLog(GetStatusCommandImpl.class);
+
+ @Override
+ public String getName() {
+ return "GetStatusRequest";
+ }
+
+ @Override
+ public SLResult execute() {
+
+ //ignore maxDelay and TokenStatus
+// GetStatusRequestType req = getRequestValue();
+
+ log.debug("execute GetStatusRequest");
+
+ StatusRequest stalRequest = new StatusRequest();
+
+ STAL stal = cmdCtx.getSTAL();
+
+ List<STALResponse> responses = stal.handleRequest(Collections.singletonList(stalRequest));
+
+ if (responses != null && responses.size() == 1) {
+ STALResponse stalResponse = responses.get(0);
+ if (stalResponse instanceof StatusResponse) {
+ boolean ready = ((StatusResponse) stalResponse).isCardReady();
+ log.trace("received status response cardReady: " + ready);
+ return new GetStatusResultImpl(ready);
+ } else if (stalResponse instanceof ErrorResponse) {
+ log.debug("received error response");
+ SLCommandException ex = new SLCommandException(((ErrorResponse) stalResponse).getErrorCode());
+ return new ErrorResultImpl(ex, cmdCtx.getLocale());
+ }
+ }
+ log.error("received unexpected responses");
+ return new ErrorResultImpl(new SLCommandException(4000), cmdCtx.getLocale());
+
+ }
+}
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
new file mode 100644
index 00000000..fb1f627f
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/GetStatusResultImpl.java
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+import at.buergerkarte.namespaces.securitylayer._1.GetStatusResponseType;
+import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory;
+import at.buergerkarte.namespaces.securitylayer._1.TokenStatusType;
+import at.gv.egiz.bku.slcommands.GetStatusResult;
+import javax.xml.bind.JAXBElement;
+import javax.xml.transform.Result;
+import javax.xml.transform.Templates;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class GetStatusResultImpl extends SLResultImpl implements GetStatusResult {
+
+ protected ObjectFactory of;
+ protected GetStatusResponseType responseType;
+
+ public GetStatusResultImpl(boolean ready) {
+ of = new ObjectFactory();
+ responseType = of.createGetStatusResponseType();
+ if (ready) {
+ responseType.setTokenStatus(TokenStatusType.READY);
+ } else {
+ responseType.setTokenStatus(TokenStatusType.REMOVED);
+ }
+
+ }
+
+ @Override
+ public void writeTo(Result result, Templates templates, boolean fragment) {
+ JAXBElement<GetStatusResponseType> response = of.createGetStatusResponse(responseType);
+ 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
new file mode 100644
index 00000000..160e9589
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/IdentityLinkInfoboxImpl.java
@@ -0,0 +1,290 @@
+/*
+* 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;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Result;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import at.buergerkarte.namespaces.personenbindung._20020506_.CompressedIdentityLinkType;
+import at.buergerkarte.namespaces.securitylayer._1.AnyChildrenType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadRequestType;
+import at.gv.egiz.bku.slcommands.InfoboxReadResult;
+import at.gv.egiz.bku.slcommands.SLCommand;
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.bku.slexceptions.SLExceptionMessages;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+import at.gv.egiz.idlink.CompressedIdentityLinkFactory;
+import at.gv.egiz.idlink.IdentityLinkTransformer;
+import at.gv.egiz.idlink.ans1.IdentityLink;
+import at.gv.egiz.stal.InfoboxReadRequest;
+import at.gv.egiz.stal.STALRequest;
+
+/**
+ * An implementation of the {@link Infobox} <em>IdentityLink</em> as
+ * specified in Security Layer 1.2
+ *
+ * @author mcentner
+ */
+public class IdentityLinkInfoboxImpl extends AbstractBinaryFileInfobox {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(IdentityLinkInfoboxImpl.class);
+
+ /**
+ * The box specific parameter <code>IdentityLinkDomainIdentifier</code>.
+ */
+ public static final String BOX_SPECIFIC_PARAMETER_IDENTITY_LINK_DOMAIN_IDENTIFIER = "IdentityLinkDomainIdentifier";
+
+ /**
+ * The value of the box specific parameter <code>IdentityLinkDomainIdentifier</code>.
+ */
+ private String domainIdentifier;
+
+ @Override
+ public String getIdentifier() {
+ return "IdentityLink";
+ }
+
+ /**
+ * @return the value of the box specific parameter <code>IdentityLinkDomainIdentifier</code>
+ */
+ public String getDomainIdentifier() {
+ return domainIdentifier;
+ }
+
+ @Override
+ public InfoboxReadResult read(InfoboxReadRequestType req, SLCommandContext cmdCtx) throws SLCommandException {
+
+ AnyChildrenType boxSpecificParameters = req.getBoxSpecificParameters();
+
+ if (boxSpecificParameters != null) {
+ // check BoxSpecificParameters
+ List<Object> parameter = boxSpecificParameters.getAny();
+ JAXBElement<?> element;
+ if (parameter != null
+ && parameter.size() == 1
+ && parameter.get(0) instanceof JAXBElement<?>
+ && SLCommand.NAMESPACE_URI.equals((element = (JAXBElement<?>) parameter.get(0)).getName().getNamespaceURI())
+ && BOX_SPECIFIC_PARAMETER_IDENTITY_LINK_DOMAIN_IDENTIFIER.equals(element.getName().getLocalPart())
+ && element.getValue() instanceof String) {
+ domainIdentifier = (String) element.getValue();
+ log.debug("Got sl:IdentityLinkDomainIdentifier: " + domainIdentifier);
+ } else {
+ log.info("Got invalid BoxSpecificParameters.");
+ throw new SLCommandException(4010);
+ }
+ }
+
+ setIsXMLEntity(req);
+
+ STALHelper stalHelper = new STALHelper(cmdCtx.getSTAL());
+
+ List<STALRequest> stalRequests = new ArrayList<STALRequest>();
+
+ InfoboxReadRequest infoboxReadRequest;
+ // get raw identity link
+ infoboxReadRequest = new InfoboxReadRequest();
+ infoboxReadRequest.setInfoboxIdentifier(getIdentifier());
+ infoboxReadRequest.setDomainIdentifier(domainIdentifier);
+ stalRequests.add(infoboxReadRequest);
+
+ // get certificates
+ infoboxReadRequest = new InfoboxReadRequest();
+ infoboxReadRequest.setInfoboxIdentifier("SecureSignatureKeypair");
+ stalRequests.add(infoboxReadRequest);
+ infoboxReadRequest = new InfoboxReadRequest();
+ infoboxReadRequest.setInfoboxIdentifier("CertifiedKeypair");
+ stalRequests.add(infoboxReadRequest);
+
+ stalHelper.transmitSTALRequest(stalRequests);
+ log.trace("Got STAL response");
+
+ IdentityLink identityLink = stalHelper.getIdentityLinkFromResponses();
+ List<X509Certificate> certificates = stalHelper.getCertificatesFromResponses();
+
+
+ CompressedIdentityLinkFactory idLinkFactory = CompressedIdentityLinkFactory.getInstance();
+ JAXBElement<CompressedIdentityLinkType> compressedIdentityLink = idLinkFactory
+ .createCompressedIdentityLink(identityLink, certificates, getDomainIdentifier());
+
+ IdentityLinkTransformer identityLinkTransformer = IdentityLinkTransformer.getInstance();
+ String issuerTemplate = identityLink.getIssuerTemplate();
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db;
+ try {
+ db = dbf.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ log.error("Failed to create XML document.", e);
+ throw new SLRuntimeException(e);
+ }
+
+ Document document = db.newDocument();
+ try {
+ idLinkFactory.marshallCompressedIdentityLink(compressedIdentityLink, document, null, true);
+ } catch (JAXBException e) {
+ log.info("Failed to marshall CompressedIdentityLink.", e);
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_INFOBOX_INVALID,
+ new Object[] { getIdentifier() });
+ }
+
+ InfoboxReadResultFileImpl result = new InfoboxReadResultFileImpl();
+ ByteArrayOutputStream resultBytes = null;
+ Result xmlResult;
+ if (isXMLEntity()) {
+ // we will return the result as XML entity
+ xmlResult = result.getXmlResult(true);
+ } else {
+ // we will return the result as binary data
+ if (getDomainIdentifier() != null) {
+ // we need an XML result to be able to replace the domain identifier below
+ Document doc;
+ try {
+ doc = dbf.newDocumentBuilder().newDocument();
+ } catch (ParserConfigurationException e) {
+ // it should always be possible to create a new Document
+ log.error("Failed to create XML document.", e);
+ throw new SLRuntimeException(e);
+ }
+ xmlResult = new DOMResult(doc);
+ } else {
+ resultBytes = new ByteArrayOutputStream();
+ xmlResult = new StreamResult(resultBytes);
+ }
+ }
+
+ try {
+ log.trace("Trying to transform identitylink");
+ identityLinkTransformer.transformIdLink(issuerTemplate, new DOMSource(document), xmlResult);
+ } catch (MalformedURLException e) {
+ log.warn("Malformed issuer template URL '" + issuerTemplate + "'.");
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_IDLINK_TRANSFORMATION_FAILED,
+ new Object[] { issuerTemplate });
+ } catch (IOException e) {
+ log.warn("Failed to dereferene issuer template URL '" + issuerTemplate + "'." ,e);
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_IDLINK_TRANSFORMATION_FAILED,
+ new Object[] { issuerTemplate });
+ } catch (TransformerConfigurationException e) {
+ log.warn("Failed to create transformation template from issuer template URL '" + issuerTemplate + "'", e);
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_IDLINK_TRANSFORMATION_FAILED,
+ new Object[] { issuerTemplate });
+ } catch (TransformerException e) {
+ log.info("Faild to transform CompressedIdentityLink.", e);
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_IDLINK_TRANSFORMATION_FAILED,
+ new Object[] { issuerTemplate });
+ }
+
+ // TODO: Report BUG in IssuerTemplates
+ // Some IssuerTemplate stylesheets do not consider the pr:Type-Element of the CompressedIdentityLink ...
+ if (getDomainIdentifier() != null) {
+ if (xmlResult instanceof DOMResult) {
+ Node node = ((DOMResult) xmlResult).getNode();
+ Node nextSibling = ((DOMResult) xmlResult).getNextSibling();
+ Node idLinkNode;
+ if (nextSibling != null) {
+ idLinkNode = nextSibling.getPreviousSibling();
+ } else if (node != null) {
+ idLinkNode = node.getFirstChild();
+ } else {
+ log
+ .error("An IdentityLinkDomainIdentifier of '"
+ + getDomainIdentifier()
+ + "' has been given. However, it cannot be set, as the transformation result does not contain a node.");
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_IDLINK_TRANSFORMATION_FAILED,
+ new Object[] { issuerTemplate });
+ }
+ IdentityLinkTransformer.setDomainIdentifier(idLinkNode, getDomainIdentifier());
+ } else {
+ log
+ .error("An IdentityLinkDomainIdentifier of '"
+ + getDomainIdentifier()
+ + "' has been given. However, it cannot be set, as the transformation result is not of type DOM.");
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_IDLINK_TRANSFORMATION_FAILED,
+ new Object[] { issuerTemplate });
+ }
+ }
+
+ if (!isXMLEntity()) {
+ if (resultBytes == null) {
+ resultBytes = new ByteArrayOutputStream();
+ if (xmlResult instanceof DOMResult) {
+ Node node = ((DOMResult) xmlResult).getNode();
+ DOMSource xmlSource = new DOMSource(node);
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ try {
+ Transformer transformer = transformerFactory.newTransformer();
+ transformer.transform(xmlSource, new StreamResult(resultBytes));
+ } catch (TransformerConfigurationException e) {
+ log.error(e);
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_IDLINK_TRANSFORMATION_FAILED,
+ new Object[] { issuerTemplate });
+ } catch (TransformerException e) {
+ log.error(e);
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_IDLINK_TRANSFORMATION_FAILED,
+ new Object[] { issuerTemplate });
+ }
+ } else {
+ log.error("ContentIsXMLEntity is set to 'false'. However, an XMLResult has already been set.");
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_IDLINK_TRANSFORMATION_FAILED,
+ new Object[] { issuerTemplate });
+ }
+ }
+ result.setResultBytes(resultBytes.toByteArray());
+ }
+
+ return result;
+
+ }
+
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/Infobox.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/Infobox.java
new file mode 100644
index 00000000..99d62721
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/Infobox.java
@@ -0,0 +1,70 @@
+/*
+ * 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;
+
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadRequestType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxUpdateRequestType;
+import at.gv.egiz.bku.slcommands.InfoboxReadResult;
+import at.gv.egiz.bku.slcommands.InfoboxUpdateResult;
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+
+/**
+ * An implementation of this interface represents a infobox as defined in
+ * Security-Layer 1.2.
+ *
+ * @author mcentner
+ */
+public interface Infobox {
+
+ /**
+ * @return the identifier of this infobox
+ */
+ public String getIdentifier();
+
+ /**
+ * Read data from this infobox.
+ *
+ * @param request
+ * the InfoboxReadRequest
+ * @param cmdCtx
+ * the command context
+ *
+ * @return the data read from this infobox as InfoboxReadResult
+ *
+ * @throws SLCommandException
+ *
+ * if reading from this infobox fails
+ */
+ public InfoboxReadResult read(InfoboxReadRequestType request,
+ SLCommandContext cmdCtx) throws SLCommandException;
+
+ /**
+ * Update data in this infobox.
+ *
+ * @param request
+ * the InfoboxUpdateRequest
+ * @param cmdCtx
+ * the command context
+ * @return a corresponding InfoboxUpdateResult
+ * @throws SLCommandException
+ * if updating this infobox fails
+ */
+ public InfoboxUpdateResult update(InfoboxUpdateRequestType request,
+ SLCommandContext cmdCtx) throws SLCommandException;
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxFactory.java
new file mode 100644
index 00000000..fdf94297
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxFactory.java
@@ -0,0 +1,90 @@
+/*
+* 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;
+
+import java.util.HashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.bku.slexceptions.SLExceptionMessages;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+
+/**
+ * A factory for creating {@link Infobox}es.
+ *
+ * @author mcentner
+ */
+public class InfoboxFactory {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(InfoboxFactory.class);
+
+ /**
+ * The mapping of Infobox name to concrete Infobox factory.
+ */
+ private HashMap<String, AbstractInfoboxFactory> infoboxFactories = new HashMap<String, AbstractInfoboxFactory>();
+
+ /**
+ * @param infoboxFactories the infoboxFactories to set
+ */
+ public void setInfoboxFactories(
+ HashMap<String, AbstractInfoboxFactory> factories) {
+ if (log.isDebugEnabled()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Registered infobox factories for");
+ for (String name : factories.keySet()) {
+ sb.append("\n " + name + " : " + factories.get(name).getClass());
+ }
+ log.debug(sb);
+ }
+ this.infoboxFactories = factories;
+ }
+
+ /**
+ * Create a new {@link Infobox} instance for the given
+ * <code>infoboxIdentifier</code>.
+ *
+ * @param infoboxIdentifier
+ * the infobox identifier
+ *
+ * @return an {@link Infobox} implementation for the given infobox identifier
+ *
+ * @throws SLCommandException
+ * if there is no implementation for the given infobox identifier
+ * @throws SLRuntimeException
+ * if creating an {@link Infobox} instance fails
+ */
+ public Infobox createInfobox(String infoboxIdentifier) throws SLCommandException, SLRuntimeException {
+
+ AbstractInfoboxFactory factory = infoboxFactories.get(infoboxIdentifier);
+ if (factory == null) {
+ log.info("Unsupported infobox '" + infoboxIdentifier + ".");
+ throw new SLCommandException(4002,
+ SLExceptionMessages.EC4002_INFOBOX_UNKNOWN,
+ new Object[] { infoboxIdentifier });
+ }
+
+ return factory.createInfobox();
+
+ }
+
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadCommandImpl.java
new file mode 100644
index 00000000..693f444f
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadCommandImpl.java
@@ -0,0 +1,96 @@
+/*
+* 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;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadRequestType;
+import at.gv.egiz.bku.slcommands.InfoboxReadCommand;
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slcommands.SLResult;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+
+/**
+ * This class implements the security layer command
+ * <code>InfoboxReadRequest</code>.
+ * <p>
+ * <b>NOTE:</b> Currently the only supported infobox identifier is '
+ * <code>IdentityLink</code>'.
+ * </p>
+ *
+ * @author mcentner
+ */
+public class InfoboxReadCommandImpl extends AbstractInfoboxCommandImpl<InfoboxReadRequestType> implements
+ InfoboxReadCommand {
+
+ /**
+ * Logging facility.
+ */
+ protected static Log log = LogFactory.getLog(InfoboxReadCommandImpl.class);
+
+ @Override
+ public String getName() {
+ return "InfoboxReadRequest";
+ }
+
+ @Override
+ protected String getInfoboxIdentifier(InfoboxReadRequestType request) {
+ return request.getInfoboxIdentifier();
+ }
+
+ @Override
+ public void init(SLCommandContext ctx, Object request) throws SLCommandException {
+ super.init(ctx, request);
+
+ InfoboxReadRequestType req = getRequestValue();
+
+ if (req.getAssocArrayParameters() != null &&
+ !(infobox instanceof AssocArrayInfobox)) {
+ log.info("Got AssocArrayParameters but Infobox type is not AssocArray.");
+ throw new SLCommandException(4010);
+ }
+
+ if (req.getBinaryFileParameters() != null &&
+ !(infobox instanceof BinaryFileInfobox)) {
+ log.info("Got BinaryFileParameters but Infobox type is not BinaryFile.");
+ throw new SLCommandException(4010);
+ }
+
+ }
+
+ @Override
+ public SLResult execute() {
+
+ try {
+ return infobox.read(getRequestValue(), getCmdCtx());
+ } catch (SLCommandException e) {
+ return new ErrorResultImpl(e, getCmdCtx().getLocale());
+ }
+
+ }
+
+ @Override
+ public String getIdentityLinkDomainId() {
+ if (infobox instanceof IdentityLinkInfoboxImpl) {
+ return ((IdentityLinkInfoboxImpl) infobox).getDomainIdentifier();
+ } else {
+ return null;
+ }
+ }
+
+}
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
new file mode 100644
index 00000000..422b424f
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadResultFileImpl.java
@@ -0,0 +1,160 @@
+/*
+* 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;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Result;
+import javax.xml.transform.Templates;
+import javax.xml.transform.dom.DOMResult;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import at.buergerkarte.namespaces.securitylayer._1.Base64XMLContentType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadResponseType;
+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.SLMarshallerFactory;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+
+/**
+ * This class implements the result of the security layer command <code>InfoboxReadRequest</code>.
+ *
+ * @author mcentner
+ */
+public class InfoboxReadResultFileImpl extends SLResultImpl implements
+ InfoboxReadResult {
+
+ /**
+ * Logging facility.
+ */
+ protected static Log log = LogFactory.getLog(InfoboxReadResultFileImpl.class);
+
+ /**
+ * The XML document containing the infobox content.
+ */
+ protected Document xmlDocument;
+
+ /**
+ * Creates the response document from the given <code>binaryContent</code>.
+ *
+ * @param binaryContent the infobox content
+ * @param preserveSpace the value of the <code>preserveSpace</code> parameter
+ *
+ * @return the created response document
+ */
+ private Document createResponseDocument(byte[] binaryContent, boolean preserveSpace) {
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ Document doc;
+ try {
+ doc = dbf.newDocumentBuilder().newDocument();
+ } catch (ParserConfigurationException e) {
+ // it should always be possible to create a new Document
+ log.error("Failed to create XML document.", e);
+ throw new SLRuntimeException(e);
+ }
+
+ ObjectFactory factory = new ObjectFactory();
+
+ Base64XMLContentType base64XMLContentType = factory.createBase64XMLContentType();
+ if (binaryContent == null) {
+ XMLContentType xmlContentType = factory.createXMLContentType();
+ if (preserveSpace) {
+ xmlContentType.setSpace("preserve");
+ }
+ base64XMLContentType.setXMLContent(xmlContentType);
+ } else {
+ base64XMLContentType.setBase64Content(binaryContent);
+ }
+ InfoboxReadResponseType infoboxReadResponseType = factory.createInfoboxReadResponseType();
+ infoboxReadResponseType.setBinaryFileData(base64XMLContentType);
+
+ JAXBElement<InfoboxReadResponseType> infoboxReadResponse = factory.createInfoboxReadResponse(infoboxReadResponseType);
+
+ Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(false);
+ try {
+ marshaller.marshal(infoboxReadResponse, doc);
+ } catch (JAXBException e) {
+ log.error("Failed to marshal 'InfoboxReadResponse' document.", e);
+ throw new SLRuntimeException(e);
+ }
+
+ return doc;
+
+ }
+
+
+ /**
+ * @return an XMLResult for marshalling the infobox to
+ */
+ public Result getXmlResult(boolean preserveSpace) {
+
+ xmlDocument = createResponseDocument(null, preserveSpace);
+
+ NodeList nodeList = xmlDocument.getElementsByTagNameNS(SLCommand.NAMESPACE_URI, "XMLContent");
+ return new DOMResult(nodeList.item(0));
+
+ }
+
+ /**
+ * Creates a new <code>InfoboxReadResponse</code> document and appends
+ * the given <code>node</code> as child node of the <code>XMLContent</code> element.
+ *
+ * @param node the node to be appended as child node of the <code>XMLContnet</code> element
+ * @param preserveSpace if <code>true</code> the value of the <code>XMLContent</code>'s <code>space</code>
+ * attribute is set to <code>preserve</code>.
+ */
+ public void setResultXMLContent(Node node, boolean preserveSpace) {
+
+ xmlDocument = createResponseDocument(null, preserveSpace);
+
+ NodeList nodeList = xmlDocument.getElementsByTagNameNS(SLCommand.NAMESPACE_URI, "XMLContent");
+ if (node.getOwnerDocument() != xmlDocument) {
+ node = xmlDocument.importNode(node, true);
+ }
+ nodeList.item(0).appendChild(node);
+
+ }
+
+ /**
+ * Creates a new result document for this <code>InfoboxReadResult</code>
+ * and sets the given <code>resultBytes</code> as content.
+ *
+ * @param resultBytes
+ */
+ public void setResultBytes(byte[] resultBytes) {
+
+ xmlDocument = createResponseDocument(resultBytes, false);
+
+ }
+
+ @Override
+ 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
new file mode 100644
index 00000000..271ec955
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadResultImpl.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.bku.slcommands.impl;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.transform.Result;
+import javax.xml.transform.Templates;
+
+import at.buergerkarte.namespaces.securitylayer._1.Base64XMLContentType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadDataAssocArrayType;
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxReadResponseType;
+import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory;
+import at.gv.egiz.bku.slcommands.InfoboxReadResult;
+
+public class InfoboxReadResultImpl extends SLResultImpl implements InfoboxReadResult {
+
+ /**
+ * The <code>InfoboxReadResponse</code>
+ */
+ protected InfoboxReadResponseType infoboxReadResponse;
+
+ public InfoboxReadResultImpl(InfoboxReadDataAssocArrayType assocArray) {
+
+ ObjectFactory objectFactory = new ObjectFactory();
+ InfoboxReadResponseType infoboxReadResponseType = objectFactory.createInfoboxReadResponseType();
+
+ infoboxReadResponseType.setAssocArrayData(assocArray);
+
+ this.infoboxReadResponse = infoboxReadResponseType;
+ }
+
+ public InfoboxReadResultImpl(Base64XMLContentType value) {
+
+ ObjectFactory objectFactory = new ObjectFactory();
+ InfoboxReadResponseType infoboxReadResponseType = objectFactory.createInfoboxReadResponseType();
+
+ infoboxReadResponseType.setBinaryFileData(value);
+
+ this.infoboxReadResponse = infoboxReadResponseType;
+
+ }
+
+ @Override
+ public void writeTo(Result result, Templates templates, boolean fragment) {
+ ObjectFactory objectFactory = new ObjectFactory();
+ JAXBElement<InfoboxReadResponseType> response = objectFactory.createInfoboxReadResponse(infoboxReadResponse);
+ writeTo(response, result, templates, fragment);
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxUpdateCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxUpdateCommandImpl.java
new file mode 100644
index 00000000..1cdeda94
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxUpdateCommandImpl.java
@@ -0,0 +1,74 @@
+/*
+* 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;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxUpdateRequestType;
+import at.gv.egiz.bku.slcommands.InfoboxUpdateCommand;
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slcommands.SLResult;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+
+public class InfoboxUpdateCommandImpl extends
+ AbstractInfoboxCommandImpl<InfoboxUpdateRequestType> implements InfoboxUpdateCommand {
+
+ private static Log log = LogFactory.getLog(InfoboxUpdateCommandImpl.class);
+
+ @Override
+ public String getName() {
+ return "InfoboxUpdateRequest";
+ }
+
+ @Override
+ protected String getInfoboxIdentifier(InfoboxUpdateRequestType request) {
+ return request.getInfoboxIdentifier();
+ }
+
+ @Override
+ public void init(SLCommandContext ctx, Object request) throws SLCommandException {
+ super.init(ctx, request);
+
+ InfoboxUpdateRequestType req = getRequestValue();
+
+ if (req.getAssocArrayParameters() != null &&
+ !(infobox instanceof AssocArrayInfobox)) {
+ log.info("Got AssocArrayParameters but Infobox type is not AssocArray.");
+ throw new SLCommandException(4010);
+ }
+
+ if (req.getBinaryFileParameters() != null &&
+ !(infobox instanceof BinaryFileInfobox)) {
+ log.info("Got BinaryFileParameters but Infobox type is not BinaryFile.");
+ throw new SLCommandException(4010);
+ }
+
+ }
+
+ @Override
+ public SLResult execute() {
+
+ try {
+ return infobox.update(getRequestValue(), getCmdCtx());
+ } catch (SLCommandException e) {
+ return new ErrorResultImpl(e, getCmdCtx().getLocale());
+ }
+
+ }
+
+}
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
new file mode 100644
index 00000000..e12536ba
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxUpdateResultImpl.java
@@ -0,0 +1,43 @@
+/*
+* 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;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.transform.Result;
+import javax.xml.transform.Templates;
+
+import at.buergerkarte.namespaces.securitylayer._1.InfoboxUpdateResponseType;
+import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory;
+import at.gv.egiz.bku.slcommands.InfoboxUpdateResult;
+
+public class InfoboxUpdateResultImpl extends SLResultImpl implements
+ InfoboxUpdateResult {
+
+ protected static JAXBElement<InfoboxUpdateResponseType> RESPONSE;
+
+ static {
+ ObjectFactory factory = new ObjectFactory();
+ InfoboxUpdateResponseType type = factory.createInfoboxUpdateResponseType();
+ RESPONSE = factory.createInfoboxUpdateResponse(type);
+ }
+
+ @Override
+ 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/NullOperationCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/NullOperationCommandImpl.java
new file mode 100644
index 00000000..1b6fb237
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/NullOperationCommandImpl.java
@@ -0,0 +1,43 @@
+/*
+* 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;
+
+import at.buergerkarte.namespaces.securitylayer._1.NullOperationRequestType;
+import at.gv.egiz.bku.slcommands.NullOperationCommand;
+import at.gv.egiz.bku.slcommands.NullOperationResult;
+import at.gv.egiz.bku.slcommands.SLResult;
+
+/**
+ * This class implements the security layer command <code>NullOperation</code>.
+ *
+ * @author mcentner
+ */
+public class NullOperationCommandImpl extends SLCommandImpl<NullOperationRequestType> implements NullOperationCommand {
+
+ protected static NullOperationResult RESULT = new NullOperationResultImpl();
+
+ @Override
+ public SLResult execute() {
+ return RESULT;
+ }
+
+ @Override
+ public String getName() {
+ return "NullOperationRequest";
+ }
+
+}
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
new file mode 100644
index 00000000..87733e39
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/NullOperationResultImpl.java
@@ -0,0 +1,48 @@
+/*
+* 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;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.transform.Result;
+import javax.xml.transform.Templates;
+
+import at.buergerkarte.namespaces.securitylayer._1.NullOperationResponseType;
+import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory;
+import at.gv.egiz.bku.slcommands.NullOperationResult;
+
+/**
+ * This class represents the result of the security layer command
+ * <code>NullOperation</code>.
+ *
+ * @author mcentner
+ */
+public class NullOperationResultImpl extends SLResultImpl implements NullOperationResult {
+
+ protected static JAXBElement<NullOperationResponseType> RESPONSE;
+
+ static {
+ ObjectFactory factory = new ObjectFactory();
+ NullOperationResponseType type = factory.createNullOperationResponseType();
+ RESPONSE = factory.createNullOperationResponse(type);
+ }
+
+ @Override
+ 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/SLCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLCommandImpl.java
new file mode 100644
index 00000000..ed055b69
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLCommandImpl.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.slcommands.impl;
+
+import javax.xml.bind.JAXBElement;
+
+import at.gv.egiz.bku.slcommands.SLCommand;
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+
+/**
+ * This class serves as abstract base class for the implementation of a security
+ * layer command.
+ *
+ * @author mcentner
+ *
+ * @param <T>
+ * the type of the corresponding request value
+ */
+public abstract class SLCommandImpl<T> implements SLCommand {
+
+ /**
+ * The <code>SLCommandContext</code> for this <code>SLCommand</code>.
+ */
+ protected SLCommandContext cmdCtx;
+
+ /**
+ * The STAL helper.
+ */
+ protected STALHelper stalHelper;
+
+ /**
+ * The request element of this command.
+ */
+ protected JAXBElement<T> request;
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void init(SLCommandContext ctx, Object request)
+ throws SLCommandException {
+
+ this.request = (JAXBElement<T>) request;
+
+ this.cmdCtx = ctx;
+ stalHelper = new STALHelper(cmdCtx.getSTAL());
+
+ }
+
+ /**
+ * Returns the request value.
+ *
+ * It is a convenience method for <code>request.getValue()</code>.
+ *
+ * @see JAXBElement#getValue()
+ * @return the request value
+ */
+ protected T getRequestValue() {
+ return request.getValue();
+ }
+
+ /**
+ * @return the corresponding <code>SLCommandContext</code>
+ */
+ protected SLCommandContext getCmdCtx() {
+ return cmdCtx;
+ }
+}
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
new file mode 100644
index 00000000..0077b7b2
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLResultImpl.java
@@ -0,0 +1,297 @@
+/*
+* 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;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.util.Locale;
+
+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;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Node;
+
+import at.buergerkarte.namespaces.securitylayer._1.ErrorResponseType;
+import at.buergerkarte.namespaces.securitylayer._1.ObjectFactory;
+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;
+
+/**
+ * This class serves as an abstract base class for the implementation of a
+ * security layer result.
+ *
+ * @author mcentner
+ */
+public abstract class SLResultImpl implements SLResult {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(SLResult.class);
+
+ /**
+ * The security layer result type (default = XML).
+ */
+ protected SLResultType resultType = SLResultType.XML;
+
+ /**
+ * The security layer result MIME-type (default = <code>text/xml</code>).
+ */
+ protected String resultingMimeType = "text/xml";
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.bku.slcommands.SLResult#getResultType()
+ */
+ public SLResultType getResultType() {
+ return resultType;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.bku.slcommands.SLResult#getMimeType()
+ */
+ public String getMimeType() {
+ return resultingMimeType;
+ }
+
+ @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;
+ } catch (TransformerFactoryConfigurationError e) {
+ log.error("Failed to create an instance of SAXTransformerFactory.", e);
+ throw new SLBindingException(2000);
+ } catch (IllegalArgumentException e) {
+ log.error("Failed to set result for transformation.", e);
+ throw new SLBindingException(2000);
+ } catch (TransformerConfigurationException e) {
+ log.info("Failed to create an instance of SAXTransformerFactory.", e);
+ throw new SLBindingException(2008);
+ }
+ }
+
+ /**
+ * Writes the given <code>response</code> to the SAX <code>result</code> using
+ * the given transform <code>templates</code>.
+ *
+ * @param response
+ * @param result
+ * @param templates
+ */
+ protected void writeTo(JAXBElement<?> response, Result result, Templates templates, boolean fragment) {
+
+ DebugWriter dw = null;
+ DebugOutputStream ds = null;
+ if (log.isTraceEnabled() && result instanceof StreamResult) {
+ StreamResult streamResult = (StreamResult) result;
+ if (streamResult.getOutputStream() != null) {
+ ds = new DebugOutputStream(streamResult.getOutputStream());
+ streamResult.setOutputStream(ds);
+ }
+ if (streamResult.getWriter() != null) {
+ dw = new DebugWriter(streamResult.getWriter());
+ streamResult.setWriter(dw);
+ }
+ }
+
+ TransformerHandler transformerHandler = null;
+ if (templates != null) {
+ try {
+ transformerHandler = getTransformerHandler(templates, result);
+ } catch (SLException e) {
+ writeErrorTo(e, result, templates, fragment);
+ }
+ }
+
+ Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(true);
+ try {
+ if (transformerHandler != null) {
+ marshaller.marshal(response, transformerHandler);
+ } else {
+ marshaller.marshal(response, result);
+ }
+ } catch (JAXBException e) {
+ log.info("Failed to marshall " + response.getName() + " result." , e);
+ SLCommandException commandException = new SLCommandException(4000);
+ writeErrorTo(commandException, result, templates, fragment);
+ }
+
+ if (ds != null) {
+ try {
+ log.trace("Marshalled result:\n" + new String(ds.getBufferedBytes(), "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ log.trace(e.getMessage());
+ }
+ }
+
+ if (dw != null) {
+ log.trace("Marshalled result:\n" + dw.getBufferedString());
+ }
+
+ }
+
+ protected void writeTo(Node node, Result result, Templates templates, boolean fragment) {
+
+ DebugWriter dw = null;
+ DebugOutputStream ds = null;
+ if (log.isTraceEnabled() && result instanceof StreamResult) {
+ StreamResult streamResult = (StreamResult) result;
+ if (streamResult.getOutputStream() != null) {
+ ds = new DebugOutputStream(streamResult.getOutputStream());
+ streamResult.setOutputStream(ds);
+ }
+ if (streamResult.getWriter() != null) {
+ dw = new DebugWriter(streamResult.getWriter());
+ streamResult.setWriter(dw);
+ }
+ }
+
+ if (templates == null) {
+ 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, fragment);
+ } catch (TransformerException e) {
+ log.error("Failed to transform result.", e);
+ 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, fragment);
+ } catch (TransformerException e) {
+ log.error("Failed to transform result.", e);
+ writeErrorTo(new SLException(2008), result, templates, fragment);
+ }
+ }
+
+ if (ds != null) {
+ try {
+ log.trace("Marshalled result:\n" + new String(ds.getBufferedBytes(), "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ log.trace(e.getMessage());
+ }
+ }
+
+ if (dw != null) {
+ log.trace("Marshalled result:\n" + dw.getBufferedString());
+ }
+
+ }
+
+ 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, boolean fragment) {
+
+ TransformerHandler transformerHandler = null;
+ if (templates != null) {
+ try {
+ transformerHandler = getTransformerHandler(templates, result);
+ } catch (SLException e) {
+ // write the exception thrown instead of the given one
+ slException = e;
+ }
+ }
+
+ 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);
+ }
+
+ try {
+ if (transformerHandler != null) {
+ marshaller.marshal(response, transformerHandler);
+ } else {
+ marshaller.marshal(response, result);
+ }
+ } catch (JAXBException e) {
+ log.fatal("Failed to marshall error result." , e);
+ throw new SLRuntimeException("Failed to marshall error result.");
+ }
+
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/STALHelper.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/STALHelper.java
new file mode 100644
index 00000000..e903c608
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/STALHelper.java
@@ -0,0 +1,242 @@
+/*
+* 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;
+
+import iaik.asn1.CodingException;
+import iaik.asn1.DerCoder;
+import iaik.utils.Base64OutputStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.bku.slexceptions.SLExceptionMessages;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+import at.gv.egiz.idlink.ans1.IdentityLink;
+import at.gv.egiz.stal.ErrorResponse;
+import at.gv.egiz.stal.InfoboxReadResponse;
+import at.gv.egiz.stal.STAL;
+import at.gv.egiz.stal.STALRequest;
+import at.gv.egiz.stal.STALResponse;
+
+/**
+ * A helper class for transmitting {@link STALRequest}s and obtaining their
+ * respective {@link STALResponse}s.
+ *
+ * @author mcentner
+ */
+public class STALHelper {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(STALHelper.class);
+
+ /**
+ * The STAL implementation.
+ */
+ private STAL stal;
+
+ /**
+ * An iterator over the <code>STALResponse</code>s received in
+ * {@link SLCommandImpl#transmitSTALRequest(List)}.
+ */
+ protected Iterator<STALResponse> stalResponses;
+
+ /**
+ * Creates a new instance of this STALHelper with the given
+ * <code>stal</code>.
+ *
+ * @param stal the STAL to be used
+ */
+ public STALHelper(STAL stal) {
+ if (stal == null) {
+ throw new NullPointerException("Argument 'stal' must not be null.");
+ }
+ this.stal = stal;
+ }
+
+ /**
+ * Calls {@link STAL#handleRequest(List)} with the given
+ * <code>stalRequests</code>.
+ *
+ * @param stalRequests
+ * @throws SLCommandException
+ */
+ public void transmitSTALRequest(List<? extends STALRequest> stalRequests) throws SLCommandException {
+ List<STALResponse> responses = stal.handleRequest(stalRequests);
+ if (responses == null) {
+ Log log = LogFactory.getLog(this.getClass());
+ log.info("Received no responses from STAL.");
+ throw new SLCommandException(4000);
+ } else if (responses.size() != stalRequests.size()) {
+ Log log = LogFactory.getLog(this.getClass());
+ log.info("Received invalid count of responses from STAL. Expected "
+ + stalRequests.size() + ", but got " + responses.size() + ".");
+ // throw new SLCommandException(4000);
+ }
+ stalResponses = responses.iterator();
+ }
+
+ /**
+ * @return <code>true</code> if there are more {@link STALResponse}s to be
+ * fetched with {@link #nextResponse(Class)}, or <code>false</code>
+ * otherwise.
+ */
+ public boolean hasNextResponse() {
+ return (stalResponses != null) ? stalResponses.hasNext() : false;
+ }
+
+ /**
+ * Returns the next response of type <code>responseClass</code> that has been
+ * received by {@link #transmitSTALRequest(List)}.
+ *
+ * @param responseClass
+ * the response must be an instance of
+ * @return the next response of type <code>responseClass</code>
+ *
+ * @throws NoSuchElementException
+ * if there is no more response
+ * @throws SLCommandException
+ * if the next response is of type {@link ErrorResponse} or not of
+ * type <code>responseClass</code>
+ */
+ public STALResponse nextResponse(
+ Class<? extends STALResponse> responseClass) throws SLCommandException {
+
+ if (stalResponses == null) {
+ throw new NoSuchElementException();
+ }
+
+ STALResponse response = stalResponses.next();
+
+ if (response instanceof ErrorResponse) {
+ throw new SLCommandException(((ErrorResponse) response).getErrorCode());
+ }
+
+ if (!(responseClass.isAssignableFrom(response.getClass()))) {
+ Log log = LogFactory.getLog(this.getClass());
+ log.info("Received " + response.getClass() + " from STAL but expected "
+ + responseClass);
+ throw new SLCommandException(4000);
+ }
+
+ return response;
+
+ }
+
+ /**
+ * Gets the list of certificates from the next STAL responses.
+ *
+ * @return the list of certificates
+ *
+ * @throws SLCommandException if getting the list of certificates fails
+ */
+ public List<X509Certificate> getCertificatesFromResponses() throws SLCommandException {
+
+ List<X509Certificate> certificates = new ArrayList<X509Certificate>();
+
+ CertificateFactory certFactory;
+ try {
+ certFactory = CertificateFactory.getInstance("X509");
+ } catch (CertificateException e) {
+ // we should always be able to get an X509 certificate factory
+ log.error("CertificateFactory.getInstance(\"X509\") failed.", e);
+ throw new SLRuntimeException(e);
+ }
+
+ InfoboxReadResponse response;
+ while(hasNextResponse()) {
+ response = (InfoboxReadResponse) nextResponse(InfoboxReadResponse.class);
+ byte[] cert = response.getInfoboxValue();
+ try {
+ certificates.add((X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(cert)));
+ } catch (CertificateException e) {
+ if (log.isDebugEnabled()) {
+ ByteArrayOutputStream certDump = new ByteArrayOutputStream();
+ OutputStreamWriter writer = new OutputStreamWriter(certDump);
+ try {
+ writer.write("-----BEGIN CERTIFICATE-----\n");
+ writer.flush();
+ Base64OutputStream b64os = new Base64OutputStream(certDump);
+ b64os.write(cert);
+ b64os.flush();
+ writer.write("\n-----END CERTIFICATE-----");
+ writer.flush();
+ } catch (IOException e1) {
+ log.info("Failed to decode certificate.", e);
+ }
+ log.debug("Failed to decode certificate.\n" + certDump.toString(), e);
+ } else {
+ log.info("Failed to decode certificate.", e);
+ }
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_INFOBOX_INVALID,
+ new Object[] { "Certificates" });
+ }
+ }
+
+ return certificates;
+
+ }
+
+ /**
+ * Gets the IdentitiyLink form the next STAL response.
+ *
+ * @return the IdentityLink
+ *
+ * @throws SLCommandException if getting the IdentitiyLink fails
+ */
+ public IdentityLink getIdentityLinkFromResponses() throws SLCommandException {
+
+ // IdentityLink
+ InfoboxReadResponse response;
+ if (hasNextResponse()) {
+ response = (InfoboxReadResponse) nextResponse(InfoboxReadResponse.class);
+ byte[] idLink = response.getInfoboxValue();
+ try {
+ return new IdentityLink(DerCoder.decode(idLink));
+ } catch (CodingException e) {
+ log.info("Failed to decode infobox 'IdentityLink'.", e);
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_INFOBOX_INVALID,
+ new Object[] { "IdentityLink" });
+ }
+ } else {
+ log.info("No infobox 'IdentityLink' returned from STAL.");
+ throw new SLCommandException(4000);
+ }
+
+ }
+
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImpl.java
new file mode 100644
index 00000000..7e204632
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SVPersonendatenInfoboxImpl.java
@@ -0,0 +1,323 @@
+/*
+* 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;
+
+import iaik.asn1.ASN;
+import iaik.asn1.ASN1Object;
+import iaik.asn1.CodingException;
+import iaik.asn1.DerCoder;
+import iaik.asn1.NumericString;
+import iaik.asn1.OCTET_STRING;
+import iaik.asn1.ObjectID;
+import iaik.asn1.SEQUENCE;
+import iaik.asn1.SET;
+import iaik.asn1.UNKNOWN;
+import iaik.asn1.structures.ChoiceOfTime;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.buergerkarte.namespaces.cardchannel.AttributeList;
+import at.buergerkarte.namespaces.cardchannel.AttributeType;
+import at.buergerkarte.namespaces.cardchannel.ObjectFactory;
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.bku.slexceptions.SLExceptionMessages;
+import at.gv.egiz.stal.InfoboxReadRequest;
+import at.gv.egiz.stal.InfoboxReadResponse;
+import at.gv.egiz.stal.STALRequest;
+
+/**
+ * An implementation of the {@link Infobox} <em>Certificates</em> as
+ * specified in Security Layer 1.2.
+ *
+ * @author mcentner
+ */
+public class SVPersonendatenInfoboxImpl extends AbstractAssocArrayInfobox {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(SVPersonendatenInfoboxImpl.class);
+
+ public static final String EHIC = "EHIC";
+
+ public static final String GRUNDDATEN = "Grunddaten";
+
+ public static final String STATUS = "Status";
+
+ public static final String SV_PERSONENBINDUNG = "SV-Personenbindung";
+
+ /**
+ * The valid keys.
+ */
+ public static final String[] KEYS = new String[] {
+ GRUNDDATEN, EHIC, STATUS, SV_PERSONENBINDUNG
+ };
+
+ @Override
+ public String getIdentifier() {
+ return "SV-Personendaten";
+ }
+
+ @Override
+ public String[] getKeys() {
+ return KEYS;
+ }
+
+ @Override
+ public boolean isValuesAreXMLEntities() {
+ return true;
+ }
+
+ @Override
+ public Map<String, Object> getValues(List<String> keys, SLCommandContext cmdCtx) throws SLCommandException {
+
+ STALHelper stalHelper = new STALHelper(cmdCtx.getSTAL());
+
+ if (keys != null && !keys.isEmpty()) {
+
+ List<STALRequest> stalRequests = new ArrayList<STALRequest>();
+
+ // get values
+ InfoboxReadRequest infoboxReadRequest;
+ for (int i = 0; i < keys.size(); i++) {
+ infoboxReadRequest = new InfoboxReadRequest();
+ infoboxReadRequest.setInfoboxIdentifier(keys.get(i));
+ stalRequests.add(infoboxReadRequest);
+ }
+
+ stalHelper.transmitSTALRequest(stalRequests);
+
+ Map<String, Object> values = new HashMap<String, Object>();
+
+ try {
+ for (int i = 0; i < keys.size(); i++) {
+
+ String key = keys.get(i);
+ InfoboxReadResponse nextResponse = (InfoboxReadResponse) stalHelper.nextResponse(InfoboxReadResponse.class);
+
+
+ ObjectFactory objectFactory = new ObjectFactory();
+
+ if (EHIC.equals(key)) {
+ AttributeList attributeList = createAttributeList(nextResponse.getInfoboxValue());
+ values.put(key, objectFactory.createEHIC(attributeList));
+ } else if (GRUNDDATEN.equals(key)) {
+ AttributeList attributeList = createAttributeList(nextResponse.getInfoboxValue());
+ values.put(key, objectFactory.createGrunddaten(attributeList));
+ } else if (SV_PERSONENBINDUNG.equals(key)) {
+ values.put(key, objectFactory.createSVPersonenbindung(nextResponse.getInfoboxValue()));
+ } else if (STATUS.equals(key)) {
+ AttributeList attributeList = createAttributeListFromRecords(nextResponse.getInfoboxValue());
+ values.put(key, objectFactory.createStatus(attributeList));
+ }
+
+ }
+ } catch (CodingException e) {
+ log.info("Failed to decode '" + getIdentifier() + "' infobox.", e);
+ throw new SLCommandException(4000,
+ SLExceptionMessages.EC4000_UNCLASSIFIED_INFOBOX_INVALID,
+ new Object[] { "IdentityLink" });
+
+ }
+
+ return values;
+
+ } else {
+
+ return new HashMap<String, Object>();
+
+ }
+
+
+ }
+
+ public static AttributeList createAttributeList(byte[] infoboxValue) throws CodingException {
+
+ ObjectFactory objectFactory = new ObjectFactory();
+
+ ASN1Object asn1 = DerCoder.decode(infoboxValue);
+
+ AttributeList attributeList = objectFactory.createAttributeList();
+ List<AttributeType> attributes = attributeList.getAttribute();
+
+ if (asn1.isA(ASN.SEQUENCE)) {
+ for (int i = 0; i < ((SEQUENCE) asn1).countComponents(); i++) {
+
+ AttributeType attributeType = objectFactory.createAttributeType();
+
+ if (asn1.getComponentAt(i).isA(ASN.SEQUENCE)) {
+ SEQUENCE attribute = (SEQUENCE) asn1.getComponentAt(i);
+ if (attribute.getComponentAt(0).isA(ASN.ObjectID)) {
+ ObjectID objectId = (ObjectID) attribute.getComponentAt(0);
+ attributeType.setOid("urn:oid:" + objectId.getID());
+ }
+ if (attribute.getComponentAt(1).isA(ASN.SET)) {
+ SET values = (SET) attribute.getComponentAt(1);
+ for (int j = 0; j < values.countComponents(); j++) {
+ setAttributeValue(attributeType, values.getComponentAt(j));
+ }
+ }
+ }
+
+ attributes.add(attributeType);
+
+ }
+
+ }
+
+ return attributeList;
+
+ }
+
+ public static AttributeList createAttributeListFromRecords(byte[] infoboxValue) throws CodingException {
+
+ ObjectFactory objectFactory = new ObjectFactory();
+
+ AttributeList attributeList = objectFactory.createAttributeList();
+ List<AttributeType> attributes = attributeList.getAttribute();
+
+ byte[] records = infoboxValue;
+
+ while (records != null && records.length > 0) {
+
+ int length;
+
+ if (records[0] != 0x00) {
+
+ ASN1Object asn1 = DerCoder.decode(records);
+
+ AttributeType attributeType = objectFactory.createAttributeType();
+
+ if (asn1.isA(ASN.SEQUENCE)) {
+ SEQUENCE attribute = (SEQUENCE) asn1;
+ if (attribute.getComponentAt(0).isA(ASN.ObjectID)) {
+ ObjectID objectId = (ObjectID) attribute.getComponentAt(0);
+ attributeType.setOid("urn:oid:" + objectId.getID());
+ }
+ if (attribute.getComponentAt(1).isA(ASN.SET)) {
+ SET values = (SET) attribute.getComponentAt(1);
+ for (int j = 0; j < values.countComponents(); j++) {
+ setAttributeValue(attributeType, values.getComponentAt(j));
+ }
+ }
+ }
+
+ attributes.add(attributeType);
+
+ length = DerCoder.encode(asn1).length;
+
+ } else {
+ length = 1;
+ }
+
+ if (length < records.length) {
+ records = Arrays.copyOfRange(records, length + 1, records.length);
+ } else {
+ records = null;
+ }
+
+ }
+
+ return attributeList;
+
+ }
+
+ private static void setAttributeValue(AttributeType attributeType, ASN1Object value) {
+
+ if (value.isA(ASN.OCTET_STRING)) {
+
+ try {
+ byte[] octets = ((OCTET_STRING) value).getWholeValue();
+ attributeType.setLatin1String(new String(octets, Charset.forName("ISO-8859-1")));
+ } catch (IOException e) {
+ log.info("Failed to set Latin1String.", e);
+ }
+
+ } else if (value.isA(ASN.NumericString)) {
+
+ attributeType.setNumericString((String) ((NumericString) value).getValue());
+
+ } else if (value.isA(ASN.GeneralizedTime)) {
+
+ try {
+ ChoiceOfTime choiceOfTime = new ChoiceOfTime(value);
+
+ GregorianCalendar gregorianCalendar = new GregorianCalendar();
+ gregorianCalendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+ gregorianCalendar.setTime(choiceOfTime.getDate());
+
+ DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
+ XMLGregorianCalendar xmlGregorianCalendar = datatypeFactory.newXMLGregorianCalendar(gregorianCalendar);
+ xmlGregorianCalendar.setTimezone(0);
+
+ attributeType.setGeneralizedTime(xmlGregorianCalendar);
+ } catch (Exception e) {
+ log.info("Failed to set GeneralizedTime.", e);
+ }
+
+ } else if (value.isA(ASN.INTEGER)) {
+
+ attributeType.setInteger((BigInteger) value.getValue());
+
+ } else if (value.isA(ASN.UTF8String)) {
+
+ attributeType.setUTF8String((String) value.getValue());
+
+ } else if (value.isA(ASN.PrintableString)) {
+
+ attributeType.setPrintableString((String) value.getValue());
+
+ } else if (value.isA(ASN.UNKNOWN)) {
+
+ byte[] bytes = (byte[]) ((UNKNOWN) value).getValue();
+
+ try {
+ BigInteger bigInteger = new BigInteger(bytes);
+ String string = bigInteger.toString(16);
+
+ Date date = new SimpleDateFormat("yyyyMMdd").parse(string);
+ attributeType.setDate(new SimpleDateFormat("yyyy-MM-dd").format(date));
+ } catch (Exception e) {
+ log.info("Failed to set Date.", e);
+ }
+ }
+
+ }
+
+
+
+
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactory.java
new file mode 100644
index 00000000..d6cbaefa
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactory.java
@@ -0,0 +1,79 @@
+/*
+* 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 java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.xml.crypto.AlgorithmMethod;
+import javax.xml.crypto.dsig.CanonicalizationMethod;
+import javax.xml.crypto.dsig.DigestMethod;
+import javax.xml.crypto.dsig.SignatureMethod;
+
+/**
+ * A factory for creating {@link AlgorithmMethod}s.
+ *
+ * @author mcentner
+ */
+public interface AlgorithmMethodFactory {
+
+ /**
+ * Creates a new DigestMethod for the given <code>signatureContext</code>.
+ *
+ * @param signatureContext
+ * the signature context
+ *
+ * @return a DigestMethod for the given <code>signatureContext</code>
+ *
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public DigestMethod createDigestMethod(SignatureContext signatureContext)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException;
+
+ /**
+ * Creates a new SignatureMethod for the given <code>signatureContext</code>.
+ *
+ * @param signatureContext
+ * the signature context
+ *
+ * @return a SignatureMethod for the given <code>signatureContext</code>
+ *
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public SignatureMethod createSignatureMethod(SignatureContext signatureContext)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException;
+
+ /**
+ * Creates a new CanonicalizationMethod for the given
+ * <code>signatureContext</code>.
+ *
+ * @param signatureContext
+ * the signature context
+ *
+ * @return a CanonicalizationMethod for the given
+ * <code>signatureContext</code>
+ *
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public CanonicalizationMethod createCanonicalizationMethod(
+ SignatureContext signatureContext) throws NoSuchAlgorithmException,
+ InvalidAlgorithmParameterException;
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactoryImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactoryImpl.java
new file mode 100644
index 00000000..8391e450
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactoryImpl.java
@@ -0,0 +1,172 @@
+/*
+* 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.security.ecc.interfaces.ECDSAParams;
+import iaik.xml.crypto.XmldsigMore;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.ECParameterSpec;
+
+import javax.xml.crypto.dsig.CanonicalizationMethod;
+import javax.xml.crypto.dsig.DigestMethod;
+import javax.xml.crypto.dsig.SignatureMethod;
+import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
+import javax.xml.crypto.dsig.spec.DigestMethodParameterSpec;
+import javax.xml.crypto.dsig.spec.SignatureMethodParameterSpec;
+
+/**
+ * An implementation of the AlgorithmMethod factory that uses the signing
+ * certificate to choose appropriate algorithms.
+ *
+ * @author mcentner
+ */
+public class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory {
+
+ /**
+ * Use SHA-2?
+ */
+ private static boolean SHA2 = false;
+
+ /**
+ * The signature algorithm URI.
+ */
+ private String signatureAlgorithmURI;
+
+ /**
+ * the digest algorithm URI.
+ */
+ private String digestAlgorithmURI = DigestMethod.SHA1;
+
+ /**
+ * The algorithm parameters for the signature algorithm.
+ */
+ private SignatureMethodParameterSpec signatureMethodParameterSpec;
+
+ /**
+ * Creates a new AlgrithmMethodFactory with the given
+ * <code>signingCertificate</code>.
+ *
+ * @param signingCertificate
+ *
+ * @throws NoSuchAlgorithmException
+ * if the public key algorithm of the given
+ * <code>signingCertificate</code> is not supported
+ */
+ public AlgorithmMethodFactoryImpl(X509Certificate signingCertificate)
+ throws NoSuchAlgorithmException {
+
+ PublicKey publicKey = signingCertificate.getPublicKey();
+ String algorithm = publicKey.getAlgorithm();
+
+ if ("DSA".equals(algorithm)) {
+ signatureAlgorithmURI = SignatureMethod.DSA_SHA1;
+ } else if ("RSA".equals(algorithm)) {
+
+ int keyLength = 0;
+ if (publicKey instanceof RSAPublicKey) {
+ keyLength = ((RSAPublicKey) publicKey).getModulus().bitLength();
+ }
+
+ if (SHA2 && keyLength >= 2048) {
+ signatureAlgorithmURI = XmldsigMore.SIGNATURE_RSA_SHA256;
+ digestAlgorithmURI = DigestMethod.SHA256;
+ } else {
+ signatureAlgorithmURI = SignatureMethod.RSA_SHA1;
+ }
+
+ } else if (("EC".equals(algorithm)) || ("ECDSA".equals(algorithm))) {
+
+ int fieldSize = 0;
+ if (publicKey instanceof iaik.security.ecc.ecdsa.ECPublicKey) {
+ ECDSAParams params = ((iaik.security.ecc.ecdsa.ECPublicKey) publicKey).getParameter();
+ fieldSize = params.getG().getCurve().getField().getSize().bitLength();
+ } else if (publicKey instanceof ECPublicKey) {
+ ECParameterSpec params = ((ECPublicKey) publicKey).getParams();
+ fieldSize = params.getCurve().getField().getFieldSize();
+ }
+
+ if (SHA2 && fieldSize >= 512) {
+ signatureAlgorithmURI = XmldsigMore.SIGNATURE_ECDSA_SHA512;
+ digestAlgorithmURI = DigestMethod.SHA512;
+ } else if (SHA2 && fieldSize >= 256) {
+ signatureAlgorithmURI = XmldsigMore.SIGNATURE_ECDSA_SHA256;
+ digestAlgorithmURI = DigestMethod.SHA256;
+ } else {
+ signatureAlgorithmURI = XmldsigMore.SIGNATURE_ECDSA_SHA1;
+ }
+
+ } else {
+ throw new NoSuchAlgorithmException("Public key algorithm '" + algorithm
+ + "' not supported.");
+ }
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seeat.gv.egiz.bku.slcommands.impl.xsect.AlgorithmMethodFactory#
+ * createCanonicalizationMethod
+ * (at.gv.egiz.bku.slcommands.impl.xsect.SignatureContext)
+ */
+ @Override
+ public CanonicalizationMethod createCanonicalizationMethod(
+ SignatureContext signatureContext) throws NoSuchAlgorithmException,
+ InvalidAlgorithmParameterException {
+
+ return signatureContext.getSignatureFactory().newCanonicalizationMethod(
+ CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null);
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * at.gv.egiz.bku.slcommands.impl.xsect.AlgorithmMethodFactory#createDigestMethod
+ * (at.gv.egiz.bku.slcommands.impl.xsect.SignatureContext)
+ */
+ @Override
+ public DigestMethod createDigestMethod(SignatureContext signatureContext)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+
+ return signatureContext.getSignatureFactory().newDigestMethod(
+ digestAlgorithmURI, (DigestMethodParameterSpec) null);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seeat.gv.egiz.bku.slcommands.impl.xsect.AlgorithmMethodFactory#
+ * createSignatureMethod
+ * (at.gv.egiz.bku.slcommands.impl.xsect.SignatureContext)
+ */
+ @Override
+ public SignatureMethod createSignatureMethod(SignatureContext signatureContext)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+
+ return signatureContext.getSignatureFactory().newSignatureMethod(
+ signatureAlgorithmURI, signatureMethodParameterSpec);
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/ByteArrayDereferencer.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/ByteArrayDereferencer.java
new file mode 100644
index 00000000..a6473a05
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/ByteArrayDereferencer.java
@@ -0,0 +1,65 @@
+/*
+* 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 java.io.ByteArrayInputStream;
+
+import javax.xml.crypto.Data;
+import javax.xml.crypto.OctetStreamData;
+import javax.xml.crypto.URIDereferencer;
+import javax.xml.crypto.URIReference;
+import javax.xml.crypto.URIReferenceException;
+import javax.xml.crypto.XMLCryptoContext;
+
+/**
+ * An URIDereferencer implementation that dereferences the given
+ * byte array.
+ *
+ * @author mcentner
+ */
+public class ByteArrayDereferencer implements URIDereferencer {
+
+ /**
+ * The dereferenced data.
+ */
+ protected byte[] dereferencedData;
+
+ /**
+ * Creates a new instance of this ByteArrayDereferencer with
+ * the given <code>dereferencedData</code>.
+ *
+ * @param dereferencedData the octets to be returned by {@link #dereference(URIReference, XMLCryptoContext)}
+ *
+ * @throws NullPointerException if <code>dereferencedData</code> is <code>null</code>
+ */
+ public ByteArrayDereferencer(byte[] dereferencedData) {
+ if (dereferencedData == null) {
+ throw new NullPointerException("Parameter 'dereferencedData' must not be null.");
+ }
+ this.dereferencedData = dereferencedData;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.xml.crypto.URIDereferencer#dereference(javax.xml.crypto.URIReference, javax.xml.crypto.XMLCryptoContext)
+ */
+ @Override
+ public Data dereference(URIReference uriReference, XMLCryptoContext context)
+ throws URIReferenceException {
+ return new OctetStreamData(new ByteArrayInputStream(dereferencedData));
+ }
+
+}
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..a57a11dd
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/DataObject.java
@@ -0,0 +1,1289 @@
+/*
+* 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.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.gui.viewer.MimeTypes;
+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.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;
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+
+/**
+ * This class represents a <code>DataObject</code> of an XML-Signature
+ * created by the security layer command <code>CreateXMLSignature</code>.
+ *
+ * @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"
+ };
+
+ /**
+ * Validate hash input.
+ */
+ private static boolean validate = false;
+
+ /**
+ * Enable validation of hash data input.
+ *
+ * @param validate
+ * <code>true</code> if validation should be enabled, or
+ * <code>false</code> otherwise.
+ */
+ public static void enableHashDataInputValidation(boolean validate) {
+ DataObject.validate = validate;
+ }
+
+ /**
+ * @return <code>true</code> if hash data input validation is enabled,
+ * or <code>false</code> 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.
+ * <p>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.</p>
+ *
+ * @param mediaTypes an array of MIME media types.
+ */
+ public static void setValidHashDataInputMediaTypes(String[] mediaTypes) {
+ 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;
+
+ private String filename;
+
+ /**
+ * 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;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ /**
+ * @return the description
+ */
+ 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.debug("MIME media type '" + mediaType + "' is not a s/valid/SUPPORTED digest input, omitting validation.");
+ }
+ }
+
+ }
+
+ /**
+ * Configures this DataObject with the information provided within the given
+ * <code>sl:DataObjectInfo</code>.
+ *
+ * @param dataObjectInfo
+ * the <code>sl:DataObjectInfo</code>
+ *
+ * @throws SLCommandException
+ * if configuring this DataObject with the information provided in
+ * the <code>sl:DataObjectInfo</code> fails.
+ * @throws SLRequestException
+ * if the information provided in the <code>sl:DataObjectInfo</code>
+ * does not conform to the security layer specification.
+ * @throws NullPointerException
+ * if <code>dataObjectInfo</code> is <code>null</code>
+ */
+ 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
+
+ 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.debug("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.debug("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) {
+ 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 = "<AssureDSigNS>".getBytes();
+// post = "</AssureDSigNS>".getBytes();
+// } else {
+// log.trace("XMLDSig bound to prefix " + dsigPrefix);
+// pre = ("<AssureDSigNS xmlns:" + dsigPrefix + "=\"http://www.w3.org/2000/09/xmldsig#\">").getBytes();
+// post = "</AssureDSigNS>".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 <code>sl:DataObject</code>.
+ *
+ * @param dataObject
+ * the <code>sl:DataObject</code>
+ * @param transforms
+ * an optional <code>Transforms</code> element (may be
+ * <code>null</code>)
+ *
+ * @throws SLCommandException
+ * if configuring this DataObject with the information provided in
+ * the <code>sl:DataObject</code> fails.
+ * @throws SLRequestException
+ * if the information provided in the <code>sl:DataObject</code>
+ * does not conform to the security layer specification.
+ * @throws NullPointerException
+ * if <code>dataObject</code> is <code>null</code>
+ */
+ 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 <code>reference</code>.
+ *
+ * @param reference
+ * the <code>reference</code> URI
+ * @param transforms
+ * an optional <code>Transforms</code> element (may be
+ * <code>null</code>)
+ *
+ * @throws SLCommandException
+ * if dereferencing the given <code>reference</code> fails, or if
+ * configuring this DataObject with the data dereferenced from the
+ * given <code>reference</code> fails.
+ * @throws NullPointerException
+ * if <code>reference</code> is <code>null</code>
+ */
+ 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 <code>sl:DataObject</code> and optionally
+ * <code>transforms</code>.
+ *
+ * @param dataObject
+ * the <code>sl:DataObject</code>
+ * @param transforms
+ * an optional Transforms object, may be <code>null</code>
+ *
+ * @throws SLCommandException
+ * if configuring this DataObject with the information provided in
+ * the <code>sl:DataObject</code> fails.
+ * @throws SLRequestException
+ * if the information provided in the <code>sl:DataObject</code>
+ * does not conform to the security layer specification.
+ * @throws NullPointerException
+ * if <code>dataObject</code> is <code>null</code>
+ */
+ 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 <code>sl:TransformInfo</code> from the given list of
+ * <code>transformInfos</code>, or <code>null</code> if none of the given
+ * <code>transformInfos</code> is preferred over the others.
+ *
+ * @param transformsInfos
+ * a list of <code>sl:TransformInfo</code>s
+ *
+ * @return the selected <code>sl:TransformInfo</code> or <code>null</code>, if
+ * none is preferred over the others
+ */
+ private TransformsInfoType selectPreferredTransformsInfo(List<TransformsInfoType> transformsInfos) {
+
+ Map<String, TransformsInfoType> mimeTypes = new HashMap<String, TransformsInfoType>();
+
+ 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 <code>ds:Transforms</code> from the given
+ * <code>sl:TransformsInfo</code>.
+ *
+ * @param transformsInfo
+ * the <code>sl:TransformsInfo</code>
+ *
+ * @return a corresponding unmarshalled <code>ds:Transforms</code>, or
+ * <code>null</code> if the given <code>sl:TransformsInfo</code> does
+ * not contain a <code>dsig:Transforms</code> element
+ *
+ * @throws SLRequestException
+ * if the <code>ds:Transforms</code> in the given
+ * <code>transformsInfo</code> are not valid or cannot be parsed.
+ *
+ * @throws MarshalException
+ * if the <code>ds:Transforms</code> in the given
+ * <code>transformsInfo</code> 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<TransformType> 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 <code>mimeType</code> and the <code>description</code> value
+ * for this DataObject.
+ *
+ * @param metaInfoType the <code>sl:FinalMetaDataInfo</code>
+ *
+ * @throws NullPointerException if <code>metaInfoType</code> is <code>null</code>
+ */
+ 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 <code>sl:TransformInfos</code>, sets the corresponding final data meta info and
+ * returns the corresponding unmarshalled <code>ds:Transforms</code>.
+ *
+ * @param transformsInfos the <code>sl:TransformInfos</code>
+ *
+ * @return the unmarshalled <code>ds:Transforms</code>, or <code>null</code> if
+ * no transformation path has been selected.
+ *
+ * @throws SLRequestException if the given list <code>ds:TransformsInfo</code> contains
+ * an invalid <code>ds:Transforms</code> element, or no suitable transformation path
+ * can be found.
+ */
+ private XSECTTransforms createTransformsAndSetFinalDataMetaInfo(
+ List<TransformsInfoType> 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
+ * <code>content</code>.
+ *
+ * @param content
+ * the to-be Base64 encoded content
+ * @return an XMLObject with the Base64 encoded <code>content</code>
+ */
+ 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 <code>content</code> node.
+ *
+ * @param content the content node
+ *
+ * @return an XMLObject with the given <code>content</code>
+ */
+ private XMLObject createXMLObject(Node content) {
+
+ String idValue = ctx.getIdValueFactory().createIdValue("Object");
+
+ List<DOMStructure> structures = Collections.singletonList(new DOMStructure(content));
+
+ return ctx.getSignatureFactory().newXMLObject(structures, idValue, null, null);
+
+ }
+
+ /**
+ * Sets the given <code>xmlObject</code> and creates and sets a corresponding
+ * <code>Reference</code>.
+ * <p>
+ * A transform to Base64-decode the xmlObject's content is inserted at the top
+ * of to the optional <code>transforms</code> if given, or to a newly created
+ * <code>Transforms</code> element if <code>transforms</code> is
+ * <code>null</code>.
+ *
+ * @param xmlObject
+ * the XMLObject
+ * @param transforms
+ * an optional <code>Transforms</code> element (may be
+ * <code>null</code>)
+ *
+ * @throws SLCommandException
+ * if creating the Reference fails
+ * @throws NullPointerException
+ * if <code>xmlObject</code> is <code>null</code>
+ */
+ 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 <code>xmlObject</code> and creates and sets a corresponding
+ * <code>Reference</code>.
+ * <p>
+ * A transform to select the xmlObject's content is inserted at the top of to
+ * the optional <code>transforms</code> if given, or to a newly created
+ * <code>Transforms</code> element if <code>transforms</code> is
+ * <code>null</code>.
+ * </p>
+ *
+ * @param xmlObject
+ * the XMLObject
+ * @param transforms
+ * an optional <code>Transforms</code> element (may be
+ * <code>null</code>)
+ *
+ * @throws SLCommandException
+ * if creating the Reference fails
+ * @throws NullPointerException
+ * if <code>xmlObject</code> is <code>null</code>
+ */
+ 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<XPathType> 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<Transform> newTransfroms = new ArrayList<Transform>();
+ 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 <code>xmlContent</code> and returns a corresponding
+ * document fragment.
+ *
+ * <p>
+ * The to-be parsed content is surrounded by <dummy> ... </dummy> elements to
+ * allow for mixed (e.g. Text and Element) content in XMLContent.
+ * </p>
+ *
+ * @param xmlContent
+ * the XMLContent to-be parsed
+ *
+ * @return a document fragment containing the parsed nodes
+ *
+ * @throws SLCommandException
+ * if parsing the given <code>xmlContent</code> fails
+ *
+ * @throws NullPointerException
+ * if <code>xmlContent</code> is <code>null</code>
+ */
+ 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<InputStream> inputStreams = new ArrayList<InputStream>();
+ try {
+ // dummy start element
+ inputStreams.add(new ByteArrayInputStream("<dummy>".getBytes("UTF-8")));
+
+ // content
+ inputStreams.add(new ByteArrayInputStream(redirectedStream.toByteArray()));
+
+ // dummy end element
+ inputStreams.add(new ByteArrayInputStream("</dummy>".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 <code>inputStream</code> using the given
+ * <code>encoding</code> and returns the parsed document.
+ *
+ * @param inputStream
+ * the to-be parsed input
+ *
+ * @param encoding
+ * the encoding to be used for parsing the given
+ * <code>inputStream</code>
+ *
+ * @return the parsed document
+ *
+ * @throws SLCommandException
+ * if parsing the <code>inputStream</code> fails.
+ *
+ * @throws NullPointerException
+ * if <code>inputStram</code> is <code>null</code>
+ */
+ 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<String> 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/IdValueFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/IdValueFactory.java
new file mode 100644
index 00000000..df42bd11
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/IdValueFactory.java
@@ -0,0 +1,37 @@
+/*
+* 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;
+
+/**
+ * A factory for creating <code>xsd:Id</code>-attribute values.
+ *
+ * @author mcentner
+ */
+public interface IdValueFactory {
+
+ /**
+ * Creates a new <code>xsd:Id</code>-attribute value for an Element of the
+ * given <code>elementName</code>.
+ *
+ * @param elementName
+ * the local name of the element to create the value for
+ *
+ * @return a <code>xsd:Id</code>-attribute value
+ */
+ public String createIdValue(String elementName);
+
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/IdValueFactoryImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/IdValueFactoryImpl.java
new file mode 100644
index 00000000..b9824655
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/IdValueFactoryImpl.java
@@ -0,0 +1,127 @@
+/*
+* 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 java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ * An implementation of the IdValueFactory.
+ * <p>
+ * This IdValueFactory creates <code>xsd:Id</code>-attribute values of the form
+ * '<code>&lt;elementName&gt;-&lt;random&gt;-&lt;sequenceNumber&gt;</code>',
+ * where
+ * <ul>
+ * <li><code>&lt;elementName&gt;</code> is the name provided at
+ * {@link #createIdValue(String)},</li>
+ * <li><code>&lt;random&gt;</code> is a random generated fixed value for an
+ * instance of this IdValueFactory and</li>
+ * <li><code>&lt;sequenceNumber&gt;</code> is the sequence number of the value
+ * generated for a given <code>elementName</code> by an instance of this
+ * IdValueFactory.</li>
+ * </ul>
+ * </p>
+ *
+ * @author mcentner
+ */
+public class IdValueFactoryImpl implements IdValueFactory {
+
+ /**
+ * A generator for <code>xsd:Id</code>-attribute values.
+ *
+ * @author mcentner
+ */
+ private class IdGenerator {
+
+ /**
+ * The salt.
+ */
+ private String salt;
+
+ /**
+ * The element name.
+ */
+ private String elementName;
+
+ /**
+ * The sequence number.
+ */
+ private int i = 0;
+
+ /**
+ * Creates a new instance of this IdGenerator with the given
+ * <code>elementName</code> and <code>salt</code> value.
+ *
+ * @param elementName the element name
+ * @param salt the salt valeu
+ */
+ private IdGenerator(String elementName, String salt) {
+ super();
+ this.elementName = elementName;
+ this.salt = salt;
+ }
+
+ /**
+ * @return returns the next <code>xsd:Id</code>-attribute value.
+ */
+ public String getNextId() {
+ return elementName + "-" + salt + "-" + Integer.toString(++i);
+ }
+
+ }
+
+ /**
+ * A map of element names to <code>xsd:Id</code>-value generators.
+ */
+ private Map<String, IdGenerator> generators = new HashMap<String, IdGenerator>();
+
+ /**
+ * The seed value.
+ */
+ private String seed;
+
+ /**
+ * Creates a new instance of this IdValueFactory.
+ */
+ public IdValueFactoryImpl() {
+
+ Random random = new Random();
+ int rand = random.nextInt();
+ seed = Integer.toHexString(rand);
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * at.gv.egiz.bku.slcommands.impl.IdValueFactory#createIdValue(java.lang.String
+ * )
+ */
+ public String createIdValue(String elementName) {
+
+ IdGenerator generator = generators.get(elementName);
+ if (generator == null) {
+ generator = new IdGenerator(elementName, seed);
+ generators.put(elementName, generator);
+ }
+ return generator.getNextId();
+
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/LocRefDereferencer.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/LocRefDereferencer.java
new file mode 100644
index 00000000..f5394157
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/LocRefDereferencer.java
@@ -0,0 +1,112 @@
+/*
+* 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 java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.xml.crypto.Data;
+import javax.xml.crypto.OctetStreamData;
+import javax.xml.crypto.URIDereferencer;
+import javax.xml.crypto.URIReference;
+import javax.xml.crypto.URIReferenceException;
+import javax.xml.crypto.XMLCryptoContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.utils.urldereferencer.StreamData;
+import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer;
+import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerContext;
+
+/**
+ * An URIDereferencer implementation that dereferences <code>LocRef</code>
+ * references.
+ *
+ * @author mcentner
+ */
+public class LocRefDereferencer implements URIDereferencer {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(LocRefDereferencer.class);
+
+ /**
+ * The <code>LocRef</code>-reference to be dereferenced by
+ * {@link #dereference(URIReference, XMLCryptoContext)}.
+ */
+ protected String locRef;
+
+ /**
+ * The context to be used for dereferencing.
+ */
+ protected URLDereferencerContext dereferencerContext;
+
+ /**
+ * Creates a new instance of this LocRefDereferencer with the given
+ * <code>dereferencerContext</code> and <code>locRef</code> reference.
+ *
+ * @param dereferencerContext
+ * the context to be used for dereferencing
+ * @param locRef
+ * the <code>LocRef</code>-reference (must be an absolute URI)
+ *
+ * @throws URISyntaxException
+ * if <code>LocRef</code> is not an absolute URI
+ */
+ public LocRefDereferencer(URLDereferencerContext dereferencerContext,
+ String locRef) throws URISyntaxException {
+
+ this.dereferencerContext = dereferencerContext;
+
+ URI locRefUri = new URI(locRef);
+ if (locRefUri.isAbsolute()) {
+ this.locRef = locRef;
+ } else {
+ throw new IllegalArgumentException(
+ "Parameter 'locRef' must be an absolut URI.");
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * javax.xml.crypto.URIDereferencer#dereference(javax.xml.crypto.URIReference,
+ * javax.xml.crypto.XMLCryptoContext)
+ */
+ @Override
+ public Data dereference(URIReference uriReference, XMLCryptoContext context)
+ throws URIReferenceException {
+
+ URLDereferencer dereferencer = URLDereferencer.getInstance();
+ StreamData streamData;
+ try {
+ streamData = dereferencer.dereference(locRef, dereferencerContext);
+ } catch (IOException e) {
+ log.info("Failed to dereference URI'" + locRef + "'. " + e.getMessage(),
+ e);
+ throw new URIReferenceException("Failed to dereference URI '" + locRef
+ + "'. " + e.getMessage(), e);
+ }
+ return new OctetStreamData(streamData.getStream(), locRef, streamData
+ .getContentType());
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALPrivateKey.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALPrivateKey.java
new file mode 100644
index 00000000..25e2d4e5
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALPrivateKey.java
@@ -0,0 +1,128 @@
+/*
+* 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 at.gv.egiz.stal.HashDataInput;
+import java.security.PrivateKey;
+
+import at.gv.egiz.stal.STAL;
+//import at.gv.egiz.stal.HashDataInputCallback;
+import java.util.List;
+
+/**
+ * This class implements a private key used by the {@link STALSignature} class.
+ *
+ * @author mcentner
+ */
+public class STALPrivateKey implements PrivateKey {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The STAL implementation.
+ */
+ private STAL stal;
+
+ /**
+ * The callback interface for obtaining the hash input data.
+ */
+// private HashDataInputCallback hashDataInputCallback;
+
+
+ private List<DataObject> dataObjects;
+
+ /**
+ * The keybox identifier.
+ */
+ private String keyboxIdentifier;
+
+ /**
+ * The signature algorithm.
+ */
+ private String algorithm;
+
+ /**
+ * Creates a new instance of this <code>STALPrivateKey</code> with the given
+ * <code>stal</code> implementation, signature <code>algorithm</code>,
+ * <code>keyboxIdentifier</code> and <code>hashDataInputCallback</code>
+ * interface.
+ *
+ * @param stal
+ * the STAL implementation
+ * @param algorithm
+ * the signature algorithm
+ * @param keyboxIdentifier
+ * the keybox identifier
+ * @param hashDataInputCallback
+ * the interface for obtaining the has input data
+ */
+ public STALPrivateKey(STAL stal,
+ String algorithm, String keyboxIdentifier, List<DataObject> dataObjects) {
+ super();
+ this.keyboxIdentifier = keyboxIdentifier;
+ this.dataObjects = dataObjects;
+ this.stal = stal;
+ this.algorithm = algorithm;
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.Key#getAlgorithm()
+ */
+ @Override
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.Key#getEncoded()
+ */
+ @Override
+ public byte[] getEncoded() {
+ throw new UnsupportedOperationException("STALPrivateKey does not support the getEncoded() method.");
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.Key#getFormat()
+ */
+ @Override
+ public String getFormat() {
+ return null;
+ }
+
+ /**
+ * @return the STAL implementation
+ */
+ public STAL getStal() {
+ return stal;
+ }
+
+ /**
+ * @return the interface for obtaining the hash data input
+ */
+ public List<DataObject> getDataObjects() {
+
+ return dataObjects;
+ }
+
+ /**
+ * @return the keybox identifier
+ */
+ public String getKeyboxIdentifier() {
+ return keyboxIdentifier;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALProvider.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALProvider.java
new file mode 100644
index 00000000..9fb9a3f1
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALProvider.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.slcommands.impl.xsect;
+
+import iaik.xml.crypto.XmldsigMore;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.Signature;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.crypto.dsig.SignatureMethod;
+
+/**
+ * A security provider implementation that provides {@link Signature} implementations
+ * based on STAL.
+ *
+ * @author mcentner
+ */
+public class STALProvider extends Provider {
+
+ private static final long serialVersionUID = 1L;
+
+ private static String IMPL_PACKAGE_NAME = "at.gv.egiz.bku.slcommands.impl.xsect";
+
+ public STALProvider() {
+
+ super("STAL", 1.0, "Security Token Abstraction Layer Provider");
+
+ final Map<String, String> map = new HashMap<String, String>();
+
+ // TODO: register further algorithms
+ map.put("Signature." + SignatureMethod.RSA_SHA1,
+ IMPL_PACKAGE_NAME + ".STALSignature");
+ map.put("Signature." + XmldsigMore.SIGNATURE_ECDSA_SHA1,
+ IMPL_PACKAGE_NAME + ".STALSignature");
+ map.put("Signature." + XmldsigMore.SIGNATURE_RSA_SHA256,
+ IMPL_PACKAGE_NAME + ".STALSignature");
+ map.put("Signature." + XmldsigMore.SIGNATURE_ECDSA_SHA256,
+ IMPL_PACKAGE_NAME + ".STALSignature");
+ map.put("Signature." + XmldsigMore.SIGNATURE_ECDSA_SHA512,
+ IMPL_PACKAGE_NAME + ".STALSignature");
+
+
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ putAll(map);
+ return null;
+ }
+ });
+
+ }
+
+}
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
new file mode 100644
index 00000000..dd7c7d8a
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALSignature.java
@@ -0,0 +1,184 @@
+/*
+* 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 at.gv.egiz.bku.slcommands.impl.DataObjectHashDataInput;
+import at.gv.egiz.bku.slexceptions.SLViewerException;
+
+import java.io.ByteArrayOutputStream;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.util.Collections;
+import java.util.List;
+
+import at.gv.egiz.stal.ErrorResponse;
+import at.gv.egiz.stal.HashDataInput;
+import at.gv.egiz.stal.STAL;
+import at.gv.egiz.stal.STALRequest;
+import at.gv.egiz.stal.STALResponse;
+import at.gv.egiz.stal.SignRequest;
+import at.gv.egiz.stal.SignResponse;
+//import at.gv.egiz.stal.HashDataInputCallback;
+import java.util.ArrayList;
+
+/**
+ * A signature service provider implementation that uses STAL to sign.
+ *
+ * @author mcentner
+ */
+public class STALSignature extends SignatureSpi {
+
+// private static final Log log = LogFactory.getLog(STALSignature.class);
+
+ /**
+ * The private key.
+ */
+ protected STALPrivateKey privateKey;
+
+ /**
+ * The to-be signed data.
+ */
+ protected ByteArrayOutputStream data = new ByteArrayOutputStream();
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineGetParameter(java.lang.String)
+ */
+ @Override
+ protected Object engineGetParameter(String param)
+ throws InvalidParameterException {
+ throw new InvalidParameterException();
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineInitSign(java.security.PrivateKey)
+ */
+ @Override
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException {
+
+ if (!(privateKey instanceof STALPrivateKey)) {
+ throw new InvalidKeyException("STALSignature supports STALKeys only.");
+ }
+
+ this.privateKey = (STALPrivateKey) privateKey;
+
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineInitVerify(java.security.PublicKey)
+ */
+ @Override
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException {
+
+ throw new UnsupportedOperationException("STALSignature does not support signature verification.");
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineSetParameter(java.lang.String, java.lang.Object)
+ */
+ @Override
+ protected void engineSetParameter(String param, Object value)
+ throws InvalidParameterException {
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineSign()
+ */
+ @Override
+ protected byte[] engineSign() throws SignatureException {
+
+ STAL stal = privateKey.getStal();
+
+ if (stal == null) {
+ throw new SignatureException("STALSignature requires the STALPrivateKey " +
+ "to provide a STAL implementation reference.");
+ }
+
+ String keyboxIdentifier = privateKey.getKeyboxIdentifier();
+
+ if (keyboxIdentifier == null) {
+ throw new SignatureException("STALSignature requires the STALPrivateKey " +
+ "to provide a KeyboxIdentifier.");
+ }
+
+ // get hashDataInputs (DigestInputStreams) once slcommands.impl.xsect.Signature::sign() was called
+ List<DataObject> dataObjects = privateKey.getDataObjects();
+// log.debug("got " + dataObjects.size() + " DataObjects, passing HashDataInputs to STAL SignRequest");
+
+ List<HashDataInput> hashDataInputs = new ArrayList<HashDataInput>();
+ for (DataObject dataObject : dataObjects) {
+ try {
+ dataObject.validateHashDataInput();
+ } catch (SLViewerException e) {
+ throw new STALSignatureException(e);
+ }
+ hashDataInputs.add(new DataObjectHashDataInput(dataObject));
+ }
+
+ SignRequest signRequest = new SignRequest();
+ signRequest.setKeyIdentifier(keyboxIdentifier);
+ signRequest.setSignedInfo(data.toByteArray());
+ signRequest.setHashDataInput(hashDataInputs);
+
+ List<STALResponse> responses = stal.handleRequest(Collections.singletonList((STALRequest) signRequest));
+
+ if (responses == null || responses.size() != 1) {
+ throw new SignatureException("Failed to access STAL.");
+ }
+
+ STALResponse response = responses.get(0);
+ if (response instanceof SignResponse) {
+ return ((SignResponse) response).getSignatureValue();
+ } else if (response instanceof ErrorResponse) {
+ throw new STALSignatureException(((ErrorResponse) response).getErrorCode());
+ } else {
+ throw new SignatureException("Failed to access STAL.");
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineUpdate(byte)
+ */
+ @Override
+ protected void engineUpdate(byte b) throws SignatureException {
+ data.write(b);
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineUpdate(byte[], int, int)
+ */
+ @Override
+ protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException {
+ data.write(b, off, len);
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineVerify(byte[])
+ */
+ @Override
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+ throw new UnsupportedOperationException("STALSignature des not support signature verification.");
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALSignatureException.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALSignatureException.java
new file mode 100644
index 00000000..4e86b07c
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/STALSignatureException.java
@@ -0,0 +1,92 @@
+/*
+* 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 java.security.SignatureException;
+
+/**
+ * A SignatureException thrown by the {@link STALSignature}.
+ *
+ * @author mcentner
+ */
+public class STALSignatureException extends SignatureException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The STAL error code.
+ */
+ private int errorCode;
+
+ /**
+ * Creates a new instance of this STALSignatureException.
+ */
+ public STALSignatureException() {
+ }
+
+ /**
+ * Creates a new instance of this STALSigantureException with
+ * the given <code>errorCode</code>.
+ *
+ * @param errorCode the error code
+ */
+ public STALSignatureException(int errorCode) {
+ this.errorCode = errorCode;
+ }
+
+ /**
+ * Creates a new instance of this STALSignatureException with
+ * the given error <code>msg</code>.
+ *
+ * @param msg the error message
+ * @see SignatureException#SignatureException(String)
+ */
+ public STALSignatureException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates a new instance of this STALSignatureException with
+ * the given root <code>cause</code>.
+ *
+ * @param cause the cause
+ * @see SignatureException#SignatureException(Throwable)
+ */
+ public STALSignatureException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Creates a new instance of this STALSignautureException with
+ * the given error <code>message</code> and root <code>cause</code>.
+ *
+ * @param message the error message
+ * @param cause the cause
+ * @see SignatureException#SignatureException(String, Throwable)
+ */
+ public STALSignatureException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * @return the error code
+ */
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+}
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
new file mode 100644
index 00000000..3cebb6a3
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/Signature.java
@@ -0,0 +1,995 @@
+/*
+* 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 java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+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.SignatureMethod;
+import javax.xml.crypto.dsig.SignedInfo;
+import javax.xml.crypto.dsig.XMLObject;
+import javax.xml.crypto.dsig.XMLSignature;
+import javax.xml.crypto.dsig.XMLSignatureException;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+import javax.xml.crypto.dsig.dom.DOMSignContext;
+import javax.xml.crypto.dsig.keyinfo.KeyInfo;
+import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
+import javax.xml.crypto.dsig.keyinfo.X509Data;
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.etsi.uri._01903.v1_1.DataObjectFormatType;
+import org.etsi.uri._01903.v1_1.QualifyingPropertiesType;
+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.NodeList;
+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.LSResourceResolver;
+import org.w3c.dom.ls.LSSerializer;
+
+import at.buergerkarte.namespaces.securitylayer._1.Base64XMLLocRefReqRefContentType;
+import at.buergerkarte.namespaces.securitylayer._1.Base64XMLOptRefContentType;
+import at.buergerkarte.namespaces.securitylayer._1.DataObjectAssociationType;
+import at.buergerkarte.namespaces.securitylayer._1.DataObjectInfoType;
+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;
+import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerContext;
+import at.gv.egiz.dom.DOMUtils;
+import at.gv.egiz.slbinding.impl.XMLContentType;
+import at.gv.egiz.stal.STAL;
+import at.gv.egiz.xades.QualifyingPropertiesException;
+import at.gv.egiz.xades.QualifyingPropertiesFactory;
+
+/**
+ * This class represents an XML-Signature as to be created by the
+ * security layer command <code>CreateXMLSignatureRequest</code>.
+ *
+ * @author mcentner
+ */
+public class Signature {
+ public static final String XMLDSIG_PREFIX = "dsig";
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(Signature.class);
+
+ /**
+ * The DOM implementation used.
+ */
+ private DOMImplementationLS domImplLS;
+
+ /**
+ * The SignatureContext for the XMLSignature.
+ */
+ private SignatureContext ctx;
+
+ /**
+ * The list of {@link DataObject}s for this signature.
+ */
+ private List<DataObject> dataObjects = new ArrayList<DataObject>();
+
+ /**
+ * A mapping from the <code>Id</code>-attribute values of this signature's
+ * <code>ds:Reference</code>s to the corresponding {@link DataObject}s.
+ */
+// private Map<String, DataObject> dataObjectReferencIds = new HashMap<String, DataObject>();
+
+ /**
+ * The SignatureEnvironment for this signature.
+ */
+ private SignatureLocation signatureLocation;
+
+ /**
+ * The XML signature.
+ */
+ private XMLSignature xmlSignature;
+
+ /**
+ * A list of attributes of type <code>xsd:ID</code> to be registered in the {@link DOMSignContext}.
+ */
+ private List<IdAttribute> idAttributes = new ArrayList<IdAttribute>();
+
+ /**
+ * The signer's X509 certificate.
+ */
+ private X509Certificate signerCertificate;
+
+ /**
+ * The signing time.
+ */
+ private Date signingTime;
+
+ /**
+ * Creates a new SLXMLSignature instance.
+ */
+ public Signature(URLDereferencerContext dereferencerContext,
+ IdValueFactory idValueFactory,
+ AlgorithmMethodFactory algorithmMethodFactory) {
+
+ domImplLS = DOMUtils.getDOMImplementationLS();
+
+ ctx = new SignatureContext();
+
+ ctx.setSignatureFactory(XMLSignatureFactory.getInstance());
+
+ ctx.setDereferencerContext(dereferencerContext);
+ ctx.setIdValueFactory(idValueFactory);
+ ctx.setAlgorithmMethodFactory(algorithmMethodFactory);
+
+ }
+
+ /**
+ * @return the Document containing this Signature
+ */
+ public Document getDocument() {
+ return ctx.getDocument();
+ }
+
+ /**
+ * @return the parent Node for this Signature
+ */
+ public Node getParent() {
+ return (signatureLocation != null) ? signatureLocation.getParent() : null;
+ }
+
+ /**
+ * @return the next sibling Node for this Signature
+ */
+ public Node getNextSibling() {
+ return (signatureLocation != null) ? signatureLocation.getNextSibling() : null;
+ }
+
+ /**
+ * @return the XMLSignature
+ */
+ public XMLSignature getXMLSignature() {
+ return xmlSignature;
+ }
+
+ /**
+ * @return the list of {@link Reference}s of this Signature
+ */
+ @SuppressWarnings("unchecked")
+ public List<Reference> getReferences() {
+ return (xmlSignature != null) ? xmlSignature.getSignedInfo().getReferences() : null;
+ }
+
+ /**
+ * @return the list of {@link XMLObject}s of this Signature
+ */
+ @SuppressWarnings("unchecked")
+ public List<XMLObject> getXMLObjects() {
+ return (xmlSignature != null) ? xmlSignature.getObjects() : null;
+ }
+
+ /**
+ * Prepares the signature document with the information given by the
+ * <code>signatureInfo</code> provided.
+ *
+ * @param signatureInfo
+ * the <code>SignatureInfo</code>
+ *
+ * @throws SLCommandException
+ * if processing fails for any reason
+ * @throws IllegalStateException
+ * if the <code>parent</code> node has already been set
+ * @throws NullPointerException
+ * if <code>signatureInfo</code> is <code>null</code>
+ */
+ public void setSignatureInfo(SignatureInfoCreationType signatureInfo) throws SLCommandException {
+
+ if (signatureLocation != null) {
+ throw new IllegalStateException("SignatureEnvironment already set.");
+ }
+
+ Base64XMLOptRefContentType signatureEnvironment = signatureInfo.getSignatureEnvironment();
+
+ if (signatureEnvironment == null) {
+
+ // no SignatureEnvironment, so we use an empty document and the document as parent
+ ensureSignatureLocation();
+
+ } else {
+
+ // parse SignatureEnvrionment and use as document
+ Document document = parseSignatureEnvironment(signatureEnvironment, signatureInfo.getSupplement());
+ ctx.setDocument(document);
+
+ signatureLocation = new SignatureLocation(ctx);
+ signatureLocation.setSignatureInfo(signatureInfo);
+
+ }
+
+ }
+
+ /**
+ * Ensures a SignatureLocation for this Signature.
+ */
+ private void ensureSignatureLocation() {
+
+ if (signatureLocation == null) {
+ Document document = DOMUtils.createDocument();
+ ctx.setDocument(document);
+
+ signatureLocation = new SignatureLocation(ctx);
+ signatureLocation.setParent(document);
+ }
+
+ }
+
+ /**
+ * Adds a DataObject with the information given by the
+ * <code>dataObjectInfo</code> provided to this Signature.
+ *
+ * @param dataObjectInfo
+ * the <code>DataObjectInfo</code> element
+ *
+ * @throws SLCommandException
+ * if adding the DataObject fails
+ * @throws SLRequestException
+ * if the information provided by the given
+ * <code>dataObjectInfo</code> does not conform to the security
+ * layer specification
+ * @throws NullPointerException
+ * if <code>dataObjectInfo</code> is <code>null</code>
+ */
+ public void addDataObject(DataObjectInfoType dataObjectInfo) throws SLCommandException, SLRequestException {
+
+ ensureSignatureLocation();
+
+ DataObject dataObject = new DataObject(ctx);
+ dataObject.setDataObjectInfo(dataObjectInfo);
+
+ dataObjects.add(dataObject);
+
+// dataObjectReferencIds.put(dataObject.getReference().getId(), dataObject);
+
+ }
+
+ /**
+ * Sets the <code>SigningTime</code> qualifying property of this Signature.
+ *
+ * @param signingTime the signing time to set
+ */
+ public void setSigningTime(Date signingTime) {
+ this.signingTime = signingTime;
+ }
+
+ /**
+ * Sets the <code>SignerCertificate</code> qualifying property of this Signature.
+ *
+ * @param certificate the signer's certificate
+ */
+ public void setSignerCeritifcate(X509Certificate certificate) {
+ this.signerCertificate = certificate;
+ }
+
+ /**
+ * Builds the XMLSignature data structure of this Signature as configured by
+ * the various setter methods.
+ *
+ * @throws SLCommandException if building this signature fails
+ */
+ public void buildXMLSignature() throws SLCommandException {
+
+ String signatureId = ctx.getIdValueFactory().createIdValue("Signature");
+
+ List<XMLObject> objects = new ArrayList<XMLObject>();
+ List<Reference> references = new ArrayList<Reference>();
+
+ // add all data objects
+ for (DataObject dataObject : dataObjects) {
+ if (dataObject.getXmlObject() != null) {
+ objects.add(dataObject.getXmlObject());
+ }
+ if (dataObject.getReference() != null) {
+ references.add(dataObject.getReference());
+ }
+ }
+
+ addXAdESObjectAndReference(objects, references, signatureId);
+
+ XMLSignatureFactory signatureFactory = ctx.getSignatureFactory();
+ AlgorithmMethodFactory algorithmMethodFactory = ctx.getAlgorithmMethodFactory();
+
+ CanonicalizationMethod cm;
+ SignatureMethod sm;
+ try {
+ cm = algorithmMethodFactory.createCanonicalizationMethod(ctx);
+ sm = algorithmMethodFactory.createSignatureMethod(ctx);
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Failed to get Canonicalization or Signature algorithm.", e);
+ throw new SLCommandException(4006);
+ } catch (InvalidAlgorithmParameterException e) {
+ log.error("Failed to get Canonicalization or Signature algorithm.", e);
+ throw new SLCommandException(4006);
+ }
+
+ String siId = ctx.getIdValueFactory().createIdValue("SignedInfo");
+
+ SignedInfo si = signatureFactory.newSignedInfo(cm, sm, references, siId);
+
+ KeyInfo ki = null;
+ if (signerCertificate != null) {
+ KeyInfoFactory kif = KeyInfoFactory.getInstance();
+ X509Data x509Data = kif.newX509Data(Collections.singletonList(signerCertificate));
+ ki = kif.newKeyInfo(Collections.singletonList(x509Data));
+ }
+
+ String signatureValueId = ctx.getIdValueFactory().createIdValue("SignatureValue");
+
+ xmlSignature = signatureFactory.newXMLSignature(si, ki, objects, signatureId, signatureValueId);
+
+ }
+
+ /**
+ * Sign this Signature using the given <code>signContext</code>.
+ * <p>
+ * Call's {@link #buildXMLSignature()} if it has not been called yet.
+ * </p>
+ *
+ * @param signContext
+ * the signing context
+ *
+ * @throws MarshalException
+ * if marshalling the XMLSignature fails
+ * @throws XMLSignatureException
+ * if signing the XMLSignature fails
+ * @throws SLCommandException
+ * if building the XMLSignature fails
+ * @throws SLViewerException
+ * @throws NullPointerException
+ * if <code>signContext</code> is <code>null</code>
+ */
+ public void sign(DOMSignContext signContext) throws MarshalException, XMLSignatureException, SLCommandException, SLViewerException {
+
+ if (xmlSignature == null) {
+ buildXMLSignature();
+ }
+
+ for (IdAttribute idAttribute : idAttributes) {
+ signContext.setIdAttributeNS(idAttribute.element, idAttribute.namespaceURI, idAttribute.localName);
+ }
+
+ // DO NOT USE:
+ // signContext.setProperty("iaik.xml.crypto.dsig.sign-over", Boolean.TRUE);
+
+ signContext.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE);
+
+ signContext.putNamespacePrefix(XMLSignature.XMLNS,XMLDSIG_PREFIX);
+
+ signContext.setURIDereferencer(new URIDereferncerAdapter(ctx.getDereferencerContext()));
+
+ try {
+ xmlSignature.sign(signContext);
+ } catch (XMLSignatureException e) {
+ 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);
+ throw commandException;
+ } else {
+ cause = cause.getCause();
+ }
+ }
+ throw e;
+ }
+
+ // debug
+ if (log.isTraceEnabled()) {
+ for (DataObject dataObject : dataObjects) {
+ Reference reference = dataObject.getReference();
+ InputStream digestInputStream = reference.getDigestInputStream();
+ if (digestInputStream != null) {
+ String mimeType = dataObject.getMimeType();
+ StringBuilder sb = new StringBuilder();
+ sb.append("DigestInput for Reference with id='");
+ sb.append(reference.getId());
+ sb.append("' (MIME-Type=");
+ sb.append(dataObject.getMimeType());
+ sb.append("):\n");
+ try {
+ if (mimeType != null && (
+ mimeType.startsWith("text") ||
+ "application/xhtml+xml".equals(mimeType))) {
+ byte[] b = new byte[512];
+ for (int l; (l = digestInputStream.read(b)) != -1;) {
+ sb.append(new String(b, 0, l));
+ }
+ } else {
+ sb.append(HexDump.hexDump(digestInputStream));
+ }
+ } catch (IOException e) {
+ log.error(e);
+ }
+ log.trace(sb.toString());
+ } else {
+ log.trace("Reference caching is not enabled.");
+ }
+ }
+ for (Reference reference : getReferences()) {
+ if (reference.getType() != null) {
+ InputStream digestInputStream = reference.getDigestInputStream();
+ if (digestInputStream != null) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("DigestInput for Reference with id='");
+ sb.append(reference.getId());
+ sb.append("'; Type:");
+ sb.append(reference.getType());
+ sb.append("):\n");
+ try {
+ byte[] b = new byte[512];
+ for (int l; (l = digestInputStream.read(b)) != -1;) {
+ sb.append(new String(b, 0, l));
+ }
+ } catch (IOException e) {
+ log.error(e);
+ }
+ log.trace(sb.toString());
+ } else {
+ log.trace("Reference caching is not enabled.");
+ }
+
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Sign this Signature using the given <code>stal</code> implementation and
+ * <code>keyboxIdentifier</code>.
+ * <p>
+ * This method configures an appropriate {@link DOMSignContext} and calls
+ * {@link #sign(DOMSignContext)}. If {@link #buildXMLSignature()} has not been
+ * called yet, it is called by this method.
+ * </p>
+ *
+ * @param stal
+ * the STAL implementation to use
+ * @param keyboxIdentifier
+ * the KeyboxIdentifier to use
+ *
+ * @throws MarshalException
+ * if marshalling this Signature fails
+ * @throws XMLSignatureException
+ * if signing this Signature fails
+ * @throws SLCommandException
+ * if building this Signature fails
+ * @throws SLViewerException
+ * @throws NullPointerException
+ * if <code>stal</code> or <code>keyboxIdentifier</code> is
+ * <code>null</code>
+ */
+ public void sign(STAL stal, String keyboxIdentifier) throws MarshalException, XMLSignatureException, SLCommandException, SLViewerException {
+
+ if (stal == null) {
+ throw new NullPointerException("Argument 'stal' must not be null.");
+ }
+
+ if (keyboxIdentifier == null) {
+ throw new NullPointerException("Argument 'keyboxIdentifier' must not be null.");
+ }
+
+ if (xmlSignature == null) {
+ buildXMLSignature();
+ }
+
+ SignatureMethod signatureMethod = xmlSignature.getSignedInfo().getSignatureMethod();
+ String algorithm = signatureMethod.getAlgorithm();
+
+ //don't get hashDataInputs (digestInputStreams) now, only once Signature.sign() was called (cf STALSignature.engineSign)
+ PrivateKey privateKey = new STALPrivateKey(stal, algorithm, keyboxIdentifier, dataObjects); // hashDataInputs);
+
+ DOMSignContext signContext;
+ if (getNextSibling() == null) {
+ signContext = new DOMSignContext(privateKey, getParent());
+ } else {
+ signContext = new DOMSignContext(privateKey, getParent(), getNextSibling());
+ }
+
+ sign(signContext);
+ }
+
+// @Override
+// public HashDataInput getHashDataInput(final String referenceId) {
+// final DataObject dataObject = dataObjectReferencIds.get(referenceId);
+// if (dataObject != null) {
+// return new HashDataInput() {
+//
+// InputStream hashDataInput = dataObject.getReference().getDigestInputStream();
+//
+// @Override
+// public String getReferenceId() {
+// return referenceId;
+// }
+//
+// @Override
+// public String getMimeType() {
+// return dataObject.getMimeType();
+// }
+//
+// @Override
+// public InputStream getHashDataInput() {
+// return hashDataInput;
+// }
+// };
+// }
+// return null;
+// }
+
+ /**
+ * Adds the XAdES <code>QualifyingProperties</code> as an
+ * <code>ds:Object</code> and a corresponding <code>ds:Reference</code> to
+ * it's <code>SignedProperties</code> element to this Signature.
+ *
+ * @param objects
+ * the list of <code>ds:Objects</code> to add the created
+ * <code>ds:Object</code> to
+ * @param references
+ * the list of <code>ds:References</code> to add the created
+ * <code>ds:Reference</code> to
+ * @param signatureId TODO
+ * @throws SLCommandException
+ * if creating and adding the XAdES
+ * <code>QualifyingProperties</code> fails
+ * @throws NullPointerException
+ * if <code>objects</code> or <code>references</code> is
+ * <code>null</code>
+ */
+ private void addXAdESObjectAndReference(List<XMLObject> objects, List<Reference> references, String signatureId) throws SLCommandException {
+
+ QualifyingPropertiesFactory factory = QualifyingPropertiesFactory.getInstance();
+
+ String idValue = ctx.getIdValueFactory().createIdValue("SignedProperties");
+
+ Date date = (signingTime != null) ? signingTime : new Date();
+
+ List<X509Certificate> signingCertificates;
+ if (signerCertificate != null) {
+ signingCertificates = Collections.singletonList(signerCertificate);
+ } else {
+ signingCertificates = Collections.emptyList();
+ }
+
+ // TODO: report MOA-SP bug
+ //
+ // The security layer specification mandates the use of version 1.2.2. of the
+ // XAdES QualifyingProperties. However MOA-SP supports only version 1.1.1. Therefore,
+ // the version 1.1.1 is used in order to be compatible with current MOA-SP versions.
+
+ List<DataObjectFormatType> dataObjectFormats = new ArrayList<DataObjectFormatType>();
+ for (DataObject dataObject : dataObjects) {
+ if (dataObject.getMimeType() != null && dataObject.getReference() != null) {
+ Reference reference = dataObject.getReference();
+ if (reference.getId() != null) {
+ String objectReference = "#" + reference.getId();
+ dataObjectFormats.add(factory.createDataObjectFormatType(
+ objectReference, dataObject.getMimeType(), dataObject
+ .getDescription()));
+ }
+ }
+ }
+
+ String target = "#" + signatureId;
+
+ DigestMethod dm;
+ try {
+ dm = ctx.getAlgorithmMethodFactory().createDigestMethod(ctx);
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Failed to get DigestMethod algorithm.", e);
+ throw new SLCommandException(4006);
+ } catch (InvalidAlgorithmParameterException e) {
+ log.error("Failed to get DigestMethod algorithm.", e);
+ throw new SLCommandException(4006);
+ }
+
+ JAXBElement<QualifyingPropertiesType> qualifyingProperties;
+ try {
+ qualifyingProperties = factory.createQualifyingProperties111(target, date, signingCertificates, idValue, dataObjectFormats, dm);
+ } catch (QualifyingPropertiesException e) {
+ log.error("Failed to create QualifyingProperties.", e);
+ throw new SLCommandException(4000);
+ }
+
+ DocumentFragment fragment = ctx.getDocument().createDocumentFragment();
+
+ try {
+ factory.marshallQualifyingProperties(qualifyingProperties, fragment);
+ } catch (JAXBException e) {
+ log.error("Failed to marshal QualifyingProperties.", e);
+ throw new SLCommandException(4000);
+ }
+
+ List<DOMStructure> content = Collections.singletonList(new DOMStructure(fragment.getFirstChild()));
+
+ String objectIdValue = ctx.getIdValueFactory().createIdValue("Object");
+
+ XMLObject object = ctx.getSignatureFactory().newXMLObject(content, objectIdValue, null, null);
+
+ objects.add(object);
+
+ // TODO: Report MOA-SP Bug
+ //
+ // Direct referencing of the SignedPorperties Id-attribute is not supported by MOA-SP
+ // because the QualifyingProperties are parsed without the XAdES schema. Therefore,
+ // the shorthand XPointer could not be resolved.
+ //
+ // The following workaround uses an XPointer to select the SignedProperties in order
+ // to allow the signature to be verified with MOA-SP.
+
+ String referenceURI = "#xmlns(xades=http://uri.etsi.org/01903/v1.1.1%23)%20xpointer(id('"
+ + objectIdValue
+ + "')/child::xades:QualifyingProperties/child::xades:SignedProperties)";
+
+ String referenceIdValue = ctx.getIdValueFactory().createIdValue("Reference");
+ String referenceType = QualifyingPropertiesFactory.SIGNED_PROPERTIES_REFERENCE_TYPE_V1_1_1;
+
+ try {
+ dm = ctx.getAlgorithmMethodFactory().createDigestMethod(ctx);
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Failed to get DigestMethod algorithm.", e);
+ throw new SLCommandException(4006);
+ } catch (InvalidAlgorithmParameterException e) {
+ log.error("Failed to get DigestMethod algorithm.", e);
+ throw new SLCommandException(4006);
+ }
+
+ Reference reference = ctx.getSignatureFactory().newReference(referenceURI, dm, null, referenceType, referenceIdValue);
+
+ references.add(reference);
+
+ Node child = fragment.getFirstChild();
+ if (child instanceof Element) {
+ NodeList nodes = ((Element) child).getElementsByTagNameNS(QualifyingPropertiesFactory.NS_URI_V1_1_1, "SignedProperties");
+ if (nodes.getLength() > 0) {
+ IdAttribute idAttribute = new IdAttribute();
+ idAttribute.element = (Element) nodes.item(0);
+ idAttribute.namespaceURI = null;
+ idAttribute.localName = "Id";
+ idAttributes.add(idAttribute);
+ }
+ }
+
+ }
+
+ /**
+ * Parse the SignatureEnvironment.
+ *
+ * @param signatureEnvironment
+ * the <code>SignatureEnvironment</code> element
+ * @param supplements
+ * an optional list of <code>Supplements</code> (may be
+ * <code>null</code>)
+ *
+ * @return the parsed SignatureEnvironment document
+ *
+ * @throws SLCommandException
+ * if parsing the SignatureEnvironment fails
+ * @throws NullPointerException
+ * if <code>signatureEnvironment</code> is <code>null</code>
+ */
+ private Document parseSignatureEnvironment(
+ Base64XMLOptRefContentType signatureEnvironment,
+ List<DataObjectAssociationType> supplements) throws SLCommandException {
+
+ if (signatureEnvironment == null) {
+ throw new NullPointerException("Argument 'signatureEnvironment' must not be null.");
+ }
+
+ LSInput input;
+ try {
+ if (signatureEnvironment.getReference() != null) {
+ log.debug("SignatureEnvironment contains Reference " + signatureEnvironment.getReference() + ".");
+ input = createLSInput(signatureEnvironment.getReference());
+ } else if (signatureEnvironment.getBase64Content() != null) {
+ log.debug("SignatureEnvironment contains Base64Content.");
+ input = createLSInput(signatureEnvironment.getBase64Content());
+ } else if (signatureEnvironment.getXMLContent() != null) {
+ log.debug("SignatureEnvironment contains XMLContent.");
+ input = createLSInput((XMLContentType) signatureEnvironment.getXMLContent());
+ } else {
+ // the schema does not allow us to reach this point
+ throw new SLCommandException(4000);
+ }
+ } catch (IOException e) {
+ log.info("XML document in which the signature is to be integrated cannot be resolved.", e);
+ throw new SLCommandException(4100);
+ } catch (XMLStreamException e) {
+ log.info("XML document in which the signature is to be integrated cannot be resolved.", e);
+ throw new SLCommandException(4100);
+ }
+
+ LSParser parser = domImplLS.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
+ DOMConfiguration domConfig = parser.getDomConfig();
+ SimpleDOMErrorHandler errorHandler = new SimpleDOMErrorHandler();
+ domConfig.setParameter("error-handler", errorHandler);
+ LSResourceResolverAdapter resourceResolver = new LSResourceResolverAdapter(supplements);
+ domConfig.setParameter("resource-resolver", resourceResolver);
+ domConfig.setParameter("validate", Boolean.TRUE);
+
+ Document doc;
+ try {
+ doc = parser.parse(input);
+ } catch (DOMException e) {
+ log.info("XML document in which the signature is to be integrated cannot be parsed.", e);
+ throw new SLCommandException(4101);
+ } catch (LSException e) {
+ log.info("XML document in which the signature is to be integrated cannot be parsed.", e);
+ throw new SLCommandException(4101);
+ }
+
+ if (resourceResolver.getError() != null) {
+ log.info("Failed to resolve resource while parsing SignatureEnvironment document.", resourceResolver.getError());
+ // we don't stop here, as we only _try_ to parse validating
+ }
+
+ if (errorHandler.hasFatalErrors()) {
+ // log fatal errors
+ if (log.isInfoEnabled()) {
+ List<String> errorMessages = errorHandler.getErrorMessages();
+ StringBuffer sb = new StringBuffer();
+ for (String errorMessage : errorMessages) {
+ sb.append(" ");
+ sb.append(errorMessage);
+ }
+ log.info("XML document in which the signature is to be integrated cannot be parsed." + sb.toString());
+ }
+ throw new SLCommandException(4101);
+ }
+
+ // log parsed document
+ if (log.isTraceEnabled()) {
+
+ StringWriter writer = new StringWriter();
+
+ writer.write("SignatureEnvironment:\n");
+
+ LSOutput output = domImplLS.createLSOutput();
+ output.setCharacterStream(writer);
+ output.setEncoding("UTF-8");
+ LSSerializer serializer = domImplLS.createLSSerializer();
+ serializer.write(doc, output);
+
+ log.trace(writer.toString());
+ }
+
+ return doc;
+
+ }
+
+ /**
+ * Creates an LSInput from the given <code>reference</code> URI.
+ *
+ * @param reference
+ * the reference URL
+ *
+ * @return an LSInput from the given <code>reference</code> URI
+ *
+ * @throws IOException
+ * if dereferencing the given <code>reference</code> fails
+ */
+ private LSInput createLSInput(String reference) throws IOException {
+
+ URLDereferencer urlDereferencer = URLDereferencer.getInstance();
+ StreamData streamData = urlDereferencer.dereference(reference, ctx.getDereferencerContext());
+
+ String contentType = streamData.getContentType();
+ String charset = HttpUtil.getCharset(contentType, true);
+ InputStreamReader streamReader;
+ try {
+ streamReader = new InputStreamReader(streamData.getStream(), charset);
+ } catch (UnsupportedEncodingException e) {
+ log.info("Charset " + charset + " not supported. Using default.");
+ streamReader = new InputStreamReader(streamData.getStream());
+ }
+
+ LSInput input = domImplLS.createLSInput();
+ input = domImplLS.createLSInput();
+ input.setCharacterStream(streamReader);
+
+ return input;
+
+ }
+
+ /**
+ * Creates an LSInput from the given <code>content</code> bytes.
+ *
+ * @param content
+ * the content bytes
+ *
+ * @return an LSInput from the givne <code>content</code> bytes
+ */
+ private LSInput createLSInput(byte[] content) {
+
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
+ LSInput input = domImplLS.createLSInput();
+ input.setByteStream(inputStream);
+
+ return input;
+
+ }
+
+ /**
+ * Creates an LSInput from the given XML <code>content</code>.
+ *
+ * @param content
+ * the XML content
+ * @return an LSInput from the given XML <code>content</code>
+ *
+ * @throws XMLStreamException
+ * if reading the XMLStream from the given XML content fails
+ */
+ private LSInput createLSInput(XMLContentType content) throws XMLStreamException {
+
+ ByteArrayOutputStream redirectedStream = content.getRedirectedStream();
+ if (redirectedStream != null) {
+ LSInput input = domImplLS.createLSInput();
+ input.setByteStream(new ByteArrayInputStream(redirectedStream.toByteArray()));
+ return input;
+ } else {
+ return null;
+ }
+
+ }
+
+ /**
+ * Represents an <code>xsd:Id</code>-attribute value.
+ *
+ * @author mcentner
+ */
+ private class IdAttribute {
+
+ private Element element;
+
+ private String namespaceURI;
+
+ private String localName;
+
+ }
+
+ /**
+ * An implementation of the LSResourceResolver that uses a list of supplements
+ * to resolve resources.
+ *
+ * @author mcentner
+ */
+ private class LSResourceResolverAdapter implements LSResourceResolver {
+
+ List<DataObjectAssociationType> supplements;
+
+ private LSResourceResolverAdapter(
+ List<DataObjectAssociationType> supplements) {
+ this.supplements = supplements;
+ }
+
+ private Exception error;
+
+ /**
+ * @return the error
+ */
+ public Exception getError() {
+ return error;
+ }
+
+ @Override
+ public LSInput resolveResource(String type, String namespaceURI,
+ String publicId, String systemId, String baseURI) {
+
+ if (log.isTraceEnabled()) {
+ log.trace("Resolve resource :" +
+ "\n type=" + type +
+ "\n namespaceURI=" + namespaceURI +
+ "\n publicId=" + publicId +
+ "\n systemId=" + systemId +
+ "\n baseURI=" + baseURI);
+ }
+
+ if (systemId != null) {
+
+ log.debug("Resolve resource '" + systemId + "'.");
+
+ for (DataObjectAssociationType supplement : supplements) {
+
+ Base64XMLLocRefReqRefContentType content = supplement.getContent();
+ if (content != null) {
+
+ String reference = content.getReference();
+ if (systemId.equals(reference)) {
+
+ try {
+ if (content.getLocRefContent() != null) {
+ log.trace("Resolved resource '" + reference + "' to supplement with LocRefContent.");
+ return createLSInput(content.getLocRefContent());
+ } else if (content.getBase64Content() != null) {
+ log.trace("Resolved resource '" + reference + "' to supplement with Base64Content.");
+ return createLSInput(content.getBase64Content());
+ } else if (content.getXMLContent() != null) {
+ log.trace("Resolved resource '" + reference + "' to supplement with XMLContent.");
+ return createLSInput((XMLContentType) content.getXMLContent());
+ } else {
+ return null;
+ }
+ } catch (IOException e) {
+ log.info("Failed to resolve resource '" + systemId + "' to supplement.", e);
+ error = e;
+ return null;
+ } catch (XMLStreamException e) {
+ log.info("Failed to resolve resource '" + systemId + "' to supplement.", e);
+ error = e;
+ return null;
+ }
+
+ }
+
+ }
+
+ }
+
+ log.info("Failed to resolve resource '" + systemId + "' to supplement. No such supplement.");
+
+ }
+
+ return null;
+
+ }
+
+
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureContext.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureContext.java
new file mode 100644
index 00000000..0925f2fd
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureContext.java
@@ -0,0 +1,129 @@
+/*
+* 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 javax.xml.crypto.dsig.DigestMethod;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+
+import org.w3c.dom.Document;
+
+import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerContext;
+
+/**
+ * An instance of this class carries context information for a XML-Signature
+ * created by the security layer command <code>CreateXMLSignature</code>.
+ *
+ * @author mcentner
+ */
+public class SignatureContext {
+
+ /**
+ * The document going to contain the XML signature.
+ */
+ private Document document;
+
+ /**
+ * The IdValueFactory used to create <code>xsd:ID</code>-attribute values.
+ */
+ private IdValueFactory idValueFactory;
+
+ /**
+ * The XMLSignatureFactory to create XML signature objects.
+ */
+ private XMLSignatureFactory signatureFactory;
+
+ /**
+ * The URLDereferencerContext for dereferencing URLs.
+ */
+ private URLDereferencerContext dereferencerContext;
+
+ /**
+ * The DigestMethodFactory to create {@link DigestMethod} objects.
+ */
+ private AlgorithmMethodFactory digestMethodFactory;
+
+ /**
+ * @return the document
+ */
+ public Document getDocument() {
+ return document;
+ }
+
+ /**
+ * @param document the document to set
+ */
+ public void setDocument(Document document) {
+ this.document = document;
+ }
+
+ /**
+ * @return the idValueFactory
+ */
+ public IdValueFactory getIdValueFactory() {
+ return idValueFactory;
+ }
+
+ /**
+ * @param idValueFactory the idValueFactory to set
+ */
+ public void setIdValueFactory(IdValueFactory idValueFactory) {
+ this.idValueFactory = idValueFactory;
+ }
+
+ /**
+ * @return the signatureFactory
+ */
+ public XMLSignatureFactory getSignatureFactory() {
+ return signatureFactory;
+ }
+
+ /**
+ * @param signatureFactory the signatureFactory to set
+ */
+ public void setSignatureFactory(XMLSignatureFactory signatureFactory) {
+ this.signatureFactory = signatureFactory;
+ }
+
+ /**
+ * @return the dereferencerContext
+ */
+ public URLDereferencerContext getDereferencerContext() {
+ return dereferencerContext;
+ }
+
+ /**
+ * @param dereferencerContext the dereferencerContext to set
+ */
+ public void setDereferencerContext(URLDereferencerContext dereferencerContext) {
+ this.dereferencerContext = dereferencerContext;
+ }
+
+ /**
+ * @return the digestMethodFactory
+ */
+ public AlgorithmMethodFactory getAlgorithmMethodFactory() {
+ return digestMethodFactory;
+ }
+
+ /**
+ * @param digestMethodFactory the digestMethodFactory to set
+ */
+ public void setAlgorithmMethodFactory(AlgorithmMethodFactory digestMethodFactory) {
+ this.digestMethodFactory = digestMethodFactory;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureLocation.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureLocation.java
new file mode 100644
index 00000000..5ec02893
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureLocation.java
@@ -0,0 +1,235 @@
+/*
+* 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 java.util.Iterator;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import at.buergerkarte.namespaces.securitylayer._1.SignatureInfoCreationType;
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.slbinding.impl.SignatureLocationType;
+
+/**
+ * This class implements the <code>SignatureLocation</code> of an XML-Signature
+ * to be created by the security layer command <code>CreateXMLSignature</code>.
+ *
+ * @author mcentner
+ */
+public class SignatureLocation {
+
+ /**
+ * Logging facility.
+ */
+ private static Log log = LogFactory.getLog(SignatureLocation.class);
+
+ /**
+ * The SignatureContext for the XML signature
+ */
+ private SignatureContext ctx;
+
+ /**
+ * The parent node for the XML signature.
+ */
+ private Node parent;
+
+ /**
+ * The next sibling node for the XML signature.
+ */
+ private Node nextSibling;
+
+ /**
+ * Creates a new SignatureLocation with the given <code>signatureContext</code>
+ *
+ * @param signatureContext the context for the XML signature creation
+ */
+ public SignatureLocation(SignatureContext signatureContext) {
+ this.ctx = signatureContext;
+ }
+
+ /**
+ * @return the parent node for the XML signature
+ */
+ public Node getParent() {
+ return parent;
+ }
+
+ /**
+ * @param parent the parent for the XML signature
+ */
+ public void setParent(Node parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * @return the next sibling node for the XML signature
+ */
+ public Node getNextSibling() {
+ return nextSibling;
+ }
+
+ /**
+ * @param nextSibling the next sibling node for the XML signature
+ */
+ public void setNextSibling(Node nextSibling) {
+ this.nextSibling = nextSibling;
+ }
+
+ /**
+ * Configures this SignatureLocation with the information provided by the
+ * given <code>SignatureInfo</code> element.
+ *
+ * @param signatureInfo
+ * the <code>SignatureInfo</code> element
+ *
+ * @throws SLCommandException
+ * if configuring this SignatureLocation with given
+ * <code>signatureInfo</code>fails
+ */
+ public void setSignatureInfo(SignatureInfoCreationType signatureInfo)
+ throws SLCommandException {
+
+ // evaluate signature location XPath ...
+ SignatureLocationType signatureLocation = (SignatureLocationType) signatureInfo
+ .getSignatureLocation();
+
+ NamespaceContext namespaceContext = new MOAIDWorkaroundNamespaceContext(
+ signatureLocation.getNamespaceContext());
+
+ parent = evaluateSignatureLocation(signatureInfo.getSignatureLocation()
+ .getValue(), namespaceContext, ctx.getDocument().getDocumentElement());
+
+ // ... and index
+ nextSibling = findNextSibling(parent, signatureInfo.getSignatureLocation()
+ .getIndex().intValue());
+
+ }
+
+ /**
+ * Evaluates the given <code>xpath</code> with the document element as context node
+ * and returns the resulting node.
+ *
+ * @param xpath the XPath expression
+ * @param nsContext the namespace context of the XPath expression
+ * @param contextNode the context node for the XPath evaluation
+ *
+ * @return the result of evaluating the XPath expression
+ *
+ * @throws SLCommandException
+ */
+ private Node evaluateSignatureLocation(String xpath, NamespaceContext nsContext, Node contextNode) throws SLCommandException {
+
+ Node node = null;
+ try {
+ XPathFactory xpathFactory = XPathFactory.newInstance();
+ XPath xPath = xpathFactory.newXPath();
+ xPath.setNamespaceContext(nsContext);
+ XPathExpression xpathExpr = xPath.compile(xpath);
+ node = (Node) xpathExpr.evaluate(contextNode, XPathConstants.NODE);
+ } catch (XPathExpressionException e) {
+ log.info("Failed to evaluate SignatureLocation XPath expression '" + xpath + "' on context node.", e);
+ throw new SLCommandException(4102);
+ }
+
+ if (node == null) {
+ log.info("Failed to evaluate SignatureLocation XPath expression '" + xpath + "'. Result is empty.");
+ throw new SLCommandException(4102);
+ }
+
+ return node;
+
+ }
+
+ /**
+ * Finds the next sibling node of the <code>parent</code>'s <code>n</code>-th child node
+ * or <code>null</code> if there is no next sibling.
+ *
+ * @param parent the parent node
+ * @param n the index of the child node
+ *
+ * @return the next sibling node of the node specified by <code>parent</code> and index <code>n</code>,
+ * or <code>null</code> if there is no next sibling node.
+ *
+ * @throws SLCommandException if the <code>n</code>-th child of <code>parent</code> does not exist
+ */
+ private Node findNextSibling(Node parent, int n) throws SLCommandException {
+
+ NodeList childNodes = parent.getChildNodes();
+ Node childNode = childNodes.item(n);
+ if (childNode == null) {
+ log.info("SingatureLocation Index '" + n + "' not found in document.");
+ throw new SLCommandException(4102);
+ } else {
+ return childNode.getNextSibling();
+ }
+
+ }
+
+ /**
+ * Workaround for a missing namespace prefix declaration in MOA-ID.
+ *
+ * @author mcentner
+ */
+ private class MOAIDWorkaroundNamespaceContext implements NamespaceContext {
+
+ private NamespaceContext namespaceContext;
+
+ public MOAIDWorkaroundNamespaceContext(NamespaceContext namespaceContext) {
+ super();
+ this.namespaceContext = namespaceContext;
+ }
+
+ @Override
+ public String getNamespaceURI(String prefix) {
+
+ String namespaceURI = namespaceContext.getNamespaceURI(prefix);
+
+ if ((namespaceURI == null || XMLConstants.NULL_NS_URI.equals(namespaceURI)) && "saml".equals(prefix)) {
+ namespaceURI = "urn:oasis:names:tc:SAML:1.0:assertion";
+ log.debug("Namespace prefix '" + prefix + "' resolved to '" + namespaceURI + "' (MOA-ID Workaround).");
+ } else {
+ log.trace("Namespace prefix '" + prefix + "' resolved to '" + namespaceURI + "'.");
+ }
+
+ return namespaceURI;
+ }
+
+ @Override
+ public String getPrefix(String namespaceURI) {
+ return namespaceContext.getPrefix(namespaceURI);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Iterator getPrefixes(String namespaceURI) {
+ return namespaceContext.getPrefixes(namespaceURI);
+ }
+
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/SimpleDOMErrorHandler.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/SimpleDOMErrorHandler.java
new file mode 100644
index 00000000..0d54adce
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/SimpleDOMErrorHandler.java
@@ -0,0 +1,98 @@
+/*
+* 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 java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.DOMError;
+import org.w3c.dom.DOMErrorHandler;
+
+/**
+ * A simple DOMErrorHandler implementation.
+ *
+ * @author mcentner
+ */
+public class SimpleDOMErrorHandler implements DOMErrorHandler {
+
+ /**
+ * Have there been errors reported?
+ */
+ private boolean errors = false;
+
+ /**
+ * Have there been fatal error reported?
+ */
+ private boolean fatalErrors = false;
+
+ /**
+ * The list of error messages of reported errors.
+ */
+ private List<String> errorMessages = new ArrayList<String>();
+
+ /**
+ * @return <code>true</code> if errors have been reported, or <code>false</code> otherwise
+ */
+ public boolean hasErrors() {
+ return errors;
+ }
+
+ /**
+ * @return <code>true</code> if fatal errors have been reported, or <code>false</code> otherwise
+ */
+ public boolean hasFatalErrors() {
+ return fatalErrors;
+ }
+
+ /**
+ * @return a list of error messages that have been reported
+ */
+ public List<String> getErrorMessages() {
+ return errorMessages;
+ }
+
+ /* (non-Javadoc)
+ * @see org.w3c.dom.DOMErrorHandler#handleError(org.w3c.dom.DOMError)
+ */
+ @Override
+ public boolean handleError(DOMError error) {
+
+ switch (error.getSeverity()) {
+
+ case DOMError.SEVERITY_WARNING :
+// log.debug("[warning] " + error.getMessage());
+ return true;
+
+ case DOMError.SEVERITY_ERROR :
+// log.debug("[error] " + error.getMessage());
+ errorMessages.add(error.getMessage());
+ errors = true;
+ return false;
+
+ case DOMError.SEVERITY_FATAL_ERROR :
+// log.debug("[fatal error] " + error.getMessage());
+ errorMessages.add(error.getMessage());
+ fatalErrors = true;
+ return false;
+
+ default:
+ return false;
+ }
+
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/URIDereferncerAdapter.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/URIDereferncerAdapter.java
new file mode 100644
index 00000000..c94937be
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/URIDereferncerAdapter.java
@@ -0,0 +1,103 @@
+/*
+* 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.utils.URIDereferencerImpl;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.xml.crypto.Data;
+import javax.xml.crypto.OctetStreamData;
+import javax.xml.crypto.URIDereferencer;
+import javax.xml.crypto.URIReference;
+import javax.xml.crypto.URIReferenceException;
+import javax.xml.crypto.XMLCryptoContext;
+
+import at.gv.egiz.bku.utils.urldereferencer.StreamData;
+import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer;
+import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerContext;
+
+/**
+ * An URIDereferencer implementation that uses an {@link URLDereferencer} to
+ * dereference.
+ *
+ * @author mcentner
+ */
+public class URIDereferncerAdapter implements URIDereferencer {
+
+ /**
+ * The context for dereferencing.
+ */
+ protected URLDereferencerContext urlDereferencerContext;
+
+ /**
+ * Creates a new URIDereferencerAdapter instance with the given
+ * <code>urlDereferencerContext</code>.
+ *
+ * @param urlDereferencerContext the context to be used for dereferencing
+ */
+ public URIDereferncerAdapter(URLDereferencerContext urlDereferencerContext) {
+ super();
+ this.urlDereferencerContext = urlDereferencerContext;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.xml.crypto.URIDereferencer#dereference(javax.xml.crypto.URIReference, javax.xml.crypto.XMLCryptoContext)
+ */
+ @Override
+ public Data dereference(URIReference uriReference, XMLCryptoContext context)
+ throws URIReferenceException {
+
+ String uriString = uriReference.getURI();
+ if (uriString == null) {
+ return null;
+ }
+
+ URI uri;
+ try {
+ uri = new URI(uriString);
+ } catch (URISyntaxException e) {
+ throw new URIReferenceException(e.getMessage(), e);
+ }
+
+ if (uri.isAbsolute()) {
+
+ URLDereferencer dereferencer = URLDereferencer.getInstance();
+ StreamData streamData;
+ try {
+ streamData = dereferencer.dereference(uriString, urlDereferencerContext);
+ } catch (IOException e) {
+ throw new URIReferenceException(e.getMessage(), e);
+ }
+ return new OctetStreamData(streamData.getStream(), uriString, streamData.getContentType());
+
+ } else {
+
+ URIDereferencer uriDereferencer = context.getURIDereferencer();
+ if (uriDereferencer == null || uriDereferencer == this) {
+ uriDereferencer = new URIDereferencerImpl();
+ }
+
+ return uriDereferencer.dereference(uriReference, context);
+
+ }
+
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/XSECTReference.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/XSECTReference.java
new file mode 100644
index 00000000..6b388f2a
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/XSECTReference.java
@@ -0,0 +1,112 @@
+/*
+* 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.dsig.DigestMethodImpl;
+import iaik.xml.crypto.dsig.DigestValueImpl;
+import iaik.xml.crypto.dsig.ReferenceImpl;
+import iaik.xml.crypto.dsig.TransformImpl;
+import iaik.xml.crypto.dsig.TransformsImpl;
+
+import javax.xml.crypto.Data;
+import javax.xml.crypto.URIDereferencer;
+import javax.xml.crypto.URIReferenceException;
+import javax.xml.crypto.XMLCryptoContext;
+import javax.xml.crypto.dsig.DigestMethod;
+import javax.xml.crypto.dsig.TransformException;
+
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.bku.slexceptions.SLExceptionMessages;
+
+/**
+ * This class extends the XSECT ReferenceImpl to allow for the use
+ * of already marshalled <code>ds:Transforms</code> elements for initialization.
+ *
+ * @author mcentner
+ */
+public class XSECTReference extends ReferenceImpl {
+
+ /**
+ * The URIDereferencer to be used for dereferencing.
+ */
+ protected URIDereferencer dereferencer;
+
+ /**
+ * Creates a new instance of this XSECTReference with the given
+ * <code>uri</code>, digest method, <code>transforms</code>, <code>type</code>
+ * and <code>id</code> value.
+ *
+ * @param uri
+ * the <code>URI</code>-attribute value (may be <code>null</code>)
+ * @param dm
+ * the digest method
+ * @param transforms
+ * a TransformsImpl element (may be <code>null</code>)
+ * @param type
+ * the <code>Type</code>-attribute value (may be <code>null</code>)
+ * @param id
+ * the <code>Id</code>-attribute value (may be <code>null</code>)
+ *
+ * @throws NullPointerException
+ * if <code>digestMethod</code> is <code>null</code>
+ * @throws IllegalArgumentException
+ * if <code>uri</code> is not RFC 2396 compliant
+ * @throws ClassCastException
+ * if any of the <code>transforms</code> is not of type
+ * {@link TransformImpl}
+ */
+ public XSECTReference(String uri, DigestMethod dm, TransformsImpl transforms, String type,
+ String id) {
+ super(uri, transforms, type, id);
+ digestMethod_ = (DigestMethodImpl) dm;
+ digestValue_ = new DigestValueImpl();
+ }
+
+ /* (non-Javadoc)
+ * @see iaik.xml.crypto.dsig.ReferenceType#dereference(javax.xml.crypto.XMLCryptoContext)
+ */
+ @Override
+ public Data dereference(XMLCryptoContext context) throws TransformException,
+ URIReferenceException {
+ if (dereferencer != null) {
+ return dereferencer.dereference(this, context);
+ } else {
+ try {
+ return super.dereference(context);
+ } catch (URIReferenceException e) {
+ SLCommandException commandException = new SLCommandException(4003,
+ SLExceptionMessages.EC4003_NOT_RESOLVED, new Object[] { getURI() });
+ throw new URIReferenceException("Failed to dereference data to-be signed.", commandException);
+ }
+ }
+ }
+
+ /**
+ * @return the dereferencer to be used for dereferencing this reference
+ */
+ public URIDereferencer getDereferencer() {
+ return dereferencer;
+ }
+
+ /**
+ * @param dereferencer the dereferencer to be used for dereferencing this reference
+ */
+ public void setDereferencer(URIDereferencer dereferencer) {
+ this.dereferencer = dereferencer;
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/XSECTTransforms.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/XSECTTransforms.java
new file mode 100644
index 00000000..a98e4236
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/XSECTTransforms.java
@@ -0,0 +1,124 @@
+/*
+* 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.dsig.TransformImpl;
+import iaik.xml.crypto.dsig.TransformsImpl;
+
+import java.util.List;
+
+import javax.xml.crypto.MarshalException;
+import javax.xml.crypto.dom.DOMCryptoContext;
+import javax.xml.crypto.dsig.Transform;
+
+import org.w3c.dom.Node;
+
+/**
+ * This class extends the XSECT TransformsImpl to allow for the use of an
+ * unmarshalled <code>ds:Transforms</code> element for initalization.
+ *
+ * @author mcentner
+ */
+public class XSECTTransforms extends TransformsImpl {
+
+ /**
+ * Creates a new XSECTTransforms with the given list of <code>transforms</code>.
+ *
+ * @param transforms a list of {@link TransformImpl}s
+ * @see TransformsImpl#TransformsImpl(List)
+ */
+ @SuppressWarnings("unchecked")
+ public XSECTTransforms(List transforms) {
+ super(transforms);
+ }
+
+ /**
+ * Creates a new XSECTTransforms and initializes it from the given
+ * <code>ds:Transforms</code> node.
+ *
+ * @param context the context used for unmarshalling
+ * @param node the <code>ds:Transforms</code> node
+ *
+ * @throws MarshalException if unmarshalling the <code>ds:Transforms</code> fails
+ */
+ public XSECTTransforms(DOMCryptoContext context, Node node)
+ throws MarshalException {
+ super(context, node);
+ }
+
+ /**
+ * Inserts the given <code>transform</code> at the top of the
+ * transform list.
+ *
+ * @param transform the <code>ds:Transform</code> to instert
+ */
+ @SuppressWarnings("unchecked")
+ public void insertTransform(Transform transform) {
+ if (transform == null) {
+ throw new NullPointerException("Parameter 'transform' must not be null.");
+ }
+ if (!(transform instanceof TransformImpl)) {
+ throw new ClassCastException("Transform 'transform' must be of type '" + TransformImpl.class.getName() + "'.");
+ }
+ transforms_.add(0, transform);
+ }
+
+ /**
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ private List<TransformImpl> getTransformImpls() {
+ return transforms_;
+ }
+
+ /* (non-Javadoc)
+ * @see iaik.xml.crypto.dsig.TransformsType#marshal(javax.xml.crypto.dom.DOMCryptoContext, org.w3c.dom.Node, org.w3c.dom.Node)
+ */
+ @Override
+ public Node marshal(DOMCryptoContext context, Node parent, Node nextSibling)
+ throws MarshalException {
+
+ if (getNode() != null) {
+ // If this TransformsImpl has been unmarshalled from exiting nodes,
+ // we don't want to re-marshal ...
+ state_ = STATE_MARSHALED;
+
+ // ... but append the existing node to the parent ...
+ Node transformsNode = parent.insertBefore(getNode(), nextSibling);
+
+ // ... and marshal any Transforms not yet marshalled (e.g. that
+ // have been added via insertTransform().
+ Node transformNextSibling = transformsNode.getFirstChild();
+ List<TransformImpl> transforms = getTransformImpls();
+ for (int i = 0; i < transforms.size(); i++) {
+ TransformImpl transform = transforms.get(i);
+ Node transformNode = transform.getNode();
+ if (transformNode == null) {
+ // marshall TransformImpl
+ transformNode = transform.marshal(context, transformsNode, transformNextSibling);
+ }
+ transformNextSibling = transformNode.getNextSibling();
+ }
+
+ return transformsNode;
+ } else {
+ return super.marshal(context, parent, nextSibling);
+ }
+
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLBindingException.java b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLBindingException.java
new file mode 100644
index 00000000..3f1732ba
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLBindingException.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.bku.slexceptions;
+
+/**
+ * Error in the binding to the transport protocol (2xxx)
+ */
+public class SLBindingException extends SLException {
+
+ public SLBindingException(int errorCode) {
+ super(errorCode);
+ }
+
+ public SLBindingException(int errorCode, String msg, Object[] args) {
+ super(errorCode, msg, args);
+ }
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLCanceledException.java b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLCanceledException.java
new file mode 100644
index 00000000..8136a093
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLCanceledException.java
@@ -0,0 +1,26 @@
+/*
+* 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.slexceptions;
+
+public class SLCanceledException extends
+ at.gv.egiz.bku.slexceptions.SLException {
+
+ public SLCanceledException(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/slexceptions/SLCommandException.java b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLCommandException.java
new file mode 100644
index 00000000..73ae3325
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLCommandException.java
@@ -0,0 +1,30 @@
+/*
+* 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.slexceptions;
+
+public class SLCommandException extends at.gv.egiz.bku.slexceptions.SLException {
+
+ private static final long serialVersionUID = 1L;
+
+ public SLCommandException(int errorCode) {
+ super(errorCode);
+ }
+
+ public SLCommandException(int errorCode, String msg, Object[] args) {
+ super(errorCode, msg, args);
+ }
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLException.java b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLException.java
new file mode 100644
index 00000000..4b541deb
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLException.java
@@ -0,0 +1,88 @@
+/*
+* 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.slexceptions;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class SLException extends Exception {
+
+ private static String RESOURCE_BUNDLE_BASE_NAME = "at.gv.egiz.bku.slexceptions.SLExceptionMessages";
+
+ private static String MISSING_RESOURCE_PATTERN = "MISSING RESOURCE FOR ERROR MESSAGE: {0} ({1})";
+
+ private static String ILLEGAL_ARGUMENT_MESSAGE = "MESSAGE FORMAT FAILED";
+
+ private static final long serialVersionUID = 1L;
+
+ private int errorCode;
+
+ private String message;
+
+ private Object[] arguments;
+
+ public SLException(int errorCode) {
+ this.errorCode = errorCode;
+ this.message = SLExceptionMessages.STANDARD_PREFIX + Integer.toString(errorCode);
+ }
+
+ public SLException(int errorCode, String message, Object[] arguments) {
+ this.errorCode = errorCode;
+ this.message = message;
+ this.arguments = arguments;
+ }
+
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+ public String getDetailedMsg() {
+ return getLocalizedMessage();
+ }
+
+ @Override
+ public String getLocalizedMessage() {
+ return getLocalizedMessage(Locale.getDefault());
+ }
+
+ public String getLocalizedMessage(Locale locale) {
+
+ String pattern;
+ Object[] arguments = this.arguments;
+ try {
+ ResourceBundle bundle = ResourceBundle.getBundle(RESOURCE_BUNDLE_BASE_NAME, locale);
+ pattern = bundle.getString(message);
+ } catch (MissingResourceException e) {
+ pattern = MISSING_RESOURCE_PATTERN;
+ arguments = new Object[]{message, e.getMessage()};
+ }
+
+ String localizedMessage;
+ try {
+ localizedMessage = MessageFormat.format(pattern, arguments);
+ } catch (IllegalArgumentException e) {
+ localizedMessage = ILLEGAL_ARGUMENT_MESSAGE + ": " + pattern;
+ }
+
+ return localizedMessage;
+
+ }
+
+
+} \ No newline at end of file
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
new file mode 100644
index 00000000..73ac8d1b
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLExceptionMessages.java
@@ -0,0 +1,56 @@
+/*
+* 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.slexceptions;
+
+public final class SLExceptionMessages {
+
+ private SLExceptionMessages() {
+ }
+
+ public static final String STANDARD_PREFIX = "ec";
+
+ //
+ // 3xxx
+ //
+ // Error in the XML structure of the command request
+
+ public static final String EC3000_UNCLASSIFIED = "ec3000.unclassified";
+
+ public static final String EC3002_INVALID = "ec3002.invalid";
+
+ //
+ // 4xxx
+ //
+ // Error during command execution
+
+ public static final String EC4000_UNCLASSIFIED_INFOBOX_INVALID = "ec4000.infobox.invalid";
+
+ public static final String EC4000_UNCLASSIFIED_IDLINK_TRANSFORMATION_FAILED = "ec4000.idlink.transfomation.failed";
+
+ public static final String EC4002_INFOBOX_UNKNOWN = "ec4002.infobox.unknown";
+
+ public static final String EC4003_NOT_RESOLVED = "ec4003.not.resolved";
+
+ 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/SLRequestException.java b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLRequestException.java
new file mode 100644
index 00000000..548732e6
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLRequestException.java
@@ -0,0 +1,30 @@
+/*
+* 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.slexceptions;
+
+public class SLRequestException extends SLException {
+
+ public SLRequestException(int errorCode) {
+ super(errorCode);
+ // TODO Auto-generated constructor stub
+ }
+
+ public SLRequestException(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/slexceptions/SLRuntimeException.java b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLRuntimeException.java
new file mode 100644
index 00000000..d09ca418
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLRuntimeException.java
@@ -0,0 +1,37 @@
+/*
+* 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.slexceptions;
+
+public class SLRuntimeException extends RuntimeException {
+
+ public SLRuntimeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public SLRuntimeException(String message) {
+ super(message);
+ }
+
+ public SLRuntimeException(Throwable cause) {
+ super(cause);
+ }
+
+ public SLRuntimeException() {
+ }
+
+
+}
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/java/at/gv/egiz/bku/slexceptions/SLViewerException.java b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLViewerException.java
new file mode 100644
index 00000000..853328d5
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slexceptions/SLViewerException.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.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);
+ }
+} \ No newline at end of file
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/viewer/ResourceFontLoader.java b/bkucommon/src/main/java/at/gv/egiz/bku/viewer/ResourceFontLoader.java
new file mode 100644
index 00000000..8cab581d
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/viewer/ResourceFontLoader.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.viewer;
+
+import at.gv.egiz.bku.gui.viewer.FontProviderException;
+import at.gv.egiz.bku.gui.viewer.FontProvider;
+import java.awt.Font;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Loads font(s) as classpath resource.
+ * Loaded fonts are shared within all instances in this VM (classloader)
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class ResourceFontLoader implements FontProvider {
+
+ public static final String FONT_RESOURCE = "DejaVuLGCSansMono.ttf";
+
+ protected final static Log log = LogFactory.getLog(ResourceFontLoader.class);
+
+ /** TextValidator and (local) SecureViewerDialog (see LocalStalFactory) use ResourceFontLoader, load resource only once */
+ protected static Font font;
+
+ /**
+ *
+ * @return
+ * @throws FontProviderException encapsulating FontFormatException (if resource doesn't contain the plain format)
+ * or IOException (if resource cannot be retrieved)
+ */
+ @Override
+ public Font getFont() throws FontProviderException {
+ if (font == null) {
+ try {
+ if (log.isDebugEnabled()) {
+ log.debug("loading " + getClass().getClassLoader().getResource(FONT_RESOURCE));
+ }
+ font = Font.createFont(Font.PLAIN, getClass().getClassLoader().getResourceAsStream(FONT_RESOURCE));
+ } catch (Exception ex) {
+ log.error("failed to load font", ex);
+ throw new FontProviderException("failed to load font", ex);
+ }
+ }
+ log.trace("font resource loaded");
+ return font;
+ }
+}
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..ad9bf6bb
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/viewer/ValidatorFactory.java
@@ -0,0 +1,178 @@
+/*
+* 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.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+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> VALIDATOR_CLASS = Validator.class;
+
+ private static final String SERVICE_ID = "META-INF/services/" + VALIDATOR_CLASS.getName();
+
+ /**
+ * Creates a new Validator for the given <code>mimeType</code>.
+ *
+ * @param mimeType
+ *
+ * @return
+ *
+ * @throws IllegalArgumentException
+ * if no Validator for the <code>mimeType</code> 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 <code>null</code>
+ */
+ 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<URL> 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;
+
+ }
+
+ /**
+ *
+ * @throws InvocationTargetException if className's (nullary) constructor throws exception
+ */
+ private Validator createValidatorInstance(String className)
+ throws ClassNotFoundException, InstantiationException,
+ IllegalAccessException, NoSuchMethodException, InvocationTargetException {
+
+ try {
+ Constructor<?> implConstructor = classLoader.loadClass(className).getConstructor((Class[])null);
+ return (Validator) implConstructor.newInstance((Object[])null);
+ } catch (InvocationTargetException ex) {
+ //ex from constructor
+ log.error("Failed to initialize validator class '" + className + "': " + ex.getCause().getMessage(), ex.getCause());
+ throw ex;
+ } catch (NoSuchMethodException ex) {
+ log.error("Validator class '" + className + "' has no nullary constructor", ex);
+ throw ex;
+ } 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<URL> createServiceIterator() {
+
+ try {
+ final Enumeration<URL> resources = classLoader.getResources(SERVICE_ID);
+ return new Iterator<URL> () {
+
+ @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<URL> list = Collections.emptyList();
+ return list.iterator();
+ }
+
+ }
+
+}