summaryrefslogtreecommitdiff
path: root/BKUApplet/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'BKUApplet/src/main/java')
-rw-r--r--BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java224
-rw-r--r--BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java237
-rw-r--r--BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/BKUApplet.java359
-rw-r--r--BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/InternalSSLSocketFactory.java157
-rw-r--r--BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/viewer/URLFontLoader.java82
5 files changed, 1059 insertions, 0 deletions
diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java
new file mode 100644
index 00000000..d5f8dd69
--- /dev/null
+++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java
@@ -0,0 +1,224 @@
+/*
+ * 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.online.applet;
+
+import at.gv.egiz.bku.smccstal.AbstractBKUWorker;
+import at.gv.egiz.bku.gui.BKUGUIFacade;
+import at.gv.egiz.bku.smccstal.SignRequestHandler;
+import at.gv.egiz.stal.STALRequest;
+import at.gv.egiz.stal.STALResponse;
+import at.gv.egiz.stal.SignRequest;
+import at.gv.egiz.stal.service.STALPortType;
+import at.gv.egiz.stal.service.translator.STALTranslator;
+import at.gv.egiz.stal.service.translator.TranslationException;
+import at.gv.egiz.stal.service.types.ErrorResponseType;
+import at.gv.egiz.stal.service.types.GetNextRequestResponseType;
+import at.gv.egiz.stal.service.types.GetNextRequestType;
+import at.gv.egiz.stal.service.types.ObjectFactory;
+import at.gv.egiz.stal.service.types.RequestType;
+import at.gv.egiz.stal.service.types.ResponseType;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.JAXBElement;
+import javax.xml.ws.WebServiceException;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class AppletBKUWorker extends AbstractBKUWorker implements Runnable {
+
+ protected BKUApplet applet;
+ protected String sessionId;
+
+ private ObjectFactory stalObjFactory = new ObjectFactory();
+
+ public AppletBKUWorker(BKUApplet applet, BKUGUIFacade gui) {
+ super(gui);
+ this.applet = applet;
+
+ sessionId = applet.getParameter(BKUApplet.SESSION_ID);
+ if (sessionId == null) {
+ sessionId = "TestSession";
+ log.warn("using dummy sessionId " + sessionId);
+ }
+ }
+
+ @Override
+ public void run() {
+ gui.showMessageDialog(BKUGUIFacade.TITLE_WELCOME,
+ BKUGUIFacade.MESSAGE_WELCOME);
+
+ try {
+ STALPortType stalPort = applet.getSTALPort();
+ STALTranslator stalTranslator = applet.getSTALTranslator();
+
+ AppletSecureViewer secureViewer =
+ new AppletSecureViewer(gui, stalPort, sessionId);
+ addRequestHandler(SignRequest.class,
+ new SignRequestHandler(secureViewer));
+
+ GetNextRequestResponseType nextRequestResp = stalPort.connect(sessionId);
+
+ do {
+ List<JAXBElement<? extends RequestType>> requests;
+ List<JAXBElement<? extends ResponseType>> responses = new ArrayList<JAXBElement<? extends ResponseType>>();
+
+ try {
+ requests = nextRequestResp.getInfoboxReadRequestOrSignRequestOrQuitRequest();
+ responses.clear();
+
+ // (rather use validator)
+ if (requests.size() == 0) {
+ log.error("Received empty NextRequestResponse: no STAL requests to handle. (STAL-X requests might not have gotten unmarshalled)");
+ throw new RuntimeException("No STAL requests to handle.");
+ }
+
+ if (log.isInfoEnabled()) {
+ StringBuilder sb = new StringBuilder("Received ");
+ sb.append(requests.size());
+ sb.append(" requests: ");
+ for (JAXBElement<? extends RequestType> r : requests) {
+ sb.append(r.getValue().getClass());
+ sb.append(' ');
+ }
+ log.info(sb.toString());
+ }
+
+ List<STALRequest> stalRequests = new ArrayList<STALRequest>();
+ for (JAXBElement<? extends RequestType> req : requests) {
+ try {
+ stalRequests.add(stalTranslator.translate(req));
+ } catch (TranslationException ex) {
+ log.error("Received unknown request from server STAL: " + ex.getMessage());
+ throw new RuntimeException(ex);
+ }
+ }
+
+ checkPermission(stalRequests);
+
+ List<STALResponse> stalResponses = handleRequest(stalRequests);
+ for (STALResponse stalResponse : stalResponses) {
+ try {
+ responses.add(stalTranslator.translate(stalResponse));
+ } catch (TranslationException ex) {
+ log.error("Received unknown response from STAL: " + ex.getMessage());
+ throw new RuntimeException(ex);
+ }
+ }
+
+ } catch (RuntimeException ex) {
+ // return ErrorResponse to server, which displays error page
+ log.error(ex.getMessage());
+ ErrorResponseType err = stalObjFactory.createErrorResponseType();
+ if (ex instanceof SecurityException) {
+ err.setErrorCode(6002);
+ } else {
+ Throwable cause = ex.getCause();
+ if (cause != null && cause instanceof InterruptedException) {
+ log.info("do not return error response, client might want to resume session");
+ finished = true;
+ }
+ err.setErrorCode(4000);
+ }
+ responses.clear();
+ responses.add(stalObjFactory.createGetNextRequestTypeErrorResponse(err));
+
+ } finally {
+ if (!finished) {
+ if (log.isInfoEnabled()) {
+ StringBuilder sb = new StringBuilder("Sending ");
+ sb.append(responses.size());
+ sb.append(" responses: ");
+ for (JAXBElement<? extends ResponseType> r : responses) {
+ sb.append(r.getValue().getClass());
+ sb.append(' ');
+ }
+ log.info(sb.toString());
+ }
+ GetNextRequestType nextRequest = stalObjFactory.createGetNextRequestType();
+ nextRequest.setSessionId(sessionId);
+ nextRequest.getInfoboxReadResponseOrSignResponseOrErrorResponse().addAll(responses);
+ nextRequestResp = stalPort.getNextRequest(nextRequest);
+ }
+ }
+
+
+ } while (!finished);
+ log.info("Finished " + Thread.currentThread().getName());
+
+ } catch (WebServiceException ex) {
+ log.fatal("communication error with server STAL: " + ex.getMessage(), ex);
+ showErrorDialog(BKUGUIFacade.ERR_SERVICE_UNREACHABLE, ex);
+ } catch (MalformedURLException ex) {
+ log.fatal(ex.getMessage(), ex);
+ showErrorDialog(BKUGUIFacade.ERR_CONFIG, ex);
+ } catch (Exception ex) {
+ log.error(ex.getMessage(), ex);
+ showErrorDialog(BKUGUIFacade.ERR_UNKNOWN_WITH_PARAM, ex);
+ } finally {
+ if (signatureCard != null) {
+ signatureCard.disconnect(false);
+ }
+ }
+
+ applet.sendRedirect(sessionId);
+ }
+
+ /**
+ * throws RuntimeException if requests contain InfoboxReadRequest for IdentityLink
+ * and STAL Service Endpoint is no e-Gov agency
+ * @param stalRequests
+ */
+ private void checkPermission(List<STALRequest> stalRequests) {
+ for (STALRequest request : stalRequests) {
+ if (request instanceof at.gv.egiz.stal.InfoboxReadRequest) {
+ at.gv.egiz.stal.InfoboxReadRequest r = (at.gv.egiz.stal.InfoboxReadRequest) request;
+ String infoboxId = r.getInfoboxIdentifier();
+ String domainId = r.getDomainIdentifier();
+ if ("IdentityLink".equals(infoboxId) && domainId == null) {
+ if (!InternalSSLSocketFactory.getInstance().isEgovAgency()) {
+ throw new SecurityException("Insufficient rights to execute command InfoboxReadRequest for Infobox IdentityLink");
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ * @param err_code
+ * @param ex if not null, the message will be appended as parameter to the error message
+ */
+ protected void showErrorDialog(String err_code, Exception ex) {
+ actionCommandList.clear();
+ actionCommandList.add("ok");
+ Object[] params = (ex != null) ? new Object[] { ex.getMessage() } : null;
+ gui.showErrorDialog(err_code, params, this, "ok");
+ try {
+ waitForAction();
+ } catch (InterruptedException e) {
+ log.error(e);
+ }
+ }
+
+ public void getFocusFromBrowser() {
+
+ gui.getFocusFromBrowser();
+ }
+}
diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java
new file mode 100644
index 00000000..c67699af
--- /dev/null
+++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java
@@ -0,0 +1,237 @@
+/*
+ * 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.online.applet;
+
+import at.gv.egiz.bku.gui.BKUGUIFacade;
+import at.gv.egiz.bku.smccstal.SecureViewer;
+import at.gv.egiz.stal.HashDataInput;
+import at.gv.egiz.stal.impl.ByteArrayHashDataInput;
+import at.gv.egiz.stal.service.GetHashDataInputFault;
+import at.gv.egiz.stal.service.STALPortType;
+import at.gv.egiz.stal.service.types.GetHashDataInputResponseType;
+import at.gv.egiz.stal.service.types.GetHashDataInputType;
+import at.gv.egiz.stal.signedinfo.ReferenceType;
+import at.gv.egiz.stal.signedinfo.SignedInfoType;
+import java.awt.event.ActionListener;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+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 AppletSecureViewer implements SecureViewer {
+
+ private static final Log log = LogFactory.getLog(AppletSecureViewer.class);
+
+ protected BKUGUIFacade gui;
+ protected STALPortType stalPort;
+ protected String sessId;
+ protected List<HashDataInput> verifiedDataToBeSigned;
+
+ public AppletSecureViewer(BKUGUIFacade gui, STALPortType stalPort,
+ String sessId) {
+ if (gui == null) {
+ throw new NullPointerException("GUI must not be null");
+ }
+ if (stalPort == null) {
+ throw new NullPointerException("STAL port must not be null");
+ }
+ if (sessId == null) {
+ throw new NullPointerException("session id must not be null");
+ }
+ this.gui = gui;
+ this.stalPort = stalPort;
+ this.sessId = sessId;
+ }
+
+ /**
+ * retrieves the data to be signed for
+ * @param signedReferences
+ * @param okListener
+ * @param okCommand
+ * @param cancelListener
+ * @param cancelCommand
+ * @throws java.security.DigestException
+ * @throws java.lang.Exception
+ */
+ @Override
+ public void displayDataToBeSigned(SignedInfoType signedInfo,
+ ActionListener okListener, String okCommand)
+ throws DigestException, Exception {
+
+ if (verifiedDataToBeSigned == null) {
+ log.info("retrieve data to be signed for dsig:SignedInfo " +
+ signedInfo.getId());
+ List<GetHashDataInputResponseType.Reference> hdi =
+ getHashDataInput(signedInfo.getReference());
+ verifiedDataToBeSigned = verifyHashDataInput(signedInfo.getReference(),
+ hdi);
+ }
+ if (verifiedDataToBeSigned.size() > 0) {
+ gui.showSecureViewer(verifiedDataToBeSigned, okListener, okCommand);
+ } else {
+ throw new Exception("No data to be signed (apart from any QualifyingProperties or a Manifest)");
+ }
+ }
+
+ /**
+ * Get all hashdata inputs that contain an ID attribute but no Type attribute.
+ * @param signedReferences
+ * @return
+ * @throws at.gv.egiz.stal.service.GetHashDataInputFault
+ */
+ private List<GetHashDataInputResponseType.Reference> getHashDataInput(List<ReferenceType> signedReferences)
+ throws GetHashDataInputFault, Exception {
+ GetHashDataInputType request = new GetHashDataInputType();
+ request.setSessionId(sessId);
+
+// HashMap<String, ReferenceType> idSignedRefMap = new HashMap<String, ReferenceType>();
+ for (ReferenceType signedRef : signedReferences) {
+ //don't get Manifest, QualifyingProperties, ...
+ if (signedRef.getType() == null) {
+ String signedRefId = signedRef.getId();
+ if (signedRefId != null) {
+ if (log.isTraceEnabled()) {
+ log.trace("requesting hashdata input for reference " + signedRefId);
+ }
+// idSignedRefMap.put(signedRefId, signedRef);
+ GetHashDataInputType.Reference ref = new GetHashDataInputType.Reference();
+ ref.setID(signedRefId);
+ request.getReference().add(ref);
+
+ } else {
+ throw new Exception("Cannot resolve signature data for dsig:Reference without Id attribute");
+ }
+ }
+ }
+
+ if (request.getReference().size() < 1) {
+ log.error("No signature data (apart from any QualifyingProperties or a Manifest) for session " + sessId);
+ throw new Exception("No signature data (apart from any QualifyingProperties or a Manifest)");
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("WebService call GetHashDataInput for " + request.getReference().size() + " references in session " + sessId);
+ }
+ GetHashDataInputResponseType response = stalPort.getHashDataInput(request);
+ return response.getReference();
+ }
+
+ /**
+ * Verifies all signed references and returns STAL HashDataInputs
+ * @param signedReferences
+ * @param hashDataInputs
+ * @return
+ * @throws java.security.DigestException
+ * @throws java.security.NoSuchAlgorithmException
+ * @throws Exception if no hashdata input is provided for a signed reference
+ */
+ private List<HashDataInput> verifyHashDataInput(List<ReferenceType> signedReferences, List<GetHashDataInputResponseType.Reference> hashDataInputs)
+ throws DigestException, NoSuchAlgorithmException, Exception {
+
+ ArrayList<HashDataInput> verifiedHashDataInputs = new ArrayList<HashDataInput>();
+
+ for (ReferenceType signedRef : signedReferences) {
+ if (signedRef.getType() == null) {
+ log.info("Verifying digest for signed reference " + signedRef.getId());
+
+ String signedRefId = signedRef.getId();
+ byte[] signedDigest = signedRef.getDigestValue();
+ String signedDigestAlg = null;
+ if (signedRef.getDigestMethod() != null) {
+ signedDigestAlg = signedRef.getDigestMethod().getAlgorithm();
+ } else {
+ throw new NoSuchAlgorithmException("Failed to verify digest value for reference " + signedRefId + ": no digest algorithm");
+ }
+
+ // usually, there is just one item here
+ GetHashDataInputResponseType.Reference hashDataInput = null;
+ for (GetHashDataInputResponseType.Reference hdi : hashDataInputs) {
+ if (signedRefId.equals(hdi.getID())) {
+ hashDataInput = hdi;
+ break;
+ }
+ }
+ if (hashDataInput == null) {
+ throw new Exception("No hashdata input for reference " + signedRefId + " returned by service");
+ }
+
+ byte[] hdi = hashDataInput.getValue();
+ String mimeType = hashDataInput.getMimeType();
+ String encoding = hashDataInput.getEncoding();
+ String filename = hashDataInput.getFilename();
+
+ if (hdi == null) {
+ throw new Exception("No hashdata input for reference " + signedRefId + " provided by service");
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("Digesting reference " + signedRefId + " (" + mimeType + ";" + encoding + ")");
+ }
+
+ byte[] hashDataInputDigest = digest(hdi, signedDigestAlg);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Comparing digest to claimed digest value for reference " + signedRefId);
+ }
+// log.warn("***************** DISABLED HASHDATA VERIFICATION");
+ if (!Arrays.equals(hashDataInputDigest, signedDigest)) {
+ log.error("Bad digest value for reference " + signedRefId);
+ throw new DigestException("Bad digest value for reference " + signedRefId);
+ }
+
+ verifiedHashDataInputs.add(new ByteArrayHashDataInput(hdi, signedRefId, mimeType, encoding, filename));
+ }
+ }
+
+ return verifiedHashDataInputs;
+ }
+
+ //TODO
+ private byte[] digest(byte[] hashDataInput, String mdAlg) throws NoSuchAlgorithmException {
+ if ("http://www.w3.org/2000/09/xmldsig#sha1".equals(mdAlg)) {
+ mdAlg = "SHA-1";
+ } else if ("http://www.w3.org/2001/04/xmlenc#sha256".equals(mdAlg)) {
+ mdAlg = "SHA-256";
+ } else if ("http://www.w3.org/2001/04/xmlenc#sha224".equals(mdAlg)) {
+ mdAlg = "SHA-224";
+ } else if ("http://www.w3.org/2001/04/xmldsig-more#sha224".equals(mdAlg)) {
+ mdAlg = "SHA-224";
+ } else if ("http://www.w3.org/2001/04/xmldsig-more#sha384".equals(mdAlg)) {
+ mdAlg = "SHA-384";
+ } else if ("http://www.w3.org/2001/04/xmlenc#sha512".equals(mdAlg)) {
+ mdAlg = "SHA-512";
+ } else if ("http://www.w3.org/2001/04/xmldsig-more#md2".equals(mdAlg)) {
+ mdAlg = "MD2";
+ } else if ("http://www.w3.org/2001/04/xmldsig-more#md5".equals(mdAlg)) {
+ mdAlg = "MD5";
+ } else if ("http://www.w3.org/2001/04/xmlenc#ripemd160".equals(mdAlg)) {
+ mdAlg = "RipeMD-160";
+ } else {
+ throw new NoSuchAlgorithmException("Failed to verify digest value: unsupported digest algorithm " + mdAlg);
+ }
+
+ MessageDigest md = MessageDigest.getInstance(mdAlg);
+ return md.digest(hashDataInput);
+ }
+}
diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/BKUApplet.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/BKUApplet.java
new file mode 100644
index 00000000..2fa4889a
--- /dev/null
+++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/BKUApplet.java
@@ -0,0 +1,359 @@
+/*
+ * 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.online.applet;
+
+import at.gv.egiz.bku.online.applet.viewer.URLFontLoader;
+import at.gv.egiz.bku.gui.BKUGUIFacade.Style;
+import at.gv.egiz.bku.gui.DefaultHelpListener;
+import at.gv.egiz.bku.gui.AbstractHelpListener;
+import at.gv.egiz.bku.gui.SwitchFocusListener;
+import at.gv.egiz.smcc.SignatureCardFactory;
+import at.gv.egiz.stal.service.translator.STALTranslator;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Locale;
+
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import javax.net.ssl.HttpsURLConnection;
+import javax.swing.JApplet;
+import javax.swing.JPanel;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.gui.BKUGUIFacade;
+import at.gv.egiz.bku.gui.BKUGUIImpl;
+import at.gv.egiz.bku.gui.viewer.FontProvider;
+import at.gv.egiz.stal.service.STALPortType;
+import at.gv.egiz.stal.service.STALService;
+import java.applet.AppletContext;
+import java.awt.Color;
+import java.awt.Container;
+
+import javax.xml.namespace.QName;
+
+/**
+ * Note: all swing code is executed by the event dispatch thread (see
+ * BKUGUIFacade)
+ */
+public class BKUApplet extends JApplet {
+
+ private static final long serialVersionUID = 1L;
+ private static Log log = LogFactory.getLog(BKUApplet.class);
+ /**
+ * Applet parameter keys
+ */
+ public static final String GUI_STYLE = "GuiStyle";
+ public final static String LOCALE = "Locale";
+ public final static String WSDL_URL = "WSDL_URL";
+ public static final String HASHDATA_DISPLAY = "HashDataDisplay";
+ public final static String HASHDATA_URL = "HashDataURL";
+ public final static String HELP_URL = "HelpURL";
+ public final static String SESSION_ID = "SessionID";
+ public static final String BACKGROUND_IMG = "Background";
+ public static final String BACKGROUND_COLOR = "BackgroundColor";
+ public static final String REDIRECT_URL = "RedirectURL";
+ public static final String REDIRECT_TARGET = "RedirectTarget";
+ public static final String HASHDATA_DISPLAY_FRAME = "frame";
+ public static final String ENFORCE_RECOMMENDED_PIN_LENGTH = "EnforceRecommendedPINLength";
+ /**
+ * STAL WSDL namespace and service name
+ */
+ public static final String STAL_WSDL_NS = "http://www.egiz.gv.at/wsdl/stal";
+ public static final String STAL_SERVICE = "STALService";
+ /**
+ * Dummy session id, used if no sessionId parameter is provided
+ */
+ protected static final String TEST_SESSION_ID = "TestSession";
+
+ public static final String VERSION;
+ public static final String UNKNOWN_VERSION = "UNKNOWN";
+
+ static {
+ String tmp = UNKNOWN_VERSION;
+ try {
+ String BKUAppletJar = BKUApplet.class.getProtectionDomain().getCodeSource().getLocation().toString();
+ URL manifestURL = new URL("jar:" + BKUAppletJar + "!/META-INF/MANIFEST.MF");
+ if (log.isTraceEnabled()) {
+ log.trace("read version information from " + manifestURL);
+ }
+ Manifest manifest = new Manifest(manifestURL.openStream());
+ Attributes atts = manifest.getMainAttributes();
+ if (atts != null) {
+ tmp = atts.getValue("Implementation-Build");
+ }
+ } catch (IOException ex) {
+ log.error("failed to read version", ex);
+ } finally {
+ VERSION = tmp;
+ log.debug("BKU Applet " + VERSION);
+ }
+ }
+
+ /**
+ * STAL
+ */
+ protected AppletBKUWorker worker;
+ protected Thread workerThread;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.applet.Applet#getParameterInfo()
+ */
+ @Override
+ public String[][] getParameterInfo() {
+ return new String[][]{
+ {WSDL_URL, "url",
+ "URL of the WSDL of the MOCCA server side STAL"},
+ {REDIRECT_URL, "url",
+ "URL to redirect the browser to when finished"},
+ {REDIRECT_TARGET, "frame target",
+ "name of the target frame for redirection when finished"},
+ {LOCALE, "locale",
+ "locale for UI localization (optional, default: system default)"},
+ {GUI_STYLE, "simple, advanced, tiny",
+ "GUI style (optional, default: simple)"},
+ {BACKGROUND_COLOR, "#hhhhhh",
+ "background color, e.g. '#333333' (optional, default: look and feel dependend)"},
+ {BACKGROUND_IMG, "url",
+ "URL of a background image for the GUI (optional, default: no image)"},
+ {HELP_URL, "url",
+ "URL for locating help files, e.g. '../help/' (no help provided if missing)"}};
+ }
+
+
+ /**
+ * Factory method to create and wire HelpListener, GUI and BKUWorker.
+ * (Config via applet parameters, see BKUApplet.* constants)
+ */
+ @Override
+ public void init() {
+ log.info("Welcome to MOCCA " + VERSION);
+ log.trace("Called init()");
+ showStatus("Initializing MOCCA applet");
+
+ HttpsURLConnection.setDefaultSSLSocketFactory(InternalSSLSocketFactory.getInstance());
+
+ String locale = getParameter(LOCALE);
+ if (locale != null) {
+ this.setLocale(new Locale(locale));
+ }
+ log.trace("default locale: " + Locale.getDefault());
+ log.debug("setting locale: " + getLocale());
+
+ if (Boolean.parseBoolean(getParameter(ENFORCE_RECOMMENDED_PIN_LENGTH))) {
+ SignatureCardFactory.ENFORCE_RECOMMENDED_PIN_LENGTH = true;
+ log.debug("enforce recommended pin length = " + SignatureCardFactory.ENFORCE_RECOMMENDED_PIN_LENGTH);
+ }
+
+ BKUGUIFacade.Style guiStyle;
+ String guiStyleParam = getParameter(GUI_STYLE);
+ if ("advanced".equalsIgnoreCase(guiStyleParam)) {
+ guiStyle = BKUGUIFacade.Style.advanced;
+ } else if ("tiny".equalsIgnoreCase(guiStyleParam)) {
+ guiStyle = BKUGUIFacade.Style.tiny;
+ } else {
+ guiStyle = BKUGUIFacade.Style.simple;
+ }
+ log.debug("setting gui-style: " + guiStyle);
+
+ URL backgroundImgURL = null;
+ try {
+ backgroundImgURL = getURLParameter(BACKGROUND_IMG, null);
+ log.debug("setting background: " + backgroundImgURL);
+ } catch (MalformedURLException ex) {
+ log.warn("cannot load applet background image: " + ex.getMessage());
+ }
+
+ AbstractHelpListener helpListener = null;
+ try {
+ helpListener = new DefaultHelpListener(getAppletContext(),
+ getURLParameter(HELP_URL, null), getLocale());
+ if (log.isDebugEnabled()) {
+ log.debug("setting helpURL: " + getURLParameter(HELP_URL, null));
+ }
+ } catch (MalformedURLException ex) {
+ log.warn("failed to load help URL: " + ex.getMessage() + ", disabling help");
+ }
+
+ // Note: We need a panel in order to be able to set the background
+ // properly.
+ // Setting the background without a panel has side effects with the
+ // different java plugins.
+ JPanel contentPanel = new JPanel();
+ getContentPane().add(contentPanel);
+
+ String backgroundColor = getParameter(BACKGROUND_COLOR);
+ if (backgroundColor != null && backgroundColor.startsWith("#")) {
+ try {
+ Color color = new Color(Integer.parseInt(backgroundColor.substring(1), 16));
+ log.debug("setting background color to " + color);
+ contentPanel.setBackground(color);
+ } catch (NumberFormatException e) {
+ log.debug("failed to set background color '" + backgroundColor + "'");
+ }
+ }
+
+ try {
+ URLFontLoader fontProvider = new URLFontLoader(getCodeBase());
+ fontProvider.loadInBackground();
+ BKUGUIFacade gui = createGUI(contentPanel, getLocale(), guiStyle,
+ backgroundImgURL, fontProvider, helpListener, null);
+
+ worker = createBKUWorker(this, gui);
+ } catch (MalformedURLException ex) {
+ log.fatal("failed to load font provider URL", ex);
+ System.err.println("invalid font provider URL " + ex.getMessage());
+ }
+ }
+
+ @Override
+ public void start() {
+ log.trace("Called start()");
+ if (worker != null) {
+ showStatus("Starting MOCCA applet");
+ workerThread = new Thread(worker);
+ workerThread.start();
+ } else {
+ log.debug("cannot start uninitialzed MOCCA applet");
+ }
+ }
+
+ @Override
+ public void stop() {
+ log.trace("Called stop()");
+ showStatus("Stopping MOCCA applet");
+ if ((workerThread != null) && (workerThread.isAlive())) {
+ workerThread.interrupt();
+ }
+ }
+
+ @Override
+ public void destroy() {
+ log.trace("Called destroy()");
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////
+ // factory methods for subclasses to inject different components
+ // ///////////////////////////////////////////////////////////////////////////
+ protected BKUGUIFacade createGUI(Container contentPane, Locale locale,
+ Style guiStyle, URL backgroundImgURL,
+ FontProvider fontProvider, AbstractHelpListener helpListener,
+ SwitchFocusListener switchFocusListener) {
+ return new BKUGUIImpl(contentPane, locale, guiStyle, backgroundImgURL,
+ fontProvider, helpListener, switchFocusListener);
+ }
+
+ protected AppletBKUWorker createBKUWorker(BKUApplet applet, BKUGUIFacade gui) {
+ return new AppletBKUWorker(applet, gui);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////
+ // callback for BKUWorker to allow extension
+ // ///////////////////////////////////////////////////////////////////////////
+ /**
+ * Callback for BKUWorker to allow extension
+ *
+ * @return
+ * @throws java.net.MalformedURLException
+ */
+ public STALPortType getSTALPort() throws MalformedURLException {
+ URL wsdlURL = getURLParameter(WSDL_URL, null);
+ log.debug("setting STAL WSDL: " + wsdlURL);
+ QName endpointName = new QName(STAL_WSDL_NS, STAL_SERVICE);
+ STALService stal = new STALService(wsdlURL, endpointName);
+ return stal.getSTALPort();
+ }
+
+ /**
+ * Callback for BKUWorker to allow extension (TODO STALPort could know its
+ * STALTranslator)
+ *
+ * @return
+ * @throws java.net.MalformedURLException
+ */
+ public STALTranslator getSTALTranslator() {
+ return new STALTranslator();
+ }
+
+ /**
+ * Callback for BKUWorker to keep applet context out of BKUWorker
+ *
+ * @return
+ * @throws java.net.MalformedURLException
+ */
+ protected void sendRedirect(String sessionId) {
+ try {
+ AppletContext ctx = getAppletContext();
+ if (ctx == null) {
+ log.error("no applet context (applet might already have been destroyed)");
+ return;
+ }
+ URL redirectURL = getURLParameter(REDIRECT_URL, sessionId);
+ String redirectTarget = getParameter(REDIRECT_TARGET);
+ if (redirectTarget == null) {
+ log.info("Done. Redirecting to " + redirectURL + " ...");
+ ctx.showDocument(redirectURL);
+ } else {
+ log.info("Done. Redirecting to " + redirectURL + " (target=" + redirectTarget + ") ...");
+ ctx.showDocument(redirectURL, redirectTarget);
+ }
+ } catch (MalformedURLException ex) {
+ log.warn("Failed to redirect: " + ex.getMessage(), ex);
+ // gui.showErrorDialog(errorMsg, okListener, actionCommand)
+ }
+ }
+
+ public void getFocusFromBrowser() {
+
+ worker.getFocusFromBrowser();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////
+ // utility methods
+ // ///////////////////////////////////////////////////////////////////////////
+ protected URL getURLParameter(String paramKey, String sessionId)
+ throws MalformedURLException {
+ String urlParam = getParameter(paramKey);
+ if (urlParam != null && !"".equals(urlParam)) {
+ URL codebase = getCodeBase();
+ try {
+ URL url;
+ if (codebase.getProtocol().equalsIgnoreCase("file")) {
+ // for debugging in appletrunner
+ url = new URL(urlParam);
+ } else {
+ if (sessionId != null) {
+ urlParam = urlParam + ";jsessionid=" + sessionId;
+ }
+ url = new URL(codebase, urlParam);
+ }
+ return url;
+ } catch (MalformedURLException ex) {
+ log.error("applet paremeter " + urlParam + " is not a valid URL: " + ex.getMessage());
+ throw ex;
+ }
+ } else {
+ log.error("applet paremeter " + paramKey + " not set");
+ throw new MalformedURLException(paramKey + " not set");
+ }
+ }
+}
diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/InternalSSLSocketFactory.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/InternalSSLSocketFactory.java
new file mode 100644
index 00000000..a02e56eb
--- /dev/null
+++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/InternalSSLSocketFactory.java
@@ -0,0 +1,157 @@
+/*
+ * 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.online.applet;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.List;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class InternalSSLSocketFactory extends SSLSocketFactory {
+
+ private final static String GOV_DOMAIN = ".gv.at";
+
+ private static InternalSSLSocketFactory instance = new InternalSSLSocketFactory();
+
+ private final static Log log = LogFactory
+ .getLog(InternalSSLSocketFactory.class);
+
+ private SSLSocket sslSocket;
+
+ private SSLSocketFactory proxy;
+
+ private InternalSSLSocketFactory() {
+ proxy = HttpsURLConnection.getDefaultSSLSocketFactory();
+ }
+
+ public static InternalSSLSocketFactory getInstance() {
+ return instance;
+ }
+
+ @Override
+ public Socket createSocket() throws IOException {
+ sslSocket = (SSLSocket) proxy.createSocket();
+ return sslSocket;
+ }
+
+ @Override
+ public Socket createSocket(String arg0, int arg1) throws IOException,
+ UnknownHostException {
+ sslSocket = (SSLSocket) proxy.createSocket(arg0, arg1);
+
+ return sslSocket;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress arg0, int arg1) throws IOException {
+ sslSocket = (SSLSocket) proxy.createSocket(arg0, arg1);
+ return sslSocket;
+ }
+
+ @Override
+ public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3)
+ throws IOException, UnknownHostException {
+ sslSocket = (SSLSocket) proxy.createSocket(arg0, arg1, arg2, arg3);
+ return sslSocket;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2,
+ int arg3) throws IOException {
+ sslSocket = (SSLSocket) proxy.createSocket(arg0, arg1, arg2, arg3);
+ return sslSocket;
+ }
+
+ @Override
+ public Socket createSocket(Socket arg0, String arg1, int arg2, boolean arg3)
+ throws IOException {
+ sslSocket = (SSLSocket) proxy.createSocket(arg0, arg1, arg2, arg3);
+ return sslSocket;
+ }
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ return proxy.getDefaultCipherSuites();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ return proxy.getSupportedCipherSuites();
+ }
+
+ public boolean isEgovAgency() {
+ log.info("Checking if server is egov agency");
+ if (sslSocket != null) {
+ try {
+ X509Certificate cert = (X509Certificate) sslSocket.getSession()
+ .getPeerCertificates()[0];
+ log.info("Server cert: " + cert);
+ return isGovAgency(cert);
+ } catch (SSLPeerUnverifiedException e) {
+ log.error(e);
+ return false;
+ }
+ }
+ log.info("Not a SSL connection");
+ return false;
+ }
+
+ 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];
+ if (dns.endsWith(GOV_DOMAIN)) {
+ return true;
+ }
+ }
+ }
+ try {
+ Collection<List<?>> sanList = cert.getSubjectAlternativeNames();
+ if (sanList != null) {
+ for (List<?> san : sanList) {
+ 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;
+ }
+}
diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/viewer/URLFontLoader.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/viewer/URLFontLoader.java
new file mode 100644
index 00000000..49615887
--- /dev/null
+++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/viewer/URLFontLoader.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.online.applet.viewer;
+
+import at.gv.egiz.bku.gui.viewer.FontProviderException;
+import at.gv.egiz.bku.gui.viewer.FontProvider;
+import java.awt.Font;
+import java.awt.FontFormatException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.concurrent.ExecutionException;
+import javax.swing.SwingWorker;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class URLFontLoader extends SwingWorker<Font, Object> implements FontProvider {
+
+ protected static final Log log = LogFactory.getLog(URLFontLoader.class);
+ protected URL fontURL;
+ protected Font font;
+
+ public URLFontLoader(URL codebase) throws MalformedURLException {
+ this.fontURL = new URL(codebase, SANSMONO_FONT_RESOURCE);
+ if (log.isDebugEnabled()) {
+ log.debug("[" + Thread.currentThread().getName() + "] setting font load URL: " + fontURL);
+ }
+ }
+
+ public void loadInBackground() {
+ if (log.isDebugEnabled()) {
+ log.debug("[" + Thread.currentThread().getName() + "] scheduling font loading in background: " + fontURL);
+ }
+ this.execute();
+ }
+
+ @Override
+ protected Font doInBackground() throws MalformedURLException, FontFormatException, IOException {
+ if (log.isDebugEnabled()) {
+ log.debug("[" + Thread.currentThread().getName() + "] loading font in background...");
+ }
+ return Font.createFont(Font.TRUETYPE_FONT, fontURL.openStream());
+ }
+
+ /**
+ * waits for loadInBackground to finish
+ * @return the font loaded in loadInbackground
+ * @throws Exception
+ */
+ @Override
+ public Font getFont() throws FontProviderException {
+ log.debug("[" + Thread.currentThread().getName() + "] get font (EDT?)");
+ try {
+ return get();
+ } catch (InterruptedException ex) {
+ log.error("font loader interrupted");
+// Thread.currentThread().interrupt();
+ throw new FontProviderException("font loader interrupted", ex);
+ } catch (ExecutionException ex) {
+ log.error("failed to load font", ex.getCause());
+ throw new FontProviderException("failed to load font", ex.getCause());
+ }
+ }
+}