From e2ab585fc4cfc165dc02ea9142f33dd308979e49 Mon Sep 17 00:00:00 2001 From: Jakob Heher Date: Mon, 3 Oct 2022 17:36:36 +0200 Subject: start untangling BKU handler from GUI logic --- pdf-over-commons/pom.xml | 4 + .../java/at/asit/pdfover/commons/Constants.java | 11 +- pdf-over-gui/pom.xml | 9 + .../at/asit/pdfover/gui/bku/LocalBKUConnector.java | 2 +- .../asit/pdfover/gui/bku/MobileBKUConnector.java | 207 ------ .../pdfover/gui/bku/OLDMobileBKUConnector.java | 207 ++++++ .../pdfover/gui/bku/OLDmobile/ATrustHandler.java | 793 +++++++++++++++++++++ .../pdfover/gui/bku/OLDmobile/ATrustStatus.java | 68 ++ .../pdfover/gui/bku/OLDmobile/MobileBKUHelper.java | 318 +++++++++ .../asit/pdfover/gui/bku/OLDmobile/MobileBKUs.java | 27 + .../gui/bku/OLDmobile/SimpleXMLTrustManager.java | 220 ++++++ .../gui/bku/OLDmobile/TrustedSocketFactory.java | 191 +++++ .../asit/pdfover/gui/bku/mobile/ATrustHandler.java | 793 --------------------- .../asit/pdfover/gui/bku/mobile/ATrustStatus.java | 68 -- .../pdfover/gui/bku/mobile/MobileBKUHelper.java | 318 --------- .../at/asit/pdfover/gui/bku/mobile/MobileBKUs.java | 27 - .../gui/bku/mobile/SimpleXMLTrustManager.java | 220 ------ .../gui/bku/mobile/TrustedSocketFactory.java | 191 ----- .../pdfover/gui/cliarguments/PasswordArgument.java | 2 +- .../gui/cliarguments/PhoneNumberArgument.java | 2 +- .../composites/MobileBKUEnterNumberComposite.java | 2 +- .../workflow/config/ConfigurationDataInMemory.java | 2 +- .../gui/workflow/config/ConfigurationManager.java | 2 +- .../gui/workflow/states/MobileBKUState.java | 121 ++-- .../asit/pdfover/signer/pdfas/PdfAs4SLRequest.java | 4 +- pom.xml | 5 + 26 files changed, 1938 insertions(+), 1876 deletions(-) delete mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/MobileBKUConnector.java create mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDMobileBKUConnector.java create mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustHandler.java create mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustStatus.java create mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/MobileBKUHelper.java create mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/MobileBKUs.java create mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/SimpleXMLTrustManager.java create mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/TrustedSocketFactory.java delete mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustHandler.java delete mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustStatus.java delete mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/MobileBKUHelper.java delete mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/MobileBKUs.java delete mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/SimpleXMLTrustManager.java delete mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/TrustedSocketFactory.java diff --git a/pdf-over-commons/pom.xml b/pdf-over-commons/pom.xml index 58ea1e9f..712a6670 100644 --- a/pdf-over-commons/pom.xml +++ b/pdf-over-commons/pom.xml @@ -26,6 +26,10 @@ com.drewnoakes metadata-extractor + + com.google.code.findbugs + jsr305 + diff --git a/pdf-over-commons/src/main/java/at/asit/pdfover/commons/Constants.java b/pdf-over-commons/src/main/java/at/asit/pdfover/commons/Constants.java index 3c9aced8..9c6d2111 100644 --- a/pdf-over-commons/src/main/java/at/asit/pdfover/commons/Constants.java +++ b/pdf-over-commons/src/main/java/at/asit/pdfover/commons/Constants.java @@ -17,9 +17,12 @@ package at.asit.pdfover.commons; import java.io.File; import java.io.FileInputStream; +import java.net.URI; import java.util.Locale; import java.util.Properties; +import javax.annotation.Nonnull; + import org.eclipse.swt.graphics.Color; import org.eclipse.swt.widgets.Display; import org.slf4j.Logger; @@ -107,7 +110,7 @@ public class Constants { public static final String LOCAL_BKU_URL = "http://127.0.0.1:3495/http-security-layer-request"; /** Default Mobile BKU URL */ - public static final String MOBILE_BKU_URL = "https://www.a-trust.at/mobile/https-security-layer-request/default.aspx"; + public static final URI MOBILE_BKU_URL = URI.create("https://www.a-trust.at/mobile/https-security-layer-request/default.aspx"); /** How far to displace the signature with the arrow keys */ public static final int SIGNATURE_KEYBOARD_POSITIONING_OFFSET = 15; @@ -370,4 +373,10 @@ public class Constants { public static final String LABEL_BTN_IDF = "Button_Identification"; + /** + * for static analysis; mark a given value as definitely, contractually not null + * (try to avoid its use in performance-critical code, grr java) + */ + public static @Nonnull T ISNOTNULL(T value) { assert(value != null); return value; } + } diff --git a/pdf-over-gui/pom.xml b/pdf-over-gui/pom.xml index ed0e5c82..ee0b41b2 100644 --- a/pdf-over-gui/pom.xml +++ b/pdf-over-gui/pom.xml @@ -35,6 +35,11 @@ commons-httpclient commons-httpclient + + org.apache.httpcomponents.client5 + httpclient5 + 5.1.3 + commons-io commons-io @@ -60,6 +65,10 @@ ${project.parent.version} compile + + com.google.code.findbugs + jsr305 + diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/LocalBKUConnector.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/LocalBKUConnector.java index ffd924f6..fe1e3a29 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/LocalBKUConnector.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/LocalBKUConnector.java @@ -69,7 +69,7 @@ public class LocalBKUConnector implements BkuSlConnector { HttpClient client = BKUHelper.getHttpClient(); PostMethod method = new PostMethod(Constants.LOCAL_BKU_URL); - String sl_request = request.request; + String sl_request = request.xmlRequest; if (request.signatureData == null) { method.addParameter("XMLRequest", sl_request); } else { diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/MobileBKUConnector.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/MobileBKUConnector.java deleted file mode 100644 index c17451ed..00000000 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/MobileBKUConnector.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2012 by A-SIT, Secure Information Technology Center Austria - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package at.asit.pdfover.gui.bku; - -// Imports -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.asit.pdfover.commons.Constants; -import at.asit.pdfover.gui.bku.mobile.ATrustHandler; -import at.asit.pdfover.gui.bku.mobile.ATrustStatus; -import at.asit.pdfover.gui.workflow.states.MobileBKUState; -import at.asit.pdfover.signer.BkuSlConnector; -import at.asit.pdfover.signer.SignatureException; -import at.asit.pdfover.signer.pdfas.PdfAs4SLRequest; -import at.asit.pdfover.signer.pdfas.PdfAs4SigningState; - -/** - * - */ -public class MobileBKUConnector implements BkuSlConnector { - /** - * SLF4J Logger instance - **/ - private static final Logger log = LoggerFactory.getLogger(MobileBKUConnector.class); - - private MobileBKUState state; - - /** - * - * @param state - */ - public MobileBKUConnector(MobileBKUState state) { - this.state = state; - } - - /** (non-Javadoc) - * @see at.asit.pdfover.signer.BkuSlConnector#handleSLRequest(java.lang.String) - */ - @Override - public String handleSLRequest(PdfAs4SLRequest request) throws SignatureException { - PdfAs4SigningState signingState = this.state.getSigningState(); - signingState.signatureRequest = request; - - ATrustHandler handler = this.state.handler; - - do { - // Post SL Request - try { - String responseData = handler.postSLRequest(Constants.MOBILE_BKU_URL, request); - - // Now we have received some data lets check it: - log.trace("Response from mobile BKU: " + responseData); - - handler.handleSLRequestResponse(responseData); - } catch (Exception ex) { - log.error("Error in PostSLRequestThread", ex); - this.state.threadException = ex; - this.state.displayError(ex); - throw new SignatureException(ex); - } - - do { - // Check if credentials are available, get them from user if not - this.state.checkCredentials(); - - if (consumeCancelError()) - throw new SignatureException(new IllegalStateException()); - - // Post credentials - try { - String responseData = handler.postCredentials(); - - if (responseData.contains("undecided.aspx?sid=")) { - // handle polling - this.state.showOpenAppMessageWithSMSandCancel(); - - if (this.state.status.isSMSTan) { - String response = handler.postSMSRequest(); - handler.handleCredentialsResponse(response); - } else if (consumeCancelError()) { - throw new SignatureException(new IllegalStateException()); - } - } else { - - // Now we have received some data lets check it: - log.trace("Response from mobile BKU: " + responseData); - handler.handleCredentialsResponse(responseData); - } - - } catch (Exception ex) { - log.error("Error in PostCredentialsThread", ex); - this.state.threadException = new IllegalStateException(); - throw new SignatureException(new IllegalStateException()); - } - } while(this.state.status.errorMessage != null); - - // Check if response is already available - if (signingState.signatureResponse != null) { - String response = signingState.signatureResponse; - signingState.signatureResponse = null; - return response; - } - - do { - ATrustStatus status = this.state.status; - boolean enterTAN = true; - String responseData = null; - if (status.qrCodeURL != null) { - this.state.showQR(); - if ("cancel".equals(this.state.status.errorMessage)) - throw new SignatureException(new IllegalStateException()); - if (status.qrCodeURL == null) { - try { - String response = handler.postSMSRequest(); - log.trace("Response from mobile BKU: " + response); - handler.handleCredentialsResponse(response); - } catch (Exception ex) { - log.error("Error in PostCredentialsThread", ex); - this.state.threadException = new IllegalStateException(); - throw new SignatureException(new IllegalStateException()); - } - } else { - enterTAN = false; - } - } - if (enterTAN && !status.tanField) { - try { - - this.state.showFingerPrintInformation(); - if ("cancel".equals(this.state.status.errorMessage)) - throw new SignatureException(new IllegalStateException()); - } catch (Exception ex) { - log.error("Error in PostCredentialsThread", ex); - this.state.threadException = new IllegalStateException(); - //this.state.displayError(ex); - throw new SignatureException(new IllegalStateException()); - } - - if (this.state.getSMSStatus()) { - String response; - try { - response = handler.postSMSRequest(); - handler.handleCredentialsResponse(response); - } catch (Exception e) { - log.error("Error in PostCredentialsThread", e); - this.state.threadException = e; - this.state.displayError(e); - throw new SignatureException(e); - } - } - else { - enterTAN = false; - } - } - - if (enterTAN) { - // Get TAN - this.state.checkTAN(); - - if ("cancel".equals(this.state.status.errorMessage)) - throw new SignatureException(new IllegalStateException()); - - // Post TAN - try { - responseData = handler.postTAN(); - log.trace("Response from mobile BKU: " + responseData); - - // Now we have received some data lets check it: - handler.handleTANResponse(responseData); - } catch (Exception ex) { - log.error("Error in PostTanThread", ex); - this.state.threadException = ex; - this.state.displayError(ex); - throw new SignatureException(ex); - } - } - } while (this.state.status.errorMessage != null); - if (this.state.status.tanTries == -1) - throw new SignatureException(new IllegalStateException()); - } while (this.state.status.tanTries == -2); - - return signingState.signatureResponse; - } - - private boolean consumeCancelError() { - if ("cancel".equals(this.state.status.errorMessage)) { - this.state.status.errorMessage = null; - return true; - } - return false; - } - -} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDMobileBKUConnector.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDMobileBKUConnector.java new file mode 100644 index 00000000..a71f37df --- /dev/null +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDMobileBKUConnector.java @@ -0,0 +1,207 @@ +/* + * Copyright 2012 by A-SIT, Secure Information Technology Center Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package at.asit.pdfover.gui.bku; + +// Imports +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.asit.pdfover.commons.Constants; +import at.asit.pdfover.gui.bku.OLDmobile.ATrustHandler; +import at.asit.pdfover.gui.bku.OLDmobile.ATrustStatus; +import at.asit.pdfover.gui.workflow.states.MobileBKUState; +import at.asit.pdfover.signer.BkuSlConnector; +import at.asit.pdfover.signer.SignatureException; +import at.asit.pdfover.signer.pdfas.PdfAs4SLRequest; +import at.asit.pdfover.signer.pdfas.PdfAs4SigningState; + +/** + * + */ +public class OLDMobileBKUConnector implements BkuSlConnector { + /** + * SLF4J Logger instance + **/ + private static final Logger log = LoggerFactory.getLogger(OLDMobileBKUConnector.class); + + private MobileBKUState state; + + /** + * + * @param state + */ + public OLDMobileBKUConnector(MobileBKUState state) { + this.state = state; + } + + /** (non-Javadoc) + * @see at.asit.pdfover.signer.BkuSlConnector#handleSLRequest(java.lang.String) + */ + @Override + public String handleSLRequest(PdfAs4SLRequest request) throws SignatureException { + PdfAs4SigningState signingState = this.state.getSigningState(); + signingState.signatureRequest = request; + + ATrustHandler handler = this.state.handler; + + do { + // Post SL Request + try { + String responseData = handler.postSLRequest(Constants.MOBILE_BKU_URL.toString(), request); + + // Now we have received some data lets check it: + log.trace("Response from mobile BKU: " + responseData); + + handler.handleSLRequestResponse(responseData); + } catch (Exception ex) { + log.error("Error in PostSLRequestThread", ex); + this.state.threadException = ex; + this.state.displayError(ex); + throw new SignatureException(ex); + } + + do { + // Check if credentials are available, get them from user if not + this.state.checkCredentials(); + + if (consumeCancelError()) + throw new SignatureException(new IllegalStateException()); + + // Post credentials + try { + String responseData = handler.postCredentials(); + + if (responseData.contains("undecided.aspx?sid=")) { + // handle polling + this.state.showOpenAppMessageWithSMSandCancel(); + + if (this.state.status.isSMSTan) { + String response = handler.postSMSRequest(); + handler.handleCredentialsResponse(response); + } else if (consumeCancelError()) { + throw new SignatureException(new IllegalStateException()); + } + } else { + + // Now we have received some data lets check it: + log.trace("Response from mobile BKU: " + responseData); + handler.handleCredentialsResponse(responseData); + } + + } catch (Exception ex) { + log.error("Error in PostCredentialsThread", ex); + this.state.threadException = new IllegalStateException(); + throw new SignatureException(new IllegalStateException()); + } + } while(this.state.status.errorMessage != null); + + // Check if response is already available + if (signingState.signatureResponse != null) { + String response = signingState.signatureResponse; + signingState.signatureResponse = null; + return response; + } + + do { + ATrustStatus status = this.state.status; + boolean enterTAN = true; + String responseData = null; + if (status.qrCodeURL != null) { + this.state.showQR(); + if ("cancel".equals(this.state.status.errorMessage)) + throw new SignatureException(new IllegalStateException()); + if (status.qrCodeURL == null) { + try { + String response = handler.postSMSRequest(); + log.trace("Response from mobile BKU: " + response); + handler.handleCredentialsResponse(response); + } catch (Exception ex) { + log.error("Error in PostCredentialsThread", ex); + this.state.threadException = new IllegalStateException(); + throw new SignatureException(new IllegalStateException()); + } + } else { + enterTAN = false; + } + } + if (enterTAN && !status.tanField) { + try { + + this.state.showFingerPrintInformation(); + if ("cancel".equals(this.state.status.errorMessage)) + throw new SignatureException(new IllegalStateException()); + } catch (Exception ex) { + log.error("Error in PostCredentialsThread", ex); + this.state.threadException = new IllegalStateException(); + //this.state.displayError(ex); + throw new SignatureException(new IllegalStateException()); + } + + if (this.state.getSMSStatus()) { + String response; + try { + response = handler.postSMSRequest(); + handler.handleCredentialsResponse(response); + } catch (Exception e) { + log.error("Error in PostCredentialsThread", e); + this.state.threadException = e; + this.state.displayError(e); + throw new SignatureException(e); + } + } + else { + enterTAN = false; + } + } + + if (enterTAN) { + // Get TAN + this.state.checkTAN(); + + if ("cancel".equals(this.state.status.errorMessage)) + throw new SignatureException(new IllegalStateException()); + + // Post TAN + try { + responseData = handler.postTAN(); + log.trace("Response from mobile BKU: " + responseData); + + // Now we have received some data lets check it: + handler.handleTANResponse(responseData); + } catch (Exception ex) { + log.error("Error in PostTanThread", ex); + this.state.threadException = ex; + this.state.displayError(ex); + throw new SignatureException(ex); + } + } + } while (this.state.status.errorMessage != null); + if (this.state.status.tanTries == -1) + throw new SignatureException(new IllegalStateException()); + } while (this.state.status.tanTries == -2); + + return signingState.signatureResponse; + } + + private boolean consumeCancelError() { + if ("cancel".equals(this.state.status.errorMessage)) { + this.state.status.errorMessage = null; + return true; + } + return false; + } + +} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustHandler.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustHandler.java new file mode 100644 index 00000000..2e69e779 --- /dev/null +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustHandler.java @@ -0,0 +1,793 @@ +/* + * Copyright 2012 by A-SIT, Secure Information Technology Center Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package at.asit.pdfover.gui.bku.OLDmobile; + +// Imports +import java.awt.Desktop; +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.multipart.FilePart; +import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; +import org.apache.commons.httpclient.methods.multipart.Part; +import org.apache.commons.httpclient.methods.multipart.StringPart; +import org.apache.commons.io.IOUtils; +import org.eclipse.swt.SWT; +import org.eclipse.swt.program.Program; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import at.asit.pdfover.commons.Constants; +import at.asit.pdfover.gui.controls.Dialog; +import at.asit.pdfover.gui.controls.Dialog.BUTTONS; +import at.asit.pdfover.gui.controls.Dialog.ICON; +import at.asit.pdfover.gui.exceptions.ATrustConnectionException; +import at.asit.pdfover.gui.utils.FileUploadSource; +import at.asit.pdfover.commons.Messages; +import at.asit.pdfover.gui.workflow.states.LocalBKUState; +import at.asit.pdfover.gui.workflow.states.MobileBKUState; +import at.asit.pdfover.signer.pdfas.PdfAs4SLRequest; +import at.asit.pdfover.signer.pdfas.PdfAs4SigningState; + +/** + * A-Trust mobile BKU handler + */ +public class ATrustHandler { + public final MobileBKUState state; + public final Shell shell; + + /** + * @param state + * @param shell + */ + public ATrustHandler(MobileBKUState state, Shell shell) { + this.state = state; + this.shell = shell; + } + + /** + * SLF4J Logger instance + **/ + static final Logger log = LoggerFactory.getLogger(ATrustHandler.class); + + private static boolean expiryNoticeDisplayed = false; + + private static final String ACTIVATION_URL = "https://www.handy-signatur.at/"; + + /** + * Get the MobileBKUStatus + * @return the MobileBKUStatus + */ + protected ATrustStatus getStatus() { + return this.state.status; + } + + /** + * Get the SigningState + * @return the SigningState + */ + protected PdfAs4SigningState getSigningState() { + return state.getSigningState(); + } + + /** + * Execute a post to the mobile BKU, following redirects + * @param client the HttpClient + * @param post the PostMethod + * @return the response + * @throws IOException IO error + */ + protected String executePost(HttpClient client, PostMethod post) throws IOException { + if (log.isDebugEnabled()) { + String req; + if (post.getRequestEntity().getContentLength() < 1024) { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + post.getRequestEntity().writeRequest(os); + req = os.toString(); + if (req.contains("passwort=")) + req = req.replaceAll("passwort=[^&]*", "passwort=******"); + if (req.contains(":pwd=")) + req = req.replaceAll(":pwd=[^&]*", ":pwd=******"); + os.close(); + } else { + req = post.getRequestEntity().getContentLength() + " bytes"; + } + log.debug("Posting to " + post.getURI() + ": " + req); + } + int returnCode = client.executeMethod(post); + + String redirectLocation = null; + GetMethod get = null; + + + String responseData = null; + + String server = null; + + // Follow redirects + do { + // check return code + if (returnCode == HttpStatus.SC_MOVED_TEMPORARILY || + returnCode == HttpStatus.SC_MOVED_PERMANENTLY) { + + Header locationHeader = post.getResponseHeader("location"); + if (locationHeader != null) { + redirectLocation = locationHeader.getValue(); + } else { + throw new IOException( + "Got HTTP 302 but no location to follow!"); + } + } else if (returnCode == HttpStatus.SC_OK) { + if (get != null) { + responseData = get.getResponseBodyAsString(); + Header serverHeader = get.getResponseHeader( + LocalBKUState.BKU_RESPONSE_HEADER_SERVER); + if (serverHeader != null) + server = serverHeader.getValue(); + } else { + responseData = post.getResponseBodyAsString(); + + Header serverHeader = post.getResponseHeader( + LocalBKUState.BKU_RESPONSE_HEADER_SERVER); + if (serverHeader != null) + server = serverHeader.getValue(); + } + redirectLocation = null; + String p = "]*http-equiv=\"refresh\" [^>]*content=\"([^\"]*)\""; + Pattern pat = Pattern.compile(p); + Matcher m = pat.matcher(responseData); + if (m.find()) { + String content = m.group(1); + int start = content.indexOf("URL="); + if (start != -1) { + start += 9; + redirectLocation = content.substring(start, content.length() - 5); + } + } + } else { + throw new HttpException( + HttpStatus.getStatusText(returnCode)); + } + + if (redirectLocation != null) { + redirectLocation = MobileBKUHelper.getQualifiedURL(redirectLocation, new URL(post.getURI().toString())); + log.debug("Redirected to " + redirectLocation); + get = new GetMethod(redirectLocation); + get.setFollowRedirects(true); + returnCode = client.executeMethod(get); + } + } while (redirectLocation != null); + + getStatus().server = server; + if (server != null) + log.debug("Server: " + server); + + return responseData; + } + + /** + * Execute a get from the mobile BKU, following redirects + * @param client the HttpClient + * @param get the GetMethod + * @return the response + * @throws IOException IO error + */ + protected String executeGet(HttpClient client, GetMethod get) throws IOException { + log.debug("Getting " + get.getURI()); + + int returnCode = client.executeMethod(get); + + String redirectLocation = null; + + GetMethod get2 = null; + + String responseData = null; + + String server = null; + + // Follow redirects + do { + // check return code + if (returnCode == HttpStatus.SC_MOVED_TEMPORARILY || + returnCode == HttpStatus.SC_MOVED_PERMANENTLY) { + + Header locationHeader = get.getResponseHeader("location"); + if (locationHeader != null) { + redirectLocation = locationHeader.getValue(); + } else { + throw new IOException( + "Got HTTP 302 but no location to follow!"); + } + } else if (returnCode == HttpStatus.SC_OK) { + if (get2 != null) { + responseData = get2.getResponseBodyAsString(); + Header serverHeader = get2.getResponseHeader( + LocalBKUState.BKU_RESPONSE_HEADER_SERVER); + if (serverHeader != null) + server = serverHeader.getValue(); + } else { + responseData = get.getResponseBodyAsString(); + + Header serverHeader = get.getResponseHeader( + LocalBKUState.BKU_RESPONSE_HEADER_SERVER); + if (serverHeader != null) + server = serverHeader.getValue(); + } + redirectLocation = null; + String p = "]*http-equiv=\"refresh\" [^>]*content=\"([^\"]*)\""; + Pattern pat = Pattern.compile(p); + Matcher m = pat.matcher(responseData); + if (m.find()) { + String content = m.group(1); + int start = content.indexOf("URL="); + if (start != -1) { + start += 9; + redirectLocation = content.substring(start, content.length() - 5); + } + } + } else { + throw new HttpException( + HttpStatus.getStatusText(returnCode)); + } + + if (redirectLocation != null) { + redirectLocation = MobileBKUHelper.getQualifiedURL(redirectLocation, new URL(get.getURI().toString())); + log.debug("Redirected to " + redirectLocation); + get2 = new GetMethod(redirectLocation); + get2.setFollowRedirects(true); + returnCode = client.executeMethod(get2); + } + } while (redirectLocation != null); + + getStatus().server = server; + if (server != null) + log.debug("Server: " + server); + + return responseData; + } + + /** + * Post the SL request + * @param mobileBKUUrl mobile BKU URL + * @param request SLRequest + * @return the response + * @throws IOException IO error + */ + public String postSLRequest(String mobileBKUUrl, PdfAs4SLRequest request) throws IOException { + MobileBKUHelper.registerTrustedSocketFactory(); + HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); + + PostMethod post = new PostMethod(mobileBKUUrl); + String sl_request; + if (request.signatureData != null) { + sl_request = request.xmlRequest; + StringPart xmlpart = new StringPart( + "XMLRequest", sl_request, "UTF-8"); + + FilePart filepart = new FilePart("fileupload", + new FileUploadSource(request.signatureData), + "application/pdf", "UTF-8"); + + Part[] parts = { xmlpart, filepart }; + + post.setRequestEntity(new MultipartRequestEntity(parts, post + .getParams())); + } else { + sl_request = request.xmlRequest; + post.addParameter("XMLRequest", sl_request); + } + log.trace("SL Request: " + sl_request); + + state.status.baseURL = MobileBKUHelper.stripQueryString(mobileBKUUrl); + + return executePost(client, post); + } + + /* (non-Javadoc) + * @see at.asit.pdfover.gui.workflow.states.mobilebku.MobileBKUHandler#handleSLRequestResponse(java.lang.String) + */ + public void handleSLRequestResponse(String responseData) throws Exception { + ATrustStatus status = getStatus(); + + if (responseData.contains("", ""); + String errorMsg = MobileBKUHelper.extractSubstring(responseData, + "", ""); + throw new Exception("Error from mobile BKU: " + + errorCode + " - " + errorMsg); + } + + // Extract infos: + String sessionID = MobileBKUHelper.extractSubstring(responseData, + "identification.aspx?sid=", "\""); + + String viewState = MobileBKUHelper.extractValueFromTagWithParam( + responseData, "", "id", "__VIEWSTATE", "value"); + + String eventValidation = MobileBKUHelper.extractValueFromTagWithParam( + responseData, "", "id", "__EVENTVALIDATION", "value"); + + String viewstateGenerator = MobileBKUHelper.extractValueFromTagWithParamOptional(responseData, "", "id", "__VIEWSTATEGENERATOR", "value"); + + String dynamicAttrPhonenumber = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_PHONE_NUMBER); + String dynamicAttrPassword = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_SIGN_PASS); + String dynamicAttrButtonId = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_BTN_IDF); + String dynamicAttrTan = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_TAN); + + + log.debug("sessionID: " + sessionID); + log.debug("viewState: " + viewState); + log.debug("eventValidation: " + eventValidation); + + status.sessionID = sessionID; + status.viewState = viewState; + status.eventValidation = eventValidation; + if (viewstateGenerator != null ) { status.viewStateGenerator = viewstateGenerator; } + status.dynAttrPhoneNumber = dynamicAttrPhonenumber; + status.dynAttrPassword = dynamicAttrPassword; + status.dynAttrBtnId = dynamicAttrButtonId; + status.dynAttrTan = dynamicAttrTan; + } + + /* (non-Javadoc) + * @see at.asit.pdfover.gui.workflow.states.mobilebku.MobileBKUHandler#postCredentials() + */ + public String postCredentials() throws IOException { + ATrustStatus status = getStatus(); + + MobileBKUHelper.registerTrustedSocketFactory(); + HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); + + PostMethod post = new PostMethod(status.baseURL + "/identification.aspx?sid=" + status.sessionID); + post.getParams().setContentCharset("utf-8"); + post.addParameter("__VIEWSTATE", status.viewState); + post.addParameter("__VIEWSTATEGENERATOR", status.viewStateGenerator); + post.addParameter("__EVENTVALIDATION", status.eventValidation); + post.addParameter(status.dynAttrPhoneNumber, status.phoneNumber); + post.addParameter(status.dynAttrPassword, status.mobilePassword); + post.addParameter(status.dynAttrBtnId, "Identifizieren"); + + return executePost(client, post); + } + + /* (non-Javadoc) + * @see at.asit.pdfover.gui.workflow.states.mobilebku.MobileBKUHandler#handleCredentialsResponse(java.lang.String) + */ + public void handleCredentialsResponse(final String responseData) throws Exception { + ATrustStatus status = getStatus(); + String viewState = status.viewState; + String eventValidation = status.eventValidation; + String sessionID = status.sessionID; + String refVal = null; + String signatureDataURL = null; + String viewstateGenerator = status.viewStateGenerator; + + status.errorMessage = null; + + final Document responseDocument = Jsoup.parse(responseData); + + if (responseData.contains("ExpiresInfo.aspx?sid=")) { + // Certificate expiration interstitial - skip + if (!expiryNoticeDisplayed) { + Display.getDefault().syncExec(()-> { + Dialog d = new Dialog(ATrustHandler.this.shell, Messages.getString("common.info"), Messages.getString("mobileBKU.certExpiresSoon"), BUTTONS.YES_NO, ICON.WARNING); + if (d.open() == SWT.YES) { + log.debug("Trying to open " + ACTIVATION_URL); + if (Desktop.isDesktopSupported()) { + try { + Desktop.getDesktop().browse(new URI(ACTIVATION_URL)); + return; + } catch (Exception e) { + log.debug("Error opening URL", e); + } + } + log.info("SWT Desktop is not supported on this platform"); + Program.launch(ACTIVATION_URL); + } + }); + expiryNoticeDisplayed = true; + } + + String t_sessionID = MobileBKUHelper.extractSubstring(responseData, "ExpiresInfo.aspx?sid=", "\""); + String t_viewState = MobileBKUHelper.extractValueFromTagWithParam(responseData, "", "id", "__VIEWSTATE", "value"); + String t_eventValidation = MobileBKUHelper.extractValueFromTagWithParam(responseData, "", "id", "__EVENTVALIDATION", "value"); + + // Post again to skip + MobileBKUHelper.registerTrustedSocketFactory(); + HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); + + PostMethod post = new PostMethod(status.baseURL + "/ExpiresInfo.aspx?sid=" + t_sessionID); + post.getParams().setContentCharset("utf-8"); + post.addParameter("__VIEWSTATE", t_viewState); + post.addParameter("__EVENTVALIDATION", t_eventValidation); + post.addParameter("Button_Next", "Weiter"); + + handleCredentialsResponse(executePost(client, post)); + return; + } else if (responseData.contains("tanAppInfo.aspx?sid=")) { + // App info interstitial - skip + log.info("Skipping tan app interstitial"); + + String t_sessionID = MobileBKUHelper.extractSubstring(responseData, "tanAppInfo.aspx?sid=", "\""); + String t_viewState = MobileBKUHelper.extractValueFromTagWithParam(responseData, "", "id", "__VIEWSTATE", "value"); + String t_eventValidation = MobileBKUHelper.extractValueFromTagWithParam(responseData, "", "id", "__EVENTVALIDATION", "value"); + + // Post again to skip + MobileBKUHelper.registerTrustedSocketFactory(); + HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); + + PostMethod post = new PostMethod(status.baseURL + "/tanAppInfo.aspx?sid=" + t_sessionID); + post.getParams().setContentCharset("utf-8"); + post.addParameter("__VIEWSTATE", t_viewState); + post.addParameter("__EVENTVALIDATION", t_eventValidation); + post.addParameter("NextBtn", "Weiter"); + + handleCredentialsResponse(executePost(client, post)); + return; + } + + if (responseData.contains("signature.aspx?sid=")) { + // credentials ok! TAN entry + state.rememberCredentialsIfNecessary(status.phoneNumber, status.mobilePassword); + log.debug("Credentials accepted - TAN required"); + sessionID = MobileBKUHelper.extractSubstring(responseData, "signature.aspx?sid=", "\""); + viewState = MobileBKUHelper.extractValueFromTagWithParam(responseData, "", "id", "__VIEWSTATE", "value"); + eventValidation = MobileBKUHelper.extractValueFromTagWithParam(responseData, "", "id", "__EVENTVALIDATION", "value"); + refVal = MobileBKUHelper.extractSubstring(responseData, "id='vergleichswert'>Vergleichswert:", ""); + signatureDataURL = status.baseURL + "/ShowSigobj.aspx" + + MobileBKUHelper.extractSubstring(responseData, "ShowSigobj.aspx", "'"); + try { + String qrCode = MobileBKUHelper.extractValueFromTagWithParam(responseData, "img", "class", "qrcode", "src"); + log.debug("QR Code found: " + qrCode); + status.qrCodeURL = qrCode; + } catch (Exception e) { + log.debug("No QR Code found"); + } + try { + String tanTextTan = MobileBKUHelper.extractValueFromTagWithParam(responseData, "label", "id", "label_for_input_tan", "for"); + status.tanField = tanTextTan.equals("input_tan"); + status.dynAttrTan = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_TAN); + status.dynAttrSignButton = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_SIGN_BTN); + } catch (Exception e) { + log.debug("No tan field found"); + } + try { + String tanTextTan = MobileBKUHelper.extractContentFromTagWithParam(responseData, "span", "id", "text_tan"); + status.isAPPTan = !tanTextTan.toLowerCase().contains("sms"); + status.dynAttrTan = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_TAN); + status.dynAttrSignButton = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_SIGN_BTN); + }catch (Exception e) { + log.debug("No text_tan tag"); + } + try { + String webauthnLink = MobileBKUHelper.extractValueFromTagWithParam(responseData, "a", "id", "FidoButton", "href"); + log.info("Webauthn link: {}", webauthnLink); + } catch (Exception e) { + log.info("No webauthnLink"); + } + try { + String webauthnData = MobileBKUHelper.extractValueFromTagWithParam(responseData, "input", "id", "credentialOptions", "value"); + log.info("Fido credential options: {}", webauthnData); + } catch (Exception e) { + log.info("No webauthnData"); + } + + } else if (responseData.contains("sl:InfoboxReadResponse")) { + // credentials ok! InfoboxReadResponse + state.rememberCredentialsIfNecessary(status.phoneNumber, status.mobilePassword); + log.debug("Credentials accepted - Response given"); + getSigningState().signatureResponse = responseData; + return; + } else if (responseData.contains("undecided.aspx?sid=")) { + // skip intermediate page + log.debug("Page Undecided"); + getSigningState().signatureResponse = responseData; + status.errorMessage = "waiting..."; // TODO: this looks incorrect...? + return; + }else { + // error page + + // force UI again! + state.clearRememberedPassword(); + // extract error text! + try { + String errorMessage = MobileBKUHelper.extractContentFromTagWithParam(responseData, "span", "id", "Label1"); + if (errorMessage.startsWith("Fehler: ")) + errorMessage = errorMessage.substring(8); + status.errorMessage = errorMessage.strip(); + } catch (Exception e) { + log.error("Failed to get credentials error message", e); + String msg = null; + try + { + msg = MobileBKUHelper.extractSubstring(responseData, "", "") + ": " + + MobileBKUHelper.extractSubstring(responseData, "", ""); + } catch (Exception e2) { + log.error("Failed to get credentials error code", e2); + msg = Messages.getString("error.Unexpected"); + } + status.errorMessage = msg.strip(); + } + } + + log.debug("sessionID: " + sessionID); + log.debug("Vergleichswert: " + refVal); + log.debug("viewState: " + viewState); + log.debug("eventValidation: " + eventValidation); + log.debug("signatureDataURL: " + signatureDataURL); + + status.sessionID = sessionID; + status.refVal = refVal; + status.viewState = viewState; + status.eventValidation = eventValidation; + status.signatureDataURL = signatureDataURL; + status.viewStateGenerator = viewstateGenerator; + } + + /* (non-Javadoc) + * @see at.asit.pdfover.gui.workflow.states.mobilebku.MobileBKUHandler#postTAN() + */ + public String postTAN() throws IOException { + ATrustStatus status = getStatus(); + + MobileBKUHelper.registerTrustedSocketFactory(); + HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); + + PostMethod post = new PostMethod(status.baseURL + + "/signature.aspx?sid=" + status.sessionID); + post.getParams().setContentCharset("utf-8"); + post.addParameter("__VIEWSTATE", status.viewState); + post.addParameter( + "__EVENTVALIDATION", status.eventValidation); + post.addParameter(status.dynAttrTan, status.tan); + post.addParameter(status.dynAttrSignButton, "Signieren"); + post.addParameter("Button1", "Identifizieren"); + + return executePost(client, post); + } + + /* (non-Javadoc) + * @see at.asit.pdfover.gui.workflow.states.mobilebku.MobileBKUHandler#handleTANResponse(java.lang.String) + */ + public void handleTANResponse(String responseData) { + getStatus().errorMessage = null; + if (responseData.contains("sl:CreateXMLSignatureResponse xmlns:sl") || + responseData.contains("sl:CreateCMSSignatureResponse xmlns:sl")) { + // success !! + + getSigningState().signatureResponse = responseData; + } else { + try { + String tries = MobileBKUHelper.extractSubstring( + responseData, "Sie haben noch", "Versuch"); + getStatus().tanTries = Integer.parseInt(tries.trim()); + getStatus().errorMessage = "mobileBKU.wrong_tan"; + } catch (Exception e) { + getStatus().tanTries = (getStatus().tanTries - 1); + log.debug("Error parsing TAN response", e); + } + + if (getStatus().tanTries <= 0) { + getStatus().errorMessage = null; + Display.getDefault().syncExec(() -> { + Dialog dialog = new Dialog(ATrustHandler.this.shell, Messages.getString("common.warning"), + Messages.getString("mobileBKU.tan_tries_exceeded"), + BUTTONS.OK_CANCEL, ICON.QUESTION); + + // TODO: THIS IS A COLOSSAL HACK + if (dialog.open() == SWT.CANCEL) { + // Go back to BKU Selection + getStatus().tanTries = -1; + } else { + // Start signature process over + getStatus().tanTries = -2; + } + }); + } + } + } + + /** + * Cancel QR process, request SMS TAN + * @return the response + * @throws IOException Error during posting + */ + public String postSMSRequest() throws IOException { + ATrustStatus status = getStatus(); + + MobileBKUHelper.registerTrustedSocketFactory(); + HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); + + GetMethod get = new GetMethod(status.baseURL + + "/sendsms.aspx?sid=" + status.sessionID); + get.getParams().setContentCharset("utf-8"); + + return executeGet(client, get); + } + + /** + * Get the QR code image + * @return the QR code image as a String + */ + public InputStream getQRCode() { + //TODO: Update HTTPClient here + + ATrustStatus status = getStatus(); + + MobileBKUHelper.registerTrustedSocketFactory(); + HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); + + GetMethod get = new GetMethod(status.baseURL + "/" + status.qrCodeURL); + + try { + log.debug("Getting " + get.getURI()); + int returnCode = client.executeMethod(get); + + if (returnCode != HttpStatus.SC_OK) { + log.error("Error getting QR code"); + return null; + } + + return get.getResponseBodyAsStream(); + } catch (Exception e) { + log.error("Error getting QR code", e); + return null; + } + } + + /** + * Get Signature page after scanning QR code + * @return the response + * @throws IOException Error during get + */ + public String getSignaturePage() throws IOException { + ATrustStatus status = getStatus(); + + MobileBKUHelper.registerTrustedSocketFactory(); + HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); + + //TODO check + //String baseURL = "https://www.a-trust.at/mobile/https-security-layer-request"; + GetMethod get = new GetMethod(status.baseURL + + "/signature.aspx?sid=" + status.sessionID); + + return executeGet(client, get); + } + + /** + * Parse QR code response + * @param responseData + * @return whether a SL response was received + */ + public boolean handleQRResponse(String responseData) { + getStatus().errorMessage = null; + if (responseData.contains("sl:CreateXMLSignatureResponse xmlns:sl") || + responseData.contains("sl:CreateCMSSignatureResponse xmlns:sl")) { + // success !! + + getSigningState().signatureResponse = responseData; + return true; + } + return false; + } + + /* + * (non-Javadoc) + * + */ + public boolean handlePolling() throws ATrustConnectionException { + + ATrustStatus status = getStatus(); + String isReady = null; + Status serverStatus = null; + HttpClient client; + try { + do { + client = MobileBKUHelper.getHttpClient(getStatus()); + String uri = status.baseURL + "/UndecidedPolling.aspx?sid=" + status.sessionID; + GetMethod get = new GetMethod(uri); + + //client.setTimeout(35000); + //client.setConnectionTimeout(35000); + get.addRequestHeader("Accept", "application/json, text/javascript"); + get.addRequestHeader("Connection", "keep-alive"); + get.addRequestHeader("Referer", uri); + + + client.executeMethod(get); + InputStream in = new BufferedInputStream(get.getResponseBodyAsStream()); + + isReady = IOUtils.toString(in, "utf-8"); + serverStatus = new Status(isReady); + + if (serverStatus.isFin()) { + return true; + } else if (serverStatus.isError()) { + log.error("A-Trust returned Error code during polling"); + throw new ATrustConnectionException(); + } + + } while (serverStatus.isWait()); + + if (serverStatus.isFin()) { + return true; + } + //else error + status.errorMessage = "Server reponded ERROR during polling"; + log.error("Server reponded ERROR during polling"); + throw new ATrustConnectionException(); + + } catch (Exception e) { + log.error("handle polling failed" + e.getMessage()); + throw new ATrustConnectionException(); + } + } + + private class Status { + private final boolean fin; + private final boolean error; + private final boolean wait; + + public Status(String status) { + JsonElement jelement = JsonParser.parseString(status.toLowerCase()); + JsonObject jobject = jelement.getAsJsonObject(); + this.fin = jobject.get("fin").getAsBoolean(); + this.error = jobject.get("error").getAsBoolean(); + this.wait = jobject.get("wait").getAsBoolean(); + } + + public boolean isFin() { + return fin; + } + + public boolean isError() { + return error; + } + + public boolean isWait() { + return wait; + } + + + + + } + +} + + diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustStatus.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustStatus.java new file mode 100644 index 00000000..22e53a57 --- /dev/null +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustStatus.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012 by A-SIT, Secure Information Technology Center Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package at.asit.pdfover.gui.bku.OLDmobile; + +// Imports +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.asit.pdfover.gui.workflow.config.ConfigurationManager; + +/** + * A-Trust MobileBKUStatus implementation + */ +public class ATrustStatus { + /** + * SLF4J Logger instance + **/ + @SuppressWarnings("unused") + private static final Logger log = LoggerFactory.getLogger(ATrustStatus.class); + + /** Maximum number of TAN tries */ + public static final int MOBILE_MAX_TAN_TRIES = 3; + + public String sessionID; + public String phoneNumber; + public String mobilePassword; + public String baseURL; + public String refVal; + public String errorMessage; + public String tan; + public String server; + public String signatureDataURL; + public int tanTries = MOBILE_MAX_TAN_TRIES; + public String viewState; + public String eventValidation; + public String qrCodeURL = null; + public boolean tanField = false; + public boolean isAPPTan = false; + public String viewStateGenerator; + public String dynAttrPhoneNumber; + public String dynAttrPassword; + public String dynAttrBtnId; + public String dynAttrTan; + public String dynAttrSignButton; + public boolean isSMSTan = false; + + /** + * Constructor + * @param provider the ConfigProvider + */ + public ATrustStatus(ConfigurationManager provider) { + this.phoneNumber = provider.getDefaultMobileNumber(); + this.mobilePassword = provider.getDefaultMobilePassword(); + } +} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/MobileBKUHelper.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/MobileBKUHelper.java new file mode 100644 index 00000000..f258fc05 --- /dev/null +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/MobileBKUHelper.java @@ -0,0 +1,318 @@ +/* + * Copyright 2012 by A-SIT, Secure Information Technology Center Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package at.asit.pdfover.gui.bku.OLDmobile; + +// Imports +import java.net.URL; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.protocol.Protocol; +import org.jsoup.nodes.Document; +import org.jsoup.select.Elements; +import org.jsoup.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.asit.pdfover.gui.bku.BKUHelper; +import at.asit.pdfover.gui.exceptions.InvalidPasswordException; +import at.asit.pdfover.gui.exceptions.PasswordTooLongException; +import at.asit.pdfover.gui.exceptions.PasswordTooShortException; + +/** + * + */ +public class MobileBKUHelper { + /** + * SLF4J Logger instance + **/ + private static final Logger log = LoggerFactory.getLogger(MobileBKUHelper.class); + + /** + * Regular expression for mobile phone numbers: this allows the entry of + * mobile numbers in the following formats: + * + * +(countryCode)99999999999 00(countryCode)99999999999 099999999999 + * 1030199999999999 (A-Trust Test bku) + */ + private static final String NUMBER_REGEX = "^((\\+[\\d]{2})|(00[\\d]{2})|(0)|(10301))([1-9][\\d]+)$"; + + /** + * Extracts a substring from data starting after start and ending with end + * + * @param data + * the whole data string + * @param start + * the start marker + * @param end + * the end marker + * @return the substring + * @throws Exception + * not found + */ + public static String extractSubstring(String data, String start, String end) + throws Exception { + int startidx = data.indexOf(start); + if (startidx > 0) { + startidx = startidx + start.length(); + int endidx = data.indexOf(end, startidx); + if (endidx > startidx) { + return data.substring(startidx, endidx); + } + log.error("extracting substring: end not valid!: " + start + " ... " + end); //// + throw new Exception("End string not available! Mobile BKU site changed?"); + } + log.error("extracting substring: start not valid!: " + start + " ... " + end); //// + throw new Exception("Start string not available! Mobile BKU site changed?"); + } + + /** + * Extracts an XML tag from data with the given param="value" + * + * @param data + * the whole data string + * @param tag + * the tag name (empty string to match all tags) + * @param param + * the parameter to look for + * @param value + * the parameter value to look for + * @return the found tag + * @throws Exception + * not found + */ + public static String extractTagWithParam(String data, String tag, + String param, String value) throws Exception { + String start = '<' + tag; + int startidx, endidx = 0; + while ((startidx = data.indexOf(start, endidx)) != -1) { + endidx = data.indexOf('>', startidx); + if (endidx == -1) { + log.error("extracting tag: unterminated tag! " + tag + " (" + param + "=" + value + ")"); //// + throw new Exception("Tag not found! Mobile BKU site changed?"); + } + String found = data.substring(startidx, endidx + 1); + if (found.contains(param + "='" + value + "'") || + found.contains(param + "=\"" + value + "\"")) + return found; + } + log.info("extracting tag: not found!: " + tag + " (" + param + "='" + value + "')"); //// + throw new Exception("Tag not found! Mobile BKU site changed?"); + } + + /** + * Extracts a parameter value from an XML tag from data with the given param="value" + * + * @param data + * the whole data string + * @param tag + * the tag name (empty string to match all tags) + * @param param + * the parameter to look for + * @param value + * the parameter value to look for + * @param returnparam + * the parameter whose value to return + * @return the found tag + * @throws Exception + * not found + */ + public static String extractValueFromTagWithParam(String data, String tag, + String param, String value, String returnparam) throws Exception { + String found = extractTagWithParam(data, tag, param, value); + int startidx = found.indexOf(returnparam + '='); + if (startidx == -1) { + log.error("extracting tag: param not found! " + tag + " (" + param + "=" + value + ") - " + returnparam); //// + throw new Exception("Tag not found! Mobile BKU site changed?"); + } + startidx += returnparam.length() + 1; + int endidx = found.indexOf(found.charAt(startidx), startidx + 1); + if (endidx == -1) { + log.error("extracting tag: unterminated param value! " + tag + " (" + param + "=" + value + ") - " + returnparam); //// + throw new Exception("Tag not found! Mobile BKU site changed?"); + } + return found.substring(startidx + 1, endidx); + } + + /** + * This method is the same as the non optional method but instead of throwing the exception it returns null + * @return the string or null + */ + public static String extractValueFromTagWithParamOptional(String data, String tag, + String param, String value, String returnparam) { + String str; + try { + str = extractValueFromTagWithParam(data, tag, param, value, returnparam); + } catch (Exception e) { + log.debug("Optional value is not available"); + str = null; + } + return str; + + } + + /** + * Extracts the content from an XML tag from data with the given param="value" + * + * @param data + * the whole data string + * @param tag + * the tag name + * @param param + * the parameter to look for + * @param value + * the parameter value to look for + * @return the found tag's content + * @throws Exception + * not found + */ + public static String extractContentFromTagWithParam(String data, String tag, + String param, String value) throws Exception { + String found = extractTagWithParam(data, tag, param, value); + int startidx = data.indexOf(found) + found.length(); + int endidx = data.indexOf("", startidx); + if (endidx == -1) { + log.error("extracting tag: closing tag not found! " + tag + " (" + param + "=" + value + ")"); //// + throw new Exception("Tag not found! Mobile BKU site changed?"); + } + return data.substring(startidx, endidx); + } + + /** + * Validates the Mobile phone number + * + * @param number + * @return the normalized Phone number + */ + public static String normalizeMobileNumber(String number) { + // Verify number and normalize + + number = number.trim(); + + String numberWithoutWhitespace = number.replaceAll("\\s",""); + // Compile and use regular expression + Pattern pattern = Pattern.compile(NUMBER_REGEX); + Matcher matcher = pattern.matcher(numberWithoutWhitespace); + + if (!matcher.find()) + return number; /* might be an idA username, return unchanged */ + + if (matcher.groupCount() != 6) { + return number; + } + + String countryCode = matcher.group(1); + + String normalNumber = matcher.group(6); + + if (countryCode.equals("10301")) { + // A-Trust Testnumber! Don't change + return numberWithoutWhitespace; + } + + countryCode = countryCode.replace("00", "+"); + + if (countryCode.equals("0")) { + countryCode = "+43"; + } + + return countryCode + normalNumber; + } + + /** + * Validate given Password for Mobile BKU + * + * @param password + * @throws InvalidPasswordException + */ + public static void validatePassword(String password) + throws InvalidPasswordException { + if (password.length() < 5 || password.length() > 200) { + if (password.length() < 6) { + throw new PasswordTooShortException(); + } + throw new PasswordTooLongException(); + } + } + + /** + * Removes file extension from URL + * + * @param url + * the url string + * @return the stripped url + */ + public static String stripQueryString(String url) { + int pathidx = url.lastIndexOf('/'); + if (pathidx > 0) { + return url.substring(0, pathidx); + } + return url; + } + + /** + * Build a fully qualified URL out of a base URL plus a URL fragment + * @param fragment the URL fragment + * @param base the base URL + * @return the fully qualified URL + */ + public static String getQualifiedURL(String fragment, URL base) { + if (fragment.startsWith("http:") || fragment.startsWith("https:")) + return fragment; + int p = base.getPort(); + String port = ((p != -1) && (p != base.getDefaultPort())) ? ":" + p : ""; + if (fragment.startsWith("/")) { + return base.getProtocol() + "://" + base.getHost() + port + fragment; + } + return stripQueryString(base.toString()) + "/" + fragment; + } + + /** + * Register our TrustedSocketFactory for https connections + */ + @SuppressWarnings("deprecation") + public static void registerTrustedSocketFactory() { + Protocol.registerProtocol("https", + new Protocol("https", new TrustedSocketFactory(), 443)); + } + + /** + * Get a HTTP Client instance + * @param status the mobile BKU status + * @return the HttpClient + */ + public static HttpClient getHttpClient(ATrustStatus status) { + return BKUHelper.getHttpClient(true); + } + + /*** + * + * @param htmlString describes the html data in String representation + * @param attributeName is the attribute which should be selected + * @return returns the attribute name or null otherswise + */ + public static String getDynamicNameAttribute(String htmlString, String attributeName) { + + Document doc = Jsoup.parse(htmlString); + Elements inputs = doc.select("div input#" + attributeName); + + if (inputs.size() == 0 ) return null; + + String name = inputs.get(0).attr("name"); + return name; + } +} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/MobileBKUs.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/MobileBKUs.java new file mode 100644 index 00000000..31339d9f --- /dev/null +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/MobileBKUs.java @@ -0,0 +1,27 @@ +/* + * Copyright 2012 by A-SIT, Secure Information Technology Center Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package at.asit.pdfover.gui.bku.OLDmobile; + +/** + * Available mobile BKUs + */ +public enum MobileBKUs { + /** A-Trust BKU */ + A_TRUST, + + /** IAIK */ + IAIK +} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/SimpleXMLTrustManager.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/SimpleXMLTrustManager.java new file mode 100644 index 00000000..5f8bec31 --- /dev/null +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/SimpleXMLTrustManager.java @@ -0,0 +1,220 @@ +/* + * Copyright 2012 by A-SIT, Secure Information Technology Center Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package at.asit.pdfover.gui.bku.OLDmobile; + +// Imports +import java.security.KeyStore; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import at.asit.pdfover.commons.Constants; + +/** + * + */ +public class SimpleXMLTrustManager implements X509TrustManager { + /** + * SLF4J Logger instance + **/ + private static final Logger log = LoggerFactory.getLogger(SimpleXMLTrustManager.class); + + /* + * The default X509TrustManager returned by SunX509. We'll delegate + * decisions to it, and fall back to the logic in this class if the default + * X509TrustManager doesn't trust it. + */ + X509TrustManager sunJSSEX509TrustManager; + + /** + * Trust Manager for A-Trust Certificates + */ + X509TrustManager atrustTrustManager; + + /** + * Constructs the TrustManager + * + * @throws Exception + */ + public SimpleXMLTrustManager() throws Exception { + // create a "default" JSSE X509TrustManager. + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init((KeyStore) null); + + TrustManager tms[] = tmf.getTrustManagers(); + + /* + * Iterate over the returned trustmanagers, look for an instance of + * X509TrustManager. If found, use that as our "default" trust manager. + */ + for (int i = 0; i < tms.length; i++) { + if (tms[i] instanceof X509TrustManager) { + this.sunJSSEX509TrustManager = (X509TrustManager) tms[i]; + break; + } + } + + /* + * Certificates + */ + + KeyStore myKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + + myKeyStore.load(null); + + Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() + .parse(this.getClass().getResourceAsStream(Constants.RES_CERT_LIST)); + Node certificates = doc.getFirstChild(); + NodeList certificateList = certificates.getChildNodes(); + + try { + if (!certificates.getNodeName().equals("certificates")) { + throw new Exception("Used certificates xml is invalid! no certificates node"); + } + + //add trusted certificates to certStore// + for (int i = 0; i < certificateList.getLength(); i++) { + try { + + Node certificateNode = certificateList.item(i); + + if (certificateNode.getNodeName().equals("#text")) { + continue; // Ignore dummy text node .. + } + + if (!certificateNode.getNodeName().equals("certificate")) { + log.warn("Ignoring XML node: " + certificateNode.getNodeName()); + continue; + } + + String certResource = Constants.RES_CERT_PATH + certificateNode.getTextContent(); + + X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X509"). + generateCertificate(this.getClass().getResourceAsStream(certResource)); + + myKeyStore.setCertificateEntry(certificateNode.getTextContent(), cert); + + log.debug("Loaded certificate : " + certResource); + + } catch (Exception ex) { + log.error("Failed to load certificate [" + "]", ex); + } + } + + } + + catch (Exception e) { + e.toString(); + } + + tmf.init(myKeyStore); + + tms = tmf.getTrustManagers(); + + /* + * Iterate over the returned trustmanagers, look for an instance of + * X509TrustManager. If found, use that as our "default" trust manager. + */ + for (int i = 0; i < tms.length; i++) { + if (tms[i] instanceof X509TrustManager) { + this.atrustTrustManager = (X509TrustManager) tms[i]; + break; + } + } + + if (this.sunJSSEX509TrustManager != null && this.atrustTrustManager != null) { + return; + } + + /* + * Find some other way to initialize, or else we have to fail the + * constructor. + */ + throw new Exception("Couldn't initialize ASITTrustManager"); + } + + /* + * (non-Javadoc) + * + * @see + * javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert. + * X509Certificate[], java.lang.String) + */ + @Override + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + try { + this.atrustTrustManager.checkServerTrusted(arg0, arg1); + } catch (CertificateException ex) { + try { + this.sunJSSEX509TrustManager.checkClientTrusted(arg0, arg1); + } catch (CertificateException ex2) { + log.info("checkClientTrusted: ", ex2); + throw ex2; + } + } + } + + /* + * (non-Javadoc) + * + * @see + * javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert. + * X509Certificate[], java.lang.String) + */ + @Override + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + try { + this.atrustTrustManager.checkServerTrusted(arg0, arg1); + } catch (CertificateException ex) { + try { + this.sunJSSEX509TrustManager.checkServerTrusted(arg0, arg1); + } catch (CertificateException ex2) { + log.info("checkServerTrusted: ", ex2); + throw ex2; + } + } + } + + /* + * (non-Javadoc) + * + * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() + */ + @Override + public X509Certificate[] getAcceptedIssuers() { + + X509Certificate[] default_certs = this.sunJSSEX509TrustManager.getAcceptedIssuers(); + + X509Certificate[] atrust_certs = this.atrustTrustManager.getAcceptedIssuers(); + + X509Certificate[] all_certs = Arrays.copyOf(default_certs, default_certs.length + atrust_certs.length); + System.arraycopy(atrust_certs, 0, all_certs, default_certs.length, atrust_certs.length); + return all_certs; + } + +} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/TrustedSocketFactory.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/TrustedSocketFactory.java new file mode 100644 index 00000000..e6402a9d --- /dev/null +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/TrustedSocketFactory.java @@ -0,0 +1,191 @@ +/* + * Copyright 2012 by A-SIT, Secure Information Technology Center Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package at.asit.pdfover.gui.bku.OLDmobile; + +// Imports +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + +import org.apache.commons.httpclient.ConnectTimeoutException; +import org.apache.commons.httpclient.params.HttpConnectionParams; +import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.asit.pdfover.commons.Messages; + +/** + * + */ +public class TrustedSocketFactory implements SecureProtocolSocketFactory { + /** + * SLF4J Logger instance + **/ + private static final Logger log = LoggerFactory.getLogger(TrustedSocketFactory.class); + + private static final String ENABLED_CS[] = { + "TLS_RSA_WITH_AES_128_CBC_SHA", + "SSL_RSA_WITH_RC4_128_SHA", + "SSL_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_RSA_WITH_RC4_128_MD5" + }; + + private static SSLSocketFactory getFactory() throws NoSuchAlgorithmException, + KeyManagementException, Exception { + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, new TrustManager[] { new SimpleXMLTrustManager() }, + new java.security.SecureRandom()); + + return sslContext.getSocketFactory(); + } + + /* + * (non-Javadoc) + * + * @see + * org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket + * (java.lang.String, int) + */ + @Override + public Socket createSocket(String host, int port) throws IOException, + UnknownHostException { + try { + SSLSocket sslSocket = (SSLSocket) getFactory().createSocket(host, + port); + sslSocket.setEnabledCipherSuites(ENABLED_CS); + return sslSocket; + } catch (Exception ex) { + log.error("TrustedSocketFactory: ", ex); + if (ex instanceof IOException) { + throw (IOException) ex; + } else if (ex instanceof UnknownHostException) { + throw (UnknownHostException) ex; + } else { + throw new IOException( + Messages.getString("TrustedSocketFactory.FailedToCreateSecureConnection"), ex); + } + } + } + + /* + * (non-Javadoc) + * + * @see + * org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket + * (java.lang.String, int, java.net.InetAddress, int) + */ + @Override + public Socket createSocket(String host, int port, InetAddress clientHost, + int clientPort) throws IOException, UnknownHostException { + try { + SSLSocket sslSocket = (SSLSocket) getFactory().createSocket(host, + port, clientHost, clientPort); + sslSocket.setEnabledCipherSuites(ENABLED_CS); + return sslSocket; + } catch (Exception ex) { + log.error("TrustedSocketFactory: ", ex); + if (ex instanceof IOException) { + throw (IOException) ex; + } else if (ex instanceof UnknownHostException) { + throw (UnknownHostException) ex; + } else { + throw new IOException( + Messages.getString("TrustedSocketFactory.FailedToCreateSecureConnection"), ex); + } + } + } + + /* + * (non-Javadoc) + * + * @see + * org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket + * (java.lang.String, int, java.net.InetAddress, int, + * org.apache.commons.httpclient.params.HttpConnectionParams) + */ + @Override + public Socket createSocket(String host, int port, InetAddress clientHost, + int clientPort, HttpConnectionParams params) throws IOException, + UnknownHostException, ConnectTimeoutException { + try { + if (params == null) { + throw new IllegalArgumentException("Parameters may not be null"); + } + int timeout = params.getConnectionTimeout(); + SSLSocket sslSocket = null; + + SSLSocketFactory socketfactory = getFactory(); + if (timeout == 0) { + sslSocket = (SSLSocket) socketfactory.createSocket(host, port, clientHost, + clientPort); + } else { + sslSocket = (SSLSocket) socketfactory.createSocket(); + SocketAddress localaddr = new InetSocketAddress(clientHost, + clientPort); + SocketAddress remoteaddr = new InetSocketAddress(host, port); + sslSocket.bind(localaddr); + sslSocket.connect(remoteaddr, timeout); + } + sslSocket.setEnabledCipherSuites(ENABLED_CS); + return sslSocket; + } catch (Exception ex) { + log.error("TrustedSocketFactory: ", ex); + if (ex instanceof IOException) { + throw (IOException) ex; + } else if (ex instanceof UnknownHostException) { + throw (UnknownHostException) ex; + } else { + throw new IOException( + Messages.getString("TrustedSocketFactory.FailedToCreateSecureConnection"), ex); + } + } + } + + /* (non-Javadoc) + * @see org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory#createSocket(java.net.Socket, java.lang.String, int, boolean) + */ + @Override + public Socket createSocket(Socket socket, String host, int port, + boolean autoClose) throws IOException, UnknownHostException { + try { + SSLSocket sslSocket = (SSLSocket) getFactory().createSocket(socket, host, port, autoClose); + sslSocket.setEnabledCipherSuites(ENABLED_CS); + return sslSocket; + } catch (Exception ex) { + log.error("TrustedSocketFactory: ", ex); + if (ex instanceof IOException) { + throw (IOException) ex; + } else if (ex instanceof UnknownHostException) { + throw (UnknownHostException) ex; + } else { + throw new IOException( + Messages.getString("TrustedSocketFactory.FailedToCreateSecureConnection"), ex); + } + } + } + +} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustHandler.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustHandler.java deleted file mode 100644 index 8697399d..00000000 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustHandler.java +++ /dev/null @@ -1,793 +0,0 @@ -/* - * Copyright 2012 by A-SIT, Secure Information Technology Center Austria - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package at.asit.pdfover.gui.bku.mobile; - -// Imports -import java.awt.Desktop; -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URL; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.multipart.FilePart; -import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; -import org.apache.commons.httpclient.methods.multipart.Part; -import org.apache.commons.httpclient.methods.multipart.StringPart; -import org.apache.commons.io.IOUtils; -import org.eclipse.swt.SWT; -import org.eclipse.swt.program.Program; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Shell; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import at.asit.pdfover.commons.Constants; -import at.asit.pdfover.gui.controls.Dialog; -import at.asit.pdfover.gui.controls.Dialog.BUTTONS; -import at.asit.pdfover.gui.controls.Dialog.ICON; -import at.asit.pdfover.gui.exceptions.ATrustConnectionException; -import at.asit.pdfover.gui.utils.FileUploadSource; -import at.asit.pdfover.commons.Messages; -import at.asit.pdfover.gui.workflow.states.LocalBKUState; -import at.asit.pdfover.gui.workflow.states.MobileBKUState; -import at.asit.pdfover.signer.pdfas.PdfAs4SLRequest; -import at.asit.pdfover.signer.pdfas.PdfAs4SigningState; - -/** - * A-Trust mobile BKU handler - */ -public class ATrustHandler { - public final MobileBKUState state; - public final Shell shell; - - /** - * @param state - * @param shell - */ - public ATrustHandler(MobileBKUState state, Shell shell) { - this.state = state; - this.shell = shell; - } - - /** - * SLF4J Logger instance - **/ - static final Logger log = LoggerFactory.getLogger(ATrustHandler.class); - - private static boolean expiryNoticeDisplayed = false; - - private static final String ACTIVATION_URL = "https://www.handy-signatur.at/"; - - /** - * Get the MobileBKUStatus - * @return the MobileBKUStatus - */ - protected ATrustStatus getStatus() { - return this.state.status; - } - - /** - * Get the SigningState - * @return the SigningState - */ - protected PdfAs4SigningState getSigningState() { - return state.getSigningState(); - } - - /** - * Execute a post to the mobile BKU, following redirects - * @param client the HttpClient - * @param post the PostMethod - * @return the response - * @throws IOException IO error - */ - protected String executePost(HttpClient client, PostMethod post) throws IOException { - if (log.isDebugEnabled()) { - String req; - if (post.getRequestEntity().getContentLength() < 1024) { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - post.getRequestEntity().writeRequest(os); - req = os.toString(); - if (req.contains("passwort=")) - req = req.replaceAll("passwort=[^&]*", "passwort=******"); - if (req.contains(":pwd=")) - req = req.replaceAll(":pwd=[^&]*", ":pwd=******"); - os.close(); - } else { - req = post.getRequestEntity().getContentLength() + " bytes"; - } - log.debug("Posting to " + post.getURI() + ": " + req); - } - int returnCode = client.executeMethod(post); - - String redirectLocation = null; - GetMethod get = null; - - - String responseData = null; - - String server = null; - - // Follow redirects - do { - // check return code - if (returnCode == HttpStatus.SC_MOVED_TEMPORARILY || - returnCode == HttpStatus.SC_MOVED_PERMANENTLY) { - - Header locationHeader = post.getResponseHeader("location"); - if (locationHeader != null) { - redirectLocation = locationHeader.getValue(); - } else { - throw new IOException( - "Got HTTP 302 but no location to follow!"); - } - } else if (returnCode == HttpStatus.SC_OK) { - if (get != null) { - responseData = get.getResponseBodyAsString(); - Header serverHeader = get.getResponseHeader( - LocalBKUState.BKU_RESPONSE_HEADER_SERVER); - if (serverHeader != null) - server = serverHeader.getValue(); - } else { - responseData = post.getResponseBodyAsString(); - - Header serverHeader = post.getResponseHeader( - LocalBKUState.BKU_RESPONSE_HEADER_SERVER); - if (serverHeader != null) - server = serverHeader.getValue(); - } - redirectLocation = null; - String p = "]*http-equiv=\"refresh\" [^>]*content=\"([^\"]*)\""; - Pattern pat = Pattern.compile(p); - Matcher m = pat.matcher(responseData); - if (m.find()) { - String content = m.group(1); - int start = content.indexOf("URL="); - if (start != -1) { - start += 9; - redirectLocation = content.substring(start, content.length() - 5); - } - } - } else { - throw new HttpException( - HttpStatus.getStatusText(returnCode)); - } - - if (redirectLocation != null) { - redirectLocation = MobileBKUHelper.getQualifiedURL(redirectLocation, new URL(post.getURI().toString())); - log.debug("Redirected to " + redirectLocation); - get = new GetMethod(redirectLocation); - get.setFollowRedirects(true); - returnCode = client.executeMethod(get); - } - } while (redirectLocation != null); - - getStatus().server = server; - if (server != null) - log.debug("Server: " + server); - - return responseData; - } - - /** - * Execute a get from the mobile BKU, following redirects - * @param client the HttpClient - * @param get the GetMethod - * @return the response - * @throws IOException IO error - */ - protected String executeGet(HttpClient client, GetMethod get) throws IOException { - log.debug("Getting " + get.getURI()); - - int returnCode = client.executeMethod(get); - - String redirectLocation = null; - - GetMethod get2 = null; - - String responseData = null; - - String server = null; - - // Follow redirects - do { - // check return code - if (returnCode == HttpStatus.SC_MOVED_TEMPORARILY || - returnCode == HttpStatus.SC_MOVED_PERMANENTLY) { - - Header locationHeader = get.getResponseHeader("location"); - if (locationHeader != null) { - redirectLocation = locationHeader.getValue(); - } else { - throw new IOException( - "Got HTTP 302 but no location to follow!"); - } - } else if (returnCode == HttpStatus.SC_OK) { - if (get2 != null) { - responseData = get2.getResponseBodyAsString(); - Header serverHeader = get2.getResponseHeader( - LocalBKUState.BKU_RESPONSE_HEADER_SERVER); - if (serverHeader != null) - server = serverHeader.getValue(); - } else { - responseData = get.getResponseBodyAsString(); - - Header serverHeader = get.getResponseHeader( - LocalBKUState.BKU_RESPONSE_HEADER_SERVER); - if (serverHeader != null) - server = serverHeader.getValue(); - } - redirectLocation = null; - String p = "]*http-equiv=\"refresh\" [^>]*content=\"([^\"]*)\""; - Pattern pat = Pattern.compile(p); - Matcher m = pat.matcher(responseData); - if (m.find()) { - String content = m.group(1); - int start = content.indexOf("URL="); - if (start != -1) { - start += 9; - redirectLocation = content.substring(start, content.length() - 5); - } - } - } else { - throw new HttpException( - HttpStatus.getStatusText(returnCode)); - } - - if (redirectLocation != null) { - redirectLocation = MobileBKUHelper.getQualifiedURL(redirectLocation, new URL(get.getURI().toString())); - log.debug("Redirected to " + redirectLocation); - get2 = new GetMethod(redirectLocation); - get2.setFollowRedirects(true); - returnCode = client.executeMethod(get2); - } - } while (redirectLocation != null); - - getStatus().server = server; - if (server != null) - log.debug("Server: " + server); - - return responseData; - } - - /** - * Post the SL request - * @param mobileBKUUrl mobile BKU URL - * @param request SLRequest - * @return the response - * @throws IOException IO error - */ - public String postSLRequest(String mobileBKUUrl, PdfAs4SLRequest request) throws IOException { - MobileBKUHelper.registerTrustedSocketFactory(); - HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); - - PostMethod post = new PostMethod(mobileBKUUrl); - String sl_request; - if (request.signatureData != null) { - sl_request = request.request; - StringPart xmlpart = new StringPart( - "XMLRequest", sl_request, "UTF-8"); - - FilePart filepart = new FilePart("fileupload", - new FileUploadSource(request.signatureData), - "application/pdf", "UTF-8"); - - Part[] parts = { xmlpart, filepart }; - - post.setRequestEntity(new MultipartRequestEntity(parts, post - .getParams())); - } else { - sl_request = request.request; - post.addParameter("XMLRequest", sl_request); - } - log.trace("SL Request: " + sl_request); - - state.status.baseURL = MobileBKUHelper.stripQueryString(mobileBKUUrl); - - return executePost(client, post); - } - - /* (non-Javadoc) - * @see at.asit.pdfover.gui.workflow.states.mobilebku.MobileBKUHandler#handleSLRequestResponse(java.lang.String) - */ - public void handleSLRequestResponse(String responseData) throws Exception { - ATrustStatus status = getStatus(); - - if (responseData.contains("", ""); - String errorMsg = MobileBKUHelper.extractSubstring(responseData, - "", ""); - throw new Exception("Error from mobile BKU: " + - errorCode + " - " + errorMsg); - } - - // Extract infos: - String sessionID = MobileBKUHelper.extractSubstring(responseData, - "identification.aspx?sid=", "\""); - - String viewState = MobileBKUHelper.extractValueFromTagWithParam( - responseData, "", "id", "__VIEWSTATE", "value"); - - String eventValidation = MobileBKUHelper.extractValueFromTagWithParam( - responseData, "", "id", "__EVENTVALIDATION", "value"); - - String viewstateGenerator = MobileBKUHelper.extractValueFromTagWithParamOptional(responseData, "", "id", "__VIEWSTATEGENERATOR", "value"); - - String dynamicAttrPhonenumber = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_PHONE_NUMBER); - String dynamicAttrPassword = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_SIGN_PASS); - String dynamicAttrButtonId = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_BTN_IDF); - String dynamicAttrTan = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_TAN); - - - log.debug("sessionID: " + sessionID); - log.debug("viewState: " + viewState); - log.debug("eventValidation: " + eventValidation); - - status.sessionID = sessionID; - status.viewState = viewState; - status.eventValidation = eventValidation; - if (viewstateGenerator != null ) { status.viewStateGenerator = viewstateGenerator; } - status.dynAttrPhoneNumber = dynamicAttrPhonenumber; - status.dynAttrPassword = dynamicAttrPassword; - status.dynAttrBtnId = dynamicAttrButtonId; - status.dynAttrTan = dynamicAttrTan; - } - - /* (non-Javadoc) - * @see at.asit.pdfover.gui.workflow.states.mobilebku.MobileBKUHandler#postCredentials() - */ - public String postCredentials() throws IOException { - ATrustStatus status = getStatus(); - - MobileBKUHelper.registerTrustedSocketFactory(); - HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); - - PostMethod post = new PostMethod(status.baseURL + "/identification.aspx?sid=" + status.sessionID); - post.getParams().setContentCharset("utf-8"); - post.addParameter("__VIEWSTATE", status.viewState); - post.addParameter("__VIEWSTATEGENERATOR", status.viewStateGenerator); - post.addParameter("__EVENTVALIDATION", status.eventValidation); - post.addParameter(status.dynAttrPhoneNumber, status.phoneNumber); - post.addParameter(status.dynAttrPassword, status.mobilePassword); - post.addParameter(status.dynAttrBtnId, "Identifizieren"); - - return executePost(client, post); - } - - /* (non-Javadoc) - * @see at.asit.pdfover.gui.workflow.states.mobilebku.MobileBKUHandler#handleCredentialsResponse(java.lang.String) - */ - public void handleCredentialsResponse(final String responseData) throws Exception { - ATrustStatus status = getStatus(); - String viewState = status.viewState; - String eventValidation = status.eventValidation; - String sessionID = status.sessionID; - String refVal = null; - String signatureDataURL = null; - String viewstateGenerator = status.viewStateGenerator; - - status.errorMessage = null; - - final Document responseDocument = Jsoup.parse(responseData); - - if (responseData.contains("ExpiresInfo.aspx?sid=")) { - // Certificate expiration interstitial - skip - if (!expiryNoticeDisplayed) { - Display.getDefault().syncExec(()-> { - Dialog d = new Dialog(ATrustHandler.this.shell, Messages.getString("common.info"), Messages.getString("mobileBKU.certExpiresSoon"), BUTTONS.YES_NO, ICON.WARNING); - if (d.open() == SWT.YES) { - log.debug("Trying to open " + ACTIVATION_URL); - if (Desktop.isDesktopSupported()) { - try { - Desktop.getDesktop().browse(new URI(ACTIVATION_URL)); - return; - } catch (Exception e) { - log.debug("Error opening URL", e); - } - } - log.info("SWT Desktop is not supported on this platform"); - Program.launch(ACTIVATION_URL); - } - }); - expiryNoticeDisplayed = true; - } - - String t_sessionID = MobileBKUHelper.extractSubstring(responseData, "ExpiresInfo.aspx?sid=", "\""); - String t_viewState = MobileBKUHelper.extractValueFromTagWithParam(responseData, "", "id", "__VIEWSTATE", "value"); - String t_eventValidation = MobileBKUHelper.extractValueFromTagWithParam(responseData, "", "id", "__EVENTVALIDATION", "value"); - - // Post again to skip - MobileBKUHelper.registerTrustedSocketFactory(); - HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); - - PostMethod post = new PostMethod(status.baseURL + "/ExpiresInfo.aspx?sid=" + t_sessionID); - post.getParams().setContentCharset("utf-8"); - post.addParameter("__VIEWSTATE", t_viewState); - post.addParameter("__EVENTVALIDATION", t_eventValidation); - post.addParameter("Button_Next", "Weiter"); - - handleCredentialsResponse(executePost(client, post)); - return; - } else if (responseData.contains("tanAppInfo.aspx?sid=")) { - // App info interstitial - skip - log.info("Skipping tan app interstitial"); - - String t_sessionID = MobileBKUHelper.extractSubstring(responseData, "tanAppInfo.aspx?sid=", "\""); - String t_viewState = MobileBKUHelper.extractValueFromTagWithParam(responseData, "", "id", "__VIEWSTATE", "value"); - String t_eventValidation = MobileBKUHelper.extractValueFromTagWithParam(responseData, "", "id", "__EVENTVALIDATION", "value"); - - // Post again to skip - MobileBKUHelper.registerTrustedSocketFactory(); - HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); - - PostMethod post = new PostMethod(status.baseURL + "/tanAppInfo.aspx?sid=" + t_sessionID); - post.getParams().setContentCharset("utf-8"); - post.addParameter("__VIEWSTATE", t_viewState); - post.addParameter("__EVENTVALIDATION", t_eventValidation); - post.addParameter("NextBtn", "Weiter"); - - handleCredentialsResponse(executePost(client, post)); - return; - } - - if (responseData.contains("signature.aspx?sid=")) { - // credentials ok! TAN entry - state.rememberCredentialsIfNecessary(); - log.debug("Credentials accepted - TAN required"); - sessionID = MobileBKUHelper.extractSubstring(responseData, "signature.aspx?sid=", "\""); - viewState = MobileBKUHelper.extractValueFromTagWithParam(responseData, "", "id", "__VIEWSTATE", "value"); - eventValidation = MobileBKUHelper.extractValueFromTagWithParam(responseData, "", "id", "__EVENTVALIDATION", "value"); - refVal = MobileBKUHelper.extractSubstring(responseData, "id='vergleichswert'>Vergleichswert:", ""); - signatureDataURL = status.baseURL + "/ShowSigobj.aspx" + - MobileBKUHelper.extractSubstring(responseData, "ShowSigobj.aspx", "'"); - try { - String qrCode = MobileBKUHelper.extractValueFromTagWithParam(responseData, "img", "class", "qrcode", "src"); - log.debug("QR Code found: " + qrCode); - status.qrCodeURL = qrCode; - } catch (Exception e) { - log.debug("No QR Code found"); - } - try { - String tanTextTan = MobileBKUHelper.extractValueFromTagWithParam(responseData, "label", "id", "label_for_input_tan", "for"); - status.tanField = tanTextTan.equals("input_tan"); - status.dynAttrTan = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_TAN); - status.dynAttrSignButton = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_SIGN_BTN); - } catch (Exception e) { - log.debug("No tan field found"); - } - try { - String tanTextTan = MobileBKUHelper.extractContentFromTagWithParam(responseData, "span", "id", "text_tan"); - status.isAPPTan = !tanTextTan.toLowerCase().contains("sms"); - status.dynAttrTan = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_TAN); - status.dynAttrSignButton = MobileBKUHelper.getDynamicNameAttribute(responseData, Constants.LABEL_SIGN_BTN); - }catch (Exception e) { - log.debug("No text_tan tag"); - } - try { - String webauthnLink = MobileBKUHelper.extractValueFromTagWithParam(responseData, "a", "id", "FidoButton", "href"); - log.info("Webauthn link: {}", webauthnLink); - } catch (Exception e) { - log.info("No webauthnLink"); - } - try { - String webauthnData = MobileBKUHelper.extractValueFromTagWithParam(responseData, "input", "id", "credentialOptions", "value"); - log.info("Fido credential options: {}", webauthnData); - } catch (Exception e) { - log.info("No webauthnData"); - } - - } else if (responseData.contains("sl:InfoboxReadResponse")) { - // credentials ok! InfoboxReadResponse - state.rememberCredentialsIfNecessary(); - log.debug("Credentials accepted - Response given"); - getSigningState().signatureResponse = responseData; - return; - } else if (responseData.contains("undecided.aspx?sid=")) { - // skip intermediate page - log.debug("Page Undecided"); - getSigningState().signatureResponse = responseData; - status.errorMessage = "waiting..."; // TODO: this looks incorrect...? - return; - }else { - // error page - - // force UI again! - state.clearRememberedCredentials(); - // extract error text! - try { - String errorMessage = MobileBKUHelper.extractContentFromTagWithParam(responseData, "span", "id", "Label1"); - if (errorMessage.startsWith("Fehler: ")) - errorMessage = errorMessage.substring(8); - status.errorMessage = errorMessage.strip(); - } catch (Exception e) { - log.error("Failed to get credentials error message", e); - String msg = null; - try - { - msg = MobileBKUHelper.extractSubstring(responseData, "", "") + ": " + - MobileBKUHelper.extractSubstring(responseData, "", ""); - } catch (Exception e2) { - log.error("Failed to get credentials error code", e2); - msg = Messages.getString("error.Unexpected"); - } - status.errorMessage = msg.strip(); - } - } - - log.debug("sessionID: " + sessionID); - log.debug("Vergleichswert: " + refVal); - log.debug("viewState: " + viewState); - log.debug("eventValidation: " + eventValidation); - log.debug("signatureDataURL: " + signatureDataURL); - - status.sessionID = sessionID; - status.refVal = refVal; - status.viewState = viewState; - status.eventValidation = eventValidation; - status.signatureDataURL = signatureDataURL; - status.viewStateGenerator = viewstateGenerator; - } - - /* (non-Javadoc) - * @see at.asit.pdfover.gui.workflow.states.mobilebku.MobileBKUHandler#postTAN() - */ - public String postTAN() throws IOException { - ATrustStatus status = getStatus(); - - MobileBKUHelper.registerTrustedSocketFactory(); - HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); - - PostMethod post = new PostMethod(status.baseURL - + "/signature.aspx?sid=" + status.sessionID); - post.getParams().setContentCharset("utf-8"); - post.addParameter("__VIEWSTATE", status.viewState); - post.addParameter( - "__EVENTVALIDATION", status.eventValidation); - post.addParameter(status.dynAttrTan, status.tan); - post.addParameter(status.dynAttrSignButton, "Signieren"); - post.addParameter("Button1", "Identifizieren"); - - return executePost(client, post); - } - - /* (non-Javadoc) - * @see at.asit.pdfover.gui.workflow.states.mobilebku.MobileBKUHandler#handleTANResponse(java.lang.String) - */ - public void handleTANResponse(String responseData) { - getStatus().errorMessage = null; - if (responseData.contains("sl:CreateXMLSignatureResponse xmlns:sl") || - responseData.contains("sl:CreateCMSSignatureResponse xmlns:sl")) { - // success !! - - getSigningState().signatureResponse = responseData; - } else { - try { - String tries = MobileBKUHelper.extractSubstring( - responseData, "Sie haben noch", "Versuch"); - getStatus().tanTries = Integer.parseInt(tries.trim()); - getStatus().errorMessage = "mobileBKU.wrong_tan"; - } catch (Exception e) { - getStatus().tanTries = (getStatus().tanTries - 1); - log.debug("Error parsing TAN response", e); - } - - if (getStatus().tanTries <= 0) { - getStatus().errorMessage = null; - Display.getDefault().syncExec(() -> { - Dialog dialog = new Dialog(ATrustHandler.this.shell, Messages.getString("common.warning"), - Messages.getString("mobileBKU.tan_tries_exceeded"), - BUTTONS.OK_CANCEL, ICON.QUESTION); - - // TODO: THIS IS A COLOSSAL HACK - if (dialog.open() == SWT.CANCEL) { - // Go back to BKU Selection - getStatus().tanTries = -1; - } else { - // Start signature process over - getStatus().tanTries = -2; - } - }); - } - } - } - - /** - * Cancel QR process, request SMS TAN - * @return the response - * @throws IOException Error during posting - */ - public String postSMSRequest() throws IOException { - ATrustStatus status = getStatus(); - - MobileBKUHelper.registerTrustedSocketFactory(); - HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); - - GetMethod get = new GetMethod(status.baseURL - + "/sendsms.aspx?sid=" + status.sessionID); - get.getParams().setContentCharset("utf-8"); - - return executeGet(client, get); - } - - /** - * Get the QR code image - * @return the QR code image as a String - */ - public InputStream getQRCode() { - //TODO: Update HTTPClient here - - ATrustStatus status = getStatus(); - - MobileBKUHelper.registerTrustedSocketFactory(); - HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); - - GetMethod get = new GetMethod(status.baseURL + "/" + status.qrCodeURL); - - try { - log.debug("Getting " + get.getURI()); - int returnCode = client.executeMethod(get); - - if (returnCode != HttpStatus.SC_OK) { - log.error("Error getting QR code"); - return null; - } - - return get.getResponseBodyAsStream(); - } catch (Exception e) { - log.error("Error getting QR code", e); - return null; - } - } - - /** - * Get Signature page after scanning QR code - * @return the response - * @throws IOException Error during get - */ - public String getSignaturePage() throws IOException { - ATrustStatus status = getStatus(); - - MobileBKUHelper.registerTrustedSocketFactory(); - HttpClient client = MobileBKUHelper.getHttpClient(getStatus()); - - //TODO check - //String baseURL = "https://www.a-trust.at/mobile/https-security-layer-request"; - GetMethod get = new GetMethod(status.baseURL - + "/signature.aspx?sid=" + status.sessionID); - - return executeGet(client, get); - } - - /** - * Parse QR code response - * @param responseData - * @return whether a SL response was received - */ - public boolean handleQRResponse(String responseData) { - getStatus().errorMessage = null; - if (responseData.contains("sl:CreateXMLSignatureResponse xmlns:sl") || - responseData.contains("sl:CreateCMSSignatureResponse xmlns:sl")) { - // success !! - - getSigningState().signatureResponse = responseData; - return true; - } - return false; - } - - /* - * (non-Javadoc) - * - */ - public boolean handlePolling() throws ATrustConnectionException { - - ATrustStatus status = getStatus(); - String isReady = null; - Status serverStatus = null; - HttpClient client; - try { - do { - client = MobileBKUHelper.getHttpClient(getStatus()); - String uri = status.baseURL + "/UndecidedPolling.aspx?sid=" + status.sessionID; - GetMethod get = new GetMethod(uri); - - //client.setTimeout(35000); - //client.setConnectionTimeout(35000); - get.addRequestHeader("Accept", "application/json, text/javascript"); - get.addRequestHeader("Connection", "keep-alive"); - get.addRequestHeader("Referer", uri); - - - client.executeMethod(get); - InputStream in = new BufferedInputStream(get.getResponseBodyAsStream()); - - isReady = IOUtils.toString(in, "utf-8"); - serverStatus = new Status(isReady); - - if (serverStatus.isFin()) { - return true; - } else if (serverStatus.isError()) { - log.error("A-Trust returned Error code during polling"); - throw new ATrustConnectionException(); - } - - } while (serverStatus.isWait()); - - if (serverStatus.isFin()) { - return true; - } - //else error - status.errorMessage = "Server reponded ERROR during polling"; - log.error("Server reponded ERROR during polling"); - throw new ATrustConnectionException(); - - } catch (Exception e) { - log.error("handle polling failed" + e.getMessage()); - throw new ATrustConnectionException(); - } - } - - private class Status { - private final boolean fin; - private final boolean error; - private final boolean wait; - - public Status(String status) { - JsonElement jelement = JsonParser.parseString(status.toLowerCase()); - JsonObject jobject = jelement.getAsJsonObject(); - this.fin = jobject.get("fin").getAsBoolean(); - this.error = jobject.get("error").getAsBoolean(); - this.wait = jobject.get("wait").getAsBoolean(); - } - - public boolean isFin() { - return fin; - } - - public boolean isError() { - return error; - } - - public boolean isWait() { - return wait; - } - - - - - } - -} - - diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustStatus.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustStatus.java deleted file mode 100644 index 51c08992..00000000 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustStatus.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2012 by A-SIT, Secure Information Technology Center Austria - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package at.asit.pdfover.gui.bku.mobile; - -// Imports -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.asit.pdfover.gui.workflow.config.ConfigurationManager; - -/** - * A-Trust MobileBKUStatus implementation - */ -public class ATrustStatus { - /** - * SLF4J Logger instance - **/ - @SuppressWarnings("unused") - private static final Logger log = LoggerFactory.getLogger(ATrustStatus.class); - - /** Maximum number of TAN tries */ - public static final int MOBILE_MAX_TAN_TRIES = 3; - - public String sessionID; - public String phoneNumber; - public String mobilePassword; - public String baseURL; - public String refVal; - public String errorMessage; - public String tan; - public String server; - public String signatureDataURL; - public int tanTries = MOBILE_MAX_TAN_TRIES; - public String viewState; - public String eventValidation; - public String qrCodeURL = null; - public boolean tanField = false; - public boolean isAPPTan = false; - public String viewStateGenerator; - public String dynAttrPhoneNumber; - public String dynAttrPassword; - public String dynAttrBtnId; - public String dynAttrTan; - public String dynAttrSignButton; - public boolean isSMSTan = false; - - /** - * Constructor - * @param provider the ConfigProvider - */ - public ATrustStatus(ConfigurationManager provider) { - this.phoneNumber = provider.getDefaultMobileNumber(); - this.mobilePassword = provider.getDefaultMobilePassword(); - } -} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/MobileBKUHelper.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/MobileBKUHelper.java deleted file mode 100644 index bb607be2..00000000 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/MobileBKUHelper.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright 2012 by A-SIT, Secure Information Technology Center Austria - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package at.asit.pdfover.gui.bku.mobile; - -// Imports -import java.net.URL; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.protocol.Protocol; -import org.jsoup.nodes.Document; -import org.jsoup.select.Elements; -import org.jsoup.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.asit.pdfover.gui.bku.BKUHelper; -import at.asit.pdfover.gui.exceptions.InvalidPasswordException; -import at.asit.pdfover.gui.exceptions.PasswordTooLongException; -import at.asit.pdfover.gui.exceptions.PasswordTooShortException; - -/** - * - */ -public class MobileBKUHelper { - /** - * SLF4J Logger instance - **/ - private static final Logger log = LoggerFactory.getLogger(MobileBKUHelper.class); - - /** - * Regular expression for mobile phone numbers: this allows the entry of - * mobile numbers in the following formats: - * - * +(countryCode)99999999999 00(countryCode)99999999999 099999999999 - * 1030199999999999 (A-Trust Test bku) - */ - private static final String NUMBER_REGEX = "^((\\+[\\d]{2})|(00[\\d]{2})|(0)|(10301))([1-9][\\d]+)$"; - - /** - * Extracts a substring from data starting after start and ending with end - * - * @param data - * the whole data string - * @param start - * the start marker - * @param end - * the end marker - * @return the substring - * @throws Exception - * not found - */ - public static String extractSubstring(String data, String start, String end) - throws Exception { - int startidx = data.indexOf(start); - if (startidx > 0) { - startidx = startidx + start.length(); - int endidx = data.indexOf(end, startidx); - if (endidx > startidx) { - return data.substring(startidx, endidx); - } - log.error("extracting substring: end not valid!: " + start + " ... " + end); //// - throw new Exception("End string not available! Mobile BKU site changed?"); - } - log.error("extracting substring: start not valid!: " + start + " ... " + end); //// - throw new Exception("Start string not available! Mobile BKU site changed?"); - } - - /** - * Extracts an XML tag from data with the given param="value" - * - * @param data - * the whole data string - * @param tag - * the tag name (empty string to match all tags) - * @param param - * the parameter to look for - * @param value - * the parameter value to look for - * @return the found tag - * @throws Exception - * not found - */ - public static String extractTagWithParam(String data, String tag, - String param, String value) throws Exception { - String start = '<' + tag; - int startidx, endidx = 0; - while ((startidx = data.indexOf(start, endidx)) != -1) { - endidx = data.indexOf('>', startidx); - if (endidx == -1) { - log.error("extracting tag: unterminated tag! " + tag + " (" + param + "=" + value + ")"); //// - throw new Exception("Tag not found! Mobile BKU site changed?"); - } - String found = data.substring(startidx, endidx + 1); - if (found.contains(param + "='" + value + "'") || - found.contains(param + "=\"" + value + "\"")) - return found; - } - log.info("extracting tag: not found!: " + tag + " (" + param + "='" + value + "')"); //// - throw new Exception("Tag not found! Mobile BKU site changed?"); - } - - /** - * Extracts a parameter value from an XML tag from data with the given param="value" - * - * @param data - * the whole data string - * @param tag - * the tag name (empty string to match all tags) - * @param param - * the parameter to look for - * @param value - * the parameter value to look for - * @param returnparam - * the parameter whose value to return - * @return the found tag - * @throws Exception - * not found - */ - public static String extractValueFromTagWithParam(String data, String tag, - String param, String value, String returnparam) throws Exception { - String found = extractTagWithParam(data, tag, param, value); - int startidx = found.indexOf(returnparam + '='); - if (startidx == -1) { - log.error("extracting tag: param not found! " + tag + " (" + param + "=" + value + ") - " + returnparam); //// - throw new Exception("Tag not found! Mobile BKU site changed?"); - } - startidx += returnparam.length() + 1; - int endidx = found.indexOf(found.charAt(startidx), startidx + 1); - if (endidx == -1) { - log.error("extracting tag: unterminated param value! " + tag + " (" + param + "=" + value + ") - " + returnparam); //// - throw new Exception("Tag not found! Mobile BKU site changed?"); - } - return found.substring(startidx + 1, endidx); - } - - /** - * This method is the same as the non optional method but instead of throwing the exception it returns null - * @return the string or null - */ - public static String extractValueFromTagWithParamOptional(String data, String tag, - String param, String value, String returnparam) { - String str; - try { - str = extractValueFromTagWithParam(data, tag, param, value, returnparam); - } catch (Exception e) { - log.debug("Optional value is not available"); - str = null; - } - return str; - - } - - /** - * Extracts the content from an XML tag from data with the given param="value" - * - * @param data - * the whole data string - * @param tag - * the tag name - * @param param - * the parameter to look for - * @param value - * the parameter value to look for - * @return the found tag's content - * @throws Exception - * not found - */ - public static String extractContentFromTagWithParam(String data, String tag, - String param, String value) throws Exception { - String found = extractTagWithParam(data, tag, param, value); - int startidx = data.indexOf(found) + found.length(); - int endidx = data.indexOf("", startidx); - if (endidx == -1) { - log.error("extracting tag: closing tag not found! " + tag + " (" + param + "=" + value + ")"); //// - throw new Exception("Tag not found! Mobile BKU site changed?"); - } - return data.substring(startidx, endidx); - } - - /** - * Validates the Mobile phone number - * - * @param number - * @return the normalized Phone number - */ - public static String normalizeMobileNumber(String number) { - // Verify number and normalize - - number = number.trim(); - - String numberWithoutWhitespace = number.replaceAll("\\s",""); - // Compile and use regular expression - Pattern pattern = Pattern.compile(NUMBER_REGEX); - Matcher matcher = pattern.matcher(numberWithoutWhitespace); - - if (!matcher.find()) - return number; /* might be an idA username, return unchanged */ - - if (matcher.groupCount() != 6) { - return number; - } - - String countryCode = matcher.group(1); - - String normalNumber = matcher.group(6); - - if (countryCode.equals("10301")) { - // A-Trust Testnumber! Don't change - return numberWithoutWhitespace; - } - - countryCode = countryCode.replace("00", "+"); - - if (countryCode.equals("0")) { - countryCode = "+43"; - } - - return countryCode + normalNumber; - } - - /** - * Validate given Password for Mobile BKU - * - * @param password - * @throws InvalidPasswordException - */ - public static void validatePassword(String password) - throws InvalidPasswordException { - if (password.length() < 5 || password.length() > 200) { - if (password.length() < 6) { - throw new PasswordTooShortException(); - } - throw new PasswordTooLongException(); - } - } - - /** - * Removes file extension from URL - * - * @param url - * the url string - * @return the stripped url - */ - public static String stripQueryString(String url) { - int pathidx = url.lastIndexOf('/'); - if (pathidx > 0) { - return url.substring(0, pathidx); - } - return url; - } - - /** - * Build a fully qualified URL out of a base URL plus a URL fragment - * @param fragment the URL fragment - * @param base the base URL - * @return the fully qualified URL - */ - public static String getQualifiedURL(String fragment, URL base) { - if (fragment.startsWith("http:") || fragment.startsWith("https:")) - return fragment; - int p = base.getPort(); - String port = ((p != -1) && (p != base.getDefaultPort())) ? ":" + p : ""; - if (fragment.startsWith("/")) { - return base.getProtocol() + "://" + base.getHost() + port + fragment; - } - return stripQueryString(base.toString()) + "/" + fragment; - } - - /** - * Register our TrustedSocketFactory for https connections - */ - @SuppressWarnings("deprecation") - public static void registerTrustedSocketFactory() { - Protocol.registerProtocol("https", - new Protocol("https", new TrustedSocketFactory(), 443)); - } - - /** - * Get a HTTP Client instance - * @param status the mobile BKU status - * @return the HttpClient - */ - public static HttpClient getHttpClient(ATrustStatus status) { - return BKUHelper.getHttpClient(true); - } - - /*** - * - * @param htmlString describes the html data in String representation - * @param attributeName is the attribute which should be selected - * @return returns the attribute name or null otherswise - */ - public static String getDynamicNameAttribute(String htmlString, String attributeName) { - - Document doc = Jsoup.parse(htmlString); - Elements inputs = doc.select("div input#" + attributeName); - - if (inputs.size() == 0 ) return null; - - String name = inputs.get(0).attr("name"); - return name; - } -} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/MobileBKUs.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/MobileBKUs.java deleted file mode 100644 index e0c890da..00000000 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/MobileBKUs.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2012 by A-SIT, Secure Information Technology Center Austria - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package at.asit.pdfover.gui.bku.mobile; - -/** - * Available mobile BKUs - */ -public enum MobileBKUs { - /** A-Trust BKU */ - A_TRUST, - - /** IAIK */ - IAIK -} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/SimpleXMLTrustManager.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/SimpleXMLTrustManager.java deleted file mode 100644 index ca57dc87..00000000 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/SimpleXMLTrustManager.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 2012 by A-SIT, Secure Information Technology Center Austria - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package at.asit.pdfover.gui.bku.mobile; - -// Imports -import java.security.KeyStore; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import at.asit.pdfover.commons.Constants; - -/** - * - */ -public class SimpleXMLTrustManager implements X509TrustManager { - /** - * SLF4J Logger instance - **/ - private static final Logger log = LoggerFactory.getLogger(SimpleXMLTrustManager.class); - - /* - * The default X509TrustManager returned by SunX509. We'll delegate - * decisions to it, and fall back to the logic in this class if the default - * X509TrustManager doesn't trust it. - */ - X509TrustManager sunJSSEX509TrustManager; - - /** - * Trust Manager for A-Trust Certificates - */ - X509TrustManager atrustTrustManager; - - /** - * Constructs the TrustManager - * - * @throws Exception - */ - public SimpleXMLTrustManager() throws Exception { - // create a "default" JSSE X509TrustManager. - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init((KeyStore) null); - - TrustManager tms[] = tmf.getTrustManagers(); - - /* - * Iterate over the returned trustmanagers, look for an instance of - * X509TrustManager. If found, use that as our "default" trust manager. - */ - for (int i = 0; i < tms.length; i++) { - if (tms[i] instanceof X509TrustManager) { - this.sunJSSEX509TrustManager = (X509TrustManager) tms[i]; - break; - } - } - - /* - * Certificates - */ - - KeyStore myKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - - myKeyStore.load(null); - - Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() - .parse(this.getClass().getResourceAsStream(Constants.RES_CERT_LIST)); - Node certificates = doc.getFirstChild(); - NodeList certificateList = certificates.getChildNodes(); - - try { - if (!certificates.getNodeName().equals("certificates")) { - throw new Exception("Used certificates xml is invalid! no certificates node"); - } - - //add trusted certificates to certStore// - for (int i = 0; i < certificateList.getLength(); i++) { - try { - - Node certificateNode = certificateList.item(i); - - if (certificateNode.getNodeName().equals("#text")) { - continue; // Ignore dummy text node .. - } - - if (!certificateNode.getNodeName().equals("certificate")) { - log.warn("Ignoring XML node: " + certificateNode.getNodeName()); - continue; - } - - String certResource = Constants.RES_CERT_PATH + certificateNode.getTextContent(); - - X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X509"). - generateCertificate(this.getClass().getResourceAsStream(certResource)); - - myKeyStore.setCertificateEntry(certificateNode.getTextContent(), cert); - - log.debug("Loaded certificate : " + certResource); - - } catch (Exception ex) { - log.error("Failed to load certificate [" + "]", ex); - } - } - - } - - catch (Exception e) { - e.toString(); - } - - tmf.init(myKeyStore); - - tms = tmf.getTrustManagers(); - - /* - * Iterate over the returned trustmanagers, look for an instance of - * X509TrustManager. If found, use that as our "default" trust manager. - */ - for (int i = 0; i < tms.length; i++) { - if (tms[i] instanceof X509TrustManager) { - this.atrustTrustManager = (X509TrustManager) tms[i]; - break; - } - } - - if (this.sunJSSEX509TrustManager != null && this.atrustTrustManager != null) { - return; - } - - /* - * Find some other way to initialize, or else we have to fail the - * constructor. - */ - throw new Exception("Couldn't initialize ASITTrustManager"); - } - - /* - * (non-Javadoc) - * - * @see - * javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert. - * X509Certificate[], java.lang.String) - */ - @Override - public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { - try { - this.atrustTrustManager.checkServerTrusted(arg0, arg1); - } catch (CertificateException ex) { - try { - this.sunJSSEX509TrustManager.checkClientTrusted(arg0, arg1); - } catch (CertificateException ex2) { - log.info("checkClientTrusted: ", ex2); - throw ex2; - } - } - } - - /* - * (non-Javadoc) - * - * @see - * javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert. - * X509Certificate[], java.lang.String) - */ - @Override - public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { - try { - this.atrustTrustManager.checkServerTrusted(arg0, arg1); - } catch (CertificateException ex) { - try { - this.sunJSSEX509TrustManager.checkServerTrusted(arg0, arg1); - } catch (CertificateException ex2) { - log.info("checkServerTrusted: ", ex2); - throw ex2; - } - } - } - - /* - * (non-Javadoc) - * - * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() - */ - @Override - public X509Certificate[] getAcceptedIssuers() { - - X509Certificate[] default_certs = this.sunJSSEX509TrustManager.getAcceptedIssuers(); - - X509Certificate[] atrust_certs = this.atrustTrustManager.getAcceptedIssuers(); - - X509Certificate[] all_certs = Arrays.copyOf(default_certs, default_certs.length + atrust_certs.length); - System.arraycopy(atrust_certs, 0, all_certs, default_certs.length, atrust_certs.length); - return all_certs; - } - -} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/TrustedSocketFactory.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/TrustedSocketFactory.java deleted file mode 100644 index 3dae25c9..00000000 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/TrustedSocketFactory.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright 2012 by A-SIT, Secure Information Technology Center Austria - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package at.asit.pdfover.gui.bku.mobile; - -// Imports -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.UnknownHostException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; - -import org.apache.commons.httpclient.ConnectTimeoutException; -import org.apache.commons.httpclient.params.HttpConnectionParams; -import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.asit.pdfover.commons.Messages; - -/** - * - */ -public class TrustedSocketFactory implements SecureProtocolSocketFactory { - /** - * SLF4J Logger instance - **/ - private static final Logger log = LoggerFactory.getLogger(TrustedSocketFactory.class); - - private static final String ENABLED_CS[] = { - "TLS_RSA_WITH_AES_128_CBC_SHA", - "SSL_RSA_WITH_RC4_128_SHA", - "SSL_RSA_WITH_3DES_EDE_CBC_SHA", - "SSL_RSA_WITH_RC4_128_MD5" - }; - - private static SSLSocketFactory getFactory() throws NoSuchAlgorithmException, - KeyManagementException, Exception { - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, new TrustManager[] { new SimpleXMLTrustManager() }, - new java.security.SecureRandom()); - - return sslContext.getSocketFactory(); - } - - /* - * (non-Javadoc) - * - * @see - * org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket - * (java.lang.String, int) - */ - @Override - public Socket createSocket(String host, int port) throws IOException, - UnknownHostException { - try { - SSLSocket sslSocket = (SSLSocket) getFactory().createSocket(host, - port); - sslSocket.setEnabledCipherSuites(ENABLED_CS); - return sslSocket; - } catch (Exception ex) { - log.error("TrustedSocketFactory: ", ex); - if (ex instanceof IOException) { - throw (IOException) ex; - } else if (ex instanceof UnknownHostException) { - throw (UnknownHostException) ex; - } else { - throw new IOException( - Messages.getString("TrustedSocketFactory.FailedToCreateSecureConnection"), ex); - } - } - } - - /* - * (non-Javadoc) - * - * @see - * org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket - * (java.lang.String, int, java.net.InetAddress, int) - */ - @Override - public Socket createSocket(String host, int port, InetAddress clientHost, - int clientPort) throws IOException, UnknownHostException { - try { - SSLSocket sslSocket = (SSLSocket) getFactory().createSocket(host, - port, clientHost, clientPort); - sslSocket.setEnabledCipherSuites(ENABLED_CS); - return sslSocket; - } catch (Exception ex) { - log.error("TrustedSocketFactory: ", ex); - if (ex instanceof IOException) { - throw (IOException) ex; - } else if (ex instanceof UnknownHostException) { - throw (UnknownHostException) ex; - } else { - throw new IOException( - Messages.getString("TrustedSocketFactory.FailedToCreateSecureConnection"), ex); - } - } - } - - /* - * (non-Javadoc) - * - * @see - * org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket - * (java.lang.String, int, java.net.InetAddress, int, - * org.apache.commons.httpclient.params.HttpConnectionParams) - */ - @Override - public Socket createSocket(String host, int port, InetAddress clientHost, - int clientPort, HttpConnectionParams params) throws IOException, - UnknownHostException, ConnectTimeoutException { - try { - if (params == null) { - throw new IllegalArgumentException("Parameters may not be null"); - } - int timeout = params.getConnectionTimeout(); - SSLSocket sslSocket = null; - - SSLSocketFactory socketfactory = getFactory(); - if (timeout == 0) { - sslSocket = (SSLSocket) socketfactory.createSocket(host, port, clientHost, - clientPort); - } else { - sslSocket = (SSLSocket) socketfactory.createSocket(); - SocketAddress localaddr = new InetSocketAddress(clientHost, - clientPort); - SocketAddress remoteaddr = new InetSocketAddress(host, port); - sslSocket.bind(localaddr); - sslSocket.connect(remoteaddr, timeout); - } - sslSocket.setEnabledCipherSuites(ENABLED_CS); - return sslSocket; - } catch (Exception ex) { - log.error("TrustedSocketFactory: ", ex); - if (ex instanceof IOException) { - throw (IOException) ex; - } else if (ex instanceof UnknownHostException) { - throw (UnknownHostException) ex; - } else { - throw new IOException( - Messages.getString("TrustedSocketFactory.FailedToCreateSecureConnection"), ex); - } - } - } - - /* (non-Javadoc) - * @see org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory#createSocket(java.net.Socket, java.lang.String, int, boolean) - */ - @Override - public Socket createSocket(Socket socket, String host, int port, - boolean autoClose) throws IOException, UnknownHostException { - try { - SSLSocket sslSocket = (SSLSocket) getFactory().createSocket(socket, host, port, autoClose); - sslSocket.setEnabledCipherSuites(ENABLED_CS); - return sslSocket; - } catch (Exception ex) { - log.error("TrustedSocketFactory: ", ex); - if (ex instanceof IOException) { - throw (IOException) ex; - } else if (ex instanceof UnknownHostException) { - throw (UnknownHostException) ex; - } else { - throw new IOException( - Messages.getString("TrustedSocketFactory.FailedToCreateSecureConnection"), ex); - } - } - } - -} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/cliarguments/PasswordArgument.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/cliarguments/PasswordArgument.java index aef07e1f..3ffb57b4 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/cliarguments/PasswordArgument.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/cliarguments/PasswordArgument.java @@ -19,7 +19,7 @@ package at.asit.pdfover.gui.cliarguments; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.asit.pdfover.gui.bku.mobile.MobileBKUHelper; +import at.asit.pdfover.gui.bku.OLDmobile.MobileBKUHelper; import at.asit.pdfover.gui.exceptions.InitializationException; import at.asit.pdfover.commons.Messages; diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/cliarguments/PhoneNumberArgument.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/cliarguments/PhoneNumberArgument.java index a4eff37a..c9ae045c 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/cliarguments/PhoneNumberArgument.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/cliarguments/PhoneNumberArgument.java @@ -19,7 +19,7 @@ package at.asit.pdfover.gui.cliarguments; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.asit.pdfover.gui.bku.mobile.MobileBKUHelper; +import at.asit.pdfover.gui.bku.OLDmobile.MobileBKUHelper; import at.asit.pdfover.gui.exceptions.InitializationException; import at.asit.pdfover.commons.Messages; diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/MobileBKUEnterNumberComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/MobileBKUEnterNumberComposite.java index 2a5b3e9c..5f228bcb 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/MobileBKUEnterNumberComposite.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/MobileBKUEnterNumberComposite.java @@ -32,7 +32,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.asit.pdfover.commons.Constants; -import at.asit.pdfover.gui.bku.mobile.MobileBKUHelper; +import at.asit.pdfover.gui.bku.OLDmobile.MobileBKUHelper; import at.asit.pdfover.gui.exceptions.InvalidPasswordException; import at.asit.pdfover.gui.utils.SWTUtils; import at.asit.pdfover.commons.Messages; diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/config/ConfigurationDataInMemory.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/config/ConfigurationDataInMemory.java index 71cf5567..75fe5f89 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/config/ConfigurationDataInMemory.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/config/ConfigurationDataInMemory.java @@ -30,7 +30,7 @@ import org.slf4j.LoggerFactory; import at.asit.pdfover.commons.BKUs; import at.asit.pdfover.commons.Constants; -import at.asit.pdfover.gui.bku.mobile.MobileBKUHelper; +import at.asit.pdfover.gui.bku.OLDmobile.MobileBKUHelper; import at.asit.pdfover.gui.exceptions.InvalidEmblemFile; import at.asit.pdfover.gui.exceptions.InvalidPortException; diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/config/ConfigurationManager.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/config/ConfigurationManager.java index ada3970f..37a44e71 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/config/ConfigurationManager.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/config/ConfigurationManager.java @@ -32,7 +32,7 @@ import org.slf4j.LoggerFactory; import at.asit.pdfover.commons.BKUs; import at.asit.pdfover.commons.Constants; -import at.asit.pdfover.gui.bku.mobile.MobileBKUs; +import at.asit.pdfover.gui.bku.OLDmobile.MobileBKUs; import at.asit.pdfover.gui.exceptions.InvalidEmblemFile; import at.asit.pdfover.gui.exceptions.InvalidPortException; import at.asit.pdfover.gui.utils.LocaleSerializer; diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/MobileBKUState.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/MobileBKUState.java index d84d5a50..26be4626 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/MobileBKUState.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/MobileBKUState.java @@ -21,9 +21,14 @@ import java.net.UnknownHostException; import java.util.Timer; import java.util.TimerTask; +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + // Imports import at.asit.pdfover.gui.exceptions.ATrustConnectionException; import at.asit.pdfover.signer.SignatureException; +import at.asit.pdfover.signer.UserCancelledException; import at.asit.pdfover.signer.pdfas.PdfAs4SigningState; import org.eclipse.swt.SWT; @@ -34,8 +39,9 @@ import org.slf4j.LoggerFactory; import at.asit.pdfover.gui.MainWindow.Buttons; import at.asit.pdfover.gui.MainWindowBehavior; import at.asit.pdfover.gui.bku.MobileBKUConnector; -import at.asit.pdfover.gui.bku.mobile.ATrustHandler; -import at.asit.pdfover.gui.bku.mobile.ATrustStatus; +import at.asit.pdfover.gui.bku.OLDMobileBKUConnector; +import at.asit.pdfover.gui.bku.OLDmobile.ATrustHandler; +import at.asit.pdfover.gui.bku.OLDmobile.ATrustStatus; import at.asit.pdfover.gui.composites.MobileBKUEnterNumberComposite; import at.asit.pdfover.gui.composites.MobileBKUEnterTANComposite; import at.asit.pdfover.gui.composites.MobileBKUFingerprintComposite; @@ -175,53 +181,59 @@ public class MobileBKUState extends State { }); } - public void rememberCredentialsIfNecessary() { + public static class UsernameAndPassword { + public @CheckForNull String username; + public @CheckForNull String password; + public UsernameAndPassword() {} + public UsernameAndPassword(@Nullable String u, @Nullable String p) { this.username = u; this.password = p; } + } + public @Nonnull UsernameAndPassword getRememberedCredentials() { + UsernameAndPassword r = new UsernameAndPassword(); + storeRememberedCredentialsTo(r); + return r; + } + public void storeRememberedCredentialsTo(@Nonnull UsernameAndPassword output) { + output.username = getStateMachine().configProvider.getDefaultMobileNumber(); + output.password = getStateMachine().configProvider.getDefaultMobilePassword(); + } + + public void rememberCredentialsIfNecessary(@Nullable String username, @Nullable String password) { if (getStateMachine().configProvider.getRememberMobilePassword()) { - getStateMachine().configProvider.setDefaultMobileNumberOverlay(status.phoneNumber); - getStateMachine().configProvider.setDefaultMobilePasswordOverlay(status.mobilePassword); + getStateMachine().configProvider.setDefaultMobileNumberOverlay(username); + getStateMachine().configProvider.setDefaultMobilePasswordOverlay(password); } } + public void rememberCredentialsIfNecessary(@Nonnull UsernameAndPassword credentials) { + rememberCredentialsIfNecessary(credentials.username, credentials.password); + } - public void clearRememberedCredentials() { + public void clearRememberedPassword() { getStateMachine().configProvider.setDefaultMobilePasswordOverlay(null); status.mobilePassword = null; } - /** - * Make sure phone number and password are set in the MobileBKUStatus - */ - public void checkCredentials() { - final ATrustStatus mobileStatus = this.status; - // check if we have everything we need! - if (mobileStatus.phoneNumber != null && !mobileStatus.phoneNumber.isEmpty() && - mobileStatus.mobilePassword != null && !mobileStatus.mobilePassword.isEmpty()) - return; + public @Nonnull UsernameAndPassword getCredentialsFromUser(@Nullable String currentUsername, @Nullable String errorMessage) throws UserCancelledException { + UsernameAndPassword r = new UsernameAndPassword(currentUsername, null); + getCredentialsFromUserTo(r, errorMessage); + return r; + } + public void getCredentialsFromUserTo(@Nonnull UsernameAndPassword credentials, @Nullable String errorMessage) throws UserCancelledException { + boolean[] cancelState = new boolean[1]; Display.getDefault().syncExec(() -> { MobileBKUEnterNumberComposite ui = this.getMobileBKUEnterNumberComposite(); - if (!ui.userAck) { - // We need number and password => show UI! - if (mobileStatus.errorMessage != null - && !mobileStatus.errorMessage.isEmpty()) { - // set possible error message - ui.setErrorMessage(mobileStatus.errorMessage); - mobileStatus.errorMessage = null; - } else { + if (!ui.userAck) { // We need number and password => show UI! + + if (errorMessage != null) + ui.setErrorMessage(errorMessage); + else ui.setErrorMessage(Messages.getString("mobileBKU.aTrustDisclaimer")); - } - if (ui.getMobileNumber() == null - || ui.getMobileNumber().isEmpty()) { + if ((ui.getMobileNumber() == null) || ui.getMobileNumber().isEmpty()) { // set possible phone number - ui.setMobileNumber(mobileStatus.phoneNumber); - } - - if (ui.getMobilePassword() == null - || ui.getMobilePassword().isEmpty()) { - // set possible password - ui.setMobilePassword(mobileStatus.mobilePassword); + ui.setMobileNumber(credentials.username); } ui.setRememberPassword(getStateMachine().configProvider.getRememberMobilePassword()); @@ -240,22 +252,45 @@ public class MobileBKUState extends State { if (!(ui.userCancel && ui.isRememberPassword())) /* don't allow "remember" to be enabled via cancel button */ getStateMachine().configProvider.setRememberMobilePasswordPersistent(ui.isRememberPassword()); - if (ui.userCancel) { - ui.userCancel = false; - mobileStatus.errorMessage = "cancel"; + cancelState[0] = ui.userCancel; + ui.userCancel = false; + if (cancelState[0]) return; - } // user hit ok ui.userAck = false; // get number and password from UI - mobileStatus.phoneNumber = ui.getMobileNumber(); - mobileStatus.mobilePassword = ui.getMobilePassword(); + credentials.username = ui.getMobileNumber(); + credentials.password = ui.getMobilePassword(); // show waiting composite getStateMachine().display(this.getWaitingComposite()); }); + if (cancelState[0]) + throw new UserCancelledException(); + } + + /** + * Make sure phone number and password are set in the MobileBKUStatus + * OLD METHOD (todo for nuking) + */ + public void checkCredentials() { + final ATrustStatus mobileStatus = this.status; + // check if we have everything we need! + if (mobileStatus.phoneNumber != null && !mobileStatus.phoneNumber.isEmpty() && + mobileStatus.mobilePassword != null && !mobileStatus.mobilePassword.isEmpty()) + return; + + try { + String errorMessage = mobileStatus.errorMessage; + mobileStatus.errorMessage = null; + UsernameAndPassword creds = getCredentialsFromUser(mobileStatus.phoneNumber, errorMessage); + mobileStatus.phoneNumber = creds.username; + mobileStatus.mobilePassword = creds.password; + } catch (UserCancelledException e) { + mobileStatus.errorMessage = "cancel"; + } } /** @@ -292,7 +327,7 @@ public class MobileBKUState extends State { if (tan.isUserCancel()) { tan.setUserCancel(false); - clearRememberedCredentials(); + clearRememberedPassword(); mobileStatus.errorMessage = "cancel"; return; } @@ -360,7 +395,7 @@ public class MobileBKUState extends State { if (qr.isUserCancel()) { qr.setUserCancel(false); - clearRememberedCredentials(); + clearRememberedPassword(); status.errorMessage = "cancel"; return; } @@ -497,7 +532,7 @@ public class MobileBKUState extends State { if (fingerprintComposite.isUserCancel()) { fingerprintComposite.setUserCancel(false); - clearRememberedCredentials(); + clearRememberedPassword(); status.errorMessage = "cancel"; return; } @@ -534,7 +569,7 @@ public class MobileBKUState extends State { public void run() { this.signingState = getStateMachine().status.signingState; - this.signingState.bkuConnector = new MobileBKUConnector(this); + this.signingState.bkuConnector = new OLDMobileBKUConnector(this); this.signingState.useBase64Request = false; if (this.threadException != null) { diff --git a/pdf-over-signer/src/main/java/at/asit/pdfover/signer/pdfas/PdfAs4SLRequest.java b/pdf-over-signer/src/main/java/at/asit/pdfover/signer/pdfas/PdfAs4SLRequest.java index 785d6089..d4e46e17 100644 --- a/pdf-over-signer/src/main/java/at/asit/pdfover/signer/pdfas/PdfAs4SLRequest.java +++ b/pdf-over-signer/src/main/java/at/asit/pdfover/signer/pdfas/PdfAs4SLRequest.java @@ -26,7 +26,7 @@ public class PdfAs4SLRequest { /** * The security layer request */ - public final String request; + public final String xmlRequest; /** * The document to be signed @@ -40,7 +40,7 @@ public class PdfAs4SLRequest { * @throws PdfAs4SLRequestException */ public PdfAs4SLRequest(String slRequest, byte[] signData) throws PdfAs4SLRequestException { - this.request = slRequest; + this.xmlRequest = slRequest; this.signatureData = (signData == null ? null : new ByteArrayDocumentSource(signData)); } } diff --git a/pom.xml b/pom.xml index 1038d658..2655c5e9 100644 --- a/pom.xml +++ b/pom.xml @@ -214,6 +214,11 @@ activation 1.1.1 + + com.google.code.findbugs + jsr305 + 3.0.2 + -- cgit v1.2.3