From 0e45fec2be59e0247aaa27c24ac719f548cd96cb Mon Sep 17 00:00:00 2001 From: Jakob Heher Date: Wed, 5 Oct 2022 16:03:01 +0200 Subject: fido2 composite --- .../asit/pdfover/gui/bku/MobileBKUConnector.java | 64 ++++++------- .../mobilebku/MobileBKUEnterNumberComposite.java | 3 +- .../mobilebku/MobileBKUEnterTANComposite.java | 80 ++++++---------- .../mobilebku/MobileBKUFido2Composite.java | 102 +++++++++++++++++++++ .../mobilebku/MobileBKUFingerprintComposite.java | 3 +- .../composites/mobilebku/MobileBKUQRComposite.java | 3 +- .../mobilebku/WaitingForAppComposite.java | 4 +- .../java/at/asit/pdfover/gui/utils/SWTUtils.java | 7 ++ .../gui/workflow/states/MobileBKUState.java | 85 ++++++++++++++--- .../at/asit/pdfover/gui/messages.properties | 2 + .../at/asit/pdfover/gui/messages_de.properties | 2 + pdf-over-gui/src/main/resources/img/fido_logo.png | Bin 0 -> 25056 bytes .../src/main/resources/img/webauthn-logo.png | Bin 0 -> 121670 bytes 13 files changed, 248 insertions(+), 107 deletions(-) create mode 100644 pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFido2Composite.java create mode 100644 pdf-over-gui/src/main/resources/img/fido_logo.png create mode 100644 pdf-over-gui/src/main/resources/img/webauthn-logo.png (limited to 'pdf-over-gui') 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 index 1748f631..78943eee 100644 --- 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 @@ -47,10 +47,6 @@ import at.asit.pdfover.signer.BkuSlConnector; import at.asit.pdfover.signer.SignatureException; import at.asit.pdfover.signer.UserCancelledException; import at.asit.pdfover.signer.pdfas.PdfAs4SLRequest; -import at.asit.webauthn.PublicKeyCredentialRequestOptions; -import at.asit.webauthn.WebAuthN; -import at.asit.webauthn.exceptions.WebAuthNOperationFailed; -import at.asit.webauthn.exceptions.WebAuthNUserCancelled; import static at.asit.pdfover.commons.Constants.ISNOTNULL; @@ -353,38 +349,36 @@ public class MobileBKUConnector implements BkuSlConnector { } } if (html.fido2Block != null) { - // TODO composite for this - if (WebAuthN.isAvailable()) { - try { - var fido2Assertion = PublicKeyCredentialRequestOptions.FromJSONString(html.fido2Block.fidoOptions).get("https://service.a-trust.at"); - - Base64.Encoder base64 = Base64.getEncoder(); - - JSONObject aTrustAssertion = new JSONObject(); - aTrustAssertion.put("id", fido2Assertion.id); - aTrustAssertion.put("rawId", base64.encodeToString(fido2Assertion.rawId)); - aTrustAssertion.put("type", fido2Assertion.type); - aTrustAssertion.put("extensions", new JSONObject()); // TODO fix extensions in library - - JSONObject aTrustAssertionResponse = new JSONObject(); - aTrustAssertion.put("response", aTrustAssertionResponse); - aTrustAssertionResponse.put("authenticatorData", base64.encodeToString(fido2Assertion.response.authenticatorData)); - aTrustAssertionResponse.put("clientDataJson", base64.encodeToString(fido2Assertion.response.clientDataJSON)); - aTrustAssertionResponse.put("signature", base64.encodeToString(fido2Assertion.response.signature)); - if (fido2Assertion.response.userHandle != null) - aTrustAssertionResponse.put("userHandle", base64.encodeToString(fido2Assertion.response.userHandle)); - else - aTrustAssertionResponse.put("userHandle", JSONObject.NULL); - - html.fido2Block.setFIDOResult(aTrustAssertion.toString()); - return buildFormSubmit(html, "#FidoContinue"); - } catch (WebAuthNUserCancelled e) { - log.debug("WebAuthN authentication cancelled by user"); - throw new UserCancelledException(); - } catch (WebAuthNOperationFailed e) { - log.warn("WebAuthN authentication failed", e); - } + + var fido2Result = this.state.promptUserForFIDO2Auth(html.fido2Block.fidoOptions, html.signatureDataLink, html.smsTanLink != null); + + switch (fido2Result.type) { + case TO_SMS: return new HttpGet(html.smsTanLink); + case CREDENTIAL: break; } + + var fido2Assertion = ISNOTNULL(fido2Result.credential); + + Base64.Encoder base64 = Base64.getEncoder(); + + JSONObject aTrustAssertion = new JSONObject(); + aTrustAssertion.put("id", fido2Assertion.id); + aTrustAssertion.put("rawId", base64.encodeToString(fido2Assertion.rawId)); + aTrustAssertion.put("type", fido2Assertion.type); + aTrustAssertion.put("extensions", new JSONObject()); // TODO fix extensions in library + + JSONObject aTrustAssertionResponse = new JSONObject(); + aTrustAssertion.put("response", aTrustAssertionResponse); + aTrustAssertionResponse.put("authenticatorData", base64.encodeToString(fido2Assertion.response.authenticatorData)); + aTrustAssertionResponse.put("clientDataJson", base64.encodeToString(fido2Assertion.response.clientDataJSON)); + aTrustAssertionResponse.put("signature", base64.encodeToString(fido2Assertion.response.signature)); + if (fido2Assertion.response.userHandle != null) + aTrustAssertionResponse.put("userHandle", base64.encodeToString(fido2Assertion.response.userHandle)); + else + aTrustAssertionResponse.put("userHandle", JSONObject.NULL); + + html.fido2Block.setFIDOResult(aTrustAssertion.toString()); + return buildFormSubmit(html, "#FidoContinue"); } throw new IllegalStateException("No top-level block is set? Something has gone terribly wrong."); } diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUEnterNumberComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUEnterNumberComposite.java index 575c2ad7..d5980229 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUEnterNumberComposite.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUEnterNumberComposite.java @@ -13,7 +13,7 @@ * See the Licence for the specific language governing permissions and * limitations under the Licence. */ -package at.asit.pdfover.gui.composites; +package at.asit.pdfover.gui.composites.mobilebku; // Imports import org.eclipse.swt.SWT; @@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory; import at.asit.pdfover.commons.Constants; import at.asit.pdfover.gui.bku.OLDmobile.MobileBKUHelper; +import at.asit.pdfover.gui.composites.StateComposite; 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/composites/mobilebku/MobileBKUEnterTANComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUEnterTANComposite.java index 83913c74..28aaf4c7 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUEnterTANComposite.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUEnterTANComposite.java @@ -13,7 +13,7 @@ * See the Licence for the specific language governing permissions and * limitations under the Licence. */ -package at.asit.pdfover.gui.composites; +package at.asit.pdfover.gui.composites.mobilebku; // Imports import java.net.URI; @@ -44,6 +44,7 @@ import com.beust.jcommander.internal.Nullable; import at.asit.pdfover.commons.Constants; import at.asit.pdfover.commons.Messages; import at.asit.pdfover.gui.bku.OLDmobile.ATrustStatus; +import at.asit.pdfover.gui.composites.StateComposite; import at.asit.pdfover.gui.utils.SWTUtils; import at.asit.pdfover.gui.workflow.states.State; @@ -52,42 +53,28 @@ import at.asit.pdfover.gui.workflow.states.State; */ public class MobileBKUEnterTANComposite extends StateComposite { - /** - * - */ - private final class OkSelectionListener extends SelectionAdapter { - - @Override - public void widgetSelected(SelectionEvent e) { - if(!MobileBKUEnterTANComposite.this.btn_ok.getEnabled()) { - return; - } + private void validateAndConfirmTAN() { + String tan = this.txt_tan.getText(); - String tan = MobileBKUEnterTANComposite.this.txt_tan.getText(); + tan = tan.trim(); - tan = tan.trim(); - - if (tan.isEmpty()) { - MobileBKUEnterTANComposite.this.setMessage(Messages - .getString("error.NoTan")); - return; - } - - if (MobileBKUEnterTANComposite.this.refVal.startsWith(tan)) { - MobileBKUEnterTANComposite.this.setMessage(Messages - .getString("error.EnteredReferenceValue")); - return; - } + if (tan.isEmpty()) { + this.setMessage(Messages.getString("error.NoTan")); + return; + } - if (tan.length() > 6) { - MobileBKUEnterTANComposite.this.setMessage(Messages - .getString("error.TanTooLong")); - return; - } + if (MobileBKUEnterTANComposite.this.refVal.startsWith(tan)) { + this.setMessage(Messages.getString("error.EnteredReferenceValue")); + return; + } - MobileBKUEnterTANComposite.this.tan = tan; - MobileBKUEnterTANComposite.this.userAck = true; + if (tan.length() > 6) { + this.setMessage(Messages.getString("error.TanTooLong")); + return; } + + this.tan = tan; + this.userAck = true; } /** @@ -270,29 +257,16 @@ public class MobileBKUEnterTANComposite extends StateComposite { SWTUtils.anchor(txt_tan).left(50,10).right(100,-20).top(50,10); this.txt_tan.setEditable(true); - this.txt_tan.addTraverseListener(new TraverseListener() { - @Override - public void keyTraversed(TraverseEvent e) { - if (e.detail == SWT.TRAVERSE_RETURN) { - if(MobileBKUEnterTANComposite.this.btn_ok.isEnabled()) { - (new OkSelectionListener()).widgetSelected(null); - } - } + this.txt_tan.addTraverseListener((e) -> { + if (e.detail == SWT.TRAVERSE_RETURN) { + validateAndConfirmTAN(); } }); - this.txt_tan.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - - String text = MobileBKUEnterTANComposite.this.txt_tan.getText(); - //log.debug("Current TAN: " + text); - if (text.length() > 3 - && MobileBKUEnterTANComposite.this.getRefVal() - .startsWith(text.trim())) { - MobileBKUEnterTANComposite.this.setMessage(Messages.getString("error.EnteredReferenceValue")); - } - } + this.txt_tan.addModifyListener((e) -> { + String text = this.txt_tan.getText(); + if (text.length() > 3 && this.getRefVal().startsWith(text.trim())) + this.setMessage(Messages.getString("error.EnteredReferenceValue")); }); this.lnk_sig_data = new Link(containerComposite, SWT.NATIVE | SWT.RESIZE); @@ -302,7 +276,7 @@ public class MobileBKUEnterTANComposite extends StateComposite { this.btn_ok = new Button(containerComposite, SWT.NATIVE); SWTUtils.anchor(btn_ok).right(100,-20).bottom(100,-20); - this.btn_ok.addSelectionListener(new OkSelectionListener()); + SWTUtils.addSelectionListener(btn_ok, (e) -> { validateAndConfirmTAN(); }); this.btn_cancel = new Button(containerComposite, SWT.NATIVE); SWTUtils.anchor(btn_cancel).right(btn_ok, -20).bottom(100, -20); diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFido2Composite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFido2Composite.java new file mode 100644 index 00000000..f303d6c3 --- /dev/null +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFido2Composite.java @@ -0,0 +1,102 @@ +package at.asit.pdfover.gui.composites.mobilebku; + +import javax.annotation.Nonnull; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.asit.pdfover.commons.Constants; +import at.asit.pdfover.gui.composites.StateComposite; +import at.asit.pdfover.gui.utils.SWTUtils; +import at.asit.pdfover.gui.workflow.states.State; +import at.asit.webauthn.PublicKeyCredential; +import at.asit.webauthn.PublicKeyCredentialRequestOptions; +import at.asit.webauthn.WebAuthN; +import at.asit.webauthn.exceptions.WebAuthNOperationFailed; +import at.asit.webauthn.exceptions.WebAuthNUserCancelled; +import at.asit.webauthn.responsefields.AuthenticatorAssertionResponse; + +public class MobileBKUFido2Composite extends StateComposite { + private static final Logger log = LoggerFactory.getLogger(MobileBKUFido2Composite.class); + + private @Nonnull String fido2OptionsString = ""; + + private PublicKeyCredential credential; + private boolean userCancel; + private boolean userSms; + + private Button btn_authenticate; + + public void initialize(@Nonnull String fido2Options) { + this.fido2OptionsString = fido2Options; + this.credential = null; + this.userCancel = this.userSms = false; + this.btn_authenticate.setEnabled(WebAuthN.isAvailable()); + } + + public boolean isDone() { return ((this.credential != null) || this.userCancel || this.userSms); } + public PublicKeyCredential getResultingCredential() { return this.credential; } + public boolean wasUserCancelClicked() { return userCancel; } + public boolean wasUserSMSClicked() { return userSms; } + + public MobileBKUFido2Composite(Composite parent, int style, State state) { + super(parent, style, state); + setLayout(new FormLayout()); + + final Composite containerComposite = new Composite(this, SWT.NATIVE); + containerComposite.addPaintListener((e) -> { + Rectangle clientArea = containerComposite.getClientArea(); + e.gc.setForeground(Constants.MAINBAR_ACTIVE_BACK_DARK); + e.gc.setLineWidth(3); + e.gc.setLineStyle(SWT.LINE_SOLID); + e.gc.drawRoundRectangle(clientArea.x, clientArea.y, + clientArea.width - 2, clientArea.height - 2, 10, 10); + + }); + containerComposite.setLayout(new FormLayout()); + SWTUtils.anchor(containerComposite).top(50, -120).bottom(50, 120).left(50, -200).right(50, 200); + + ImageData webauthnLogoImg = new ImageData(this.getClass().getResourceAsStream(Constants.RES_IMG_WEBAUTHN)); + Label webauthnLogo = new Label(containerComposite, SWT.NATIVE); + SWTUtils.anchor(webauthnLogo).top(0, 10).right(100, -10).height(50).width(187); + webauthnLogo.setImage(new Image(getDisplay(), webauthnLogoImg.scaledTo(187, 50))); + + ImageData fidoLogoImg = new ImageData(this.getClass().getResourceAsStream(Constants.RES_IMG_FIDO2)); + Label fidoLogo = new Label(containerComposite, SWT.NATIVE); + SWTUtils.anchor(fidoLogo).top(webauthnLogo, 10).right(100, -10).height(50).width(81); + fidoLogo.setImage(new Image(getDisplay(), fidoLogoImg.scaledTo(81, 50))); + + this.btn_authenticate = new Button(containerComposite, SWT.NATIVE); + SWTUtils.anchor(btn_authenticate).top(50, -10).left(0, 90).right(100, -90); + SWTUtils.addSelectionListener(btn_authenticate, () -> { + SWTUtils.setLocalizedText(btn_authenticate, "common.working"); + btn_authenticate.setEnabled(false); + try { + /* let the click process first so we don't steal back focus from the fido2 popup */ + try { Thread.sleep(10); } catch (InterruptedException e) {} + this.credential = PublicKeyCredentialRequestOptions.FromJSONString(this.fido2OptionsString).get("https://service.a-trust.at"); + } catch (WebAuthNUserCancelled e) { + this.userCancel = true; + } catch (WebAuthNOperationFailed e) { + // TODO + log.error("webauthn fail", e); + } finally { btn_authenticate.setEnabled(true); reloadResources(); } + }); + } + + @Override protected void checkSubclass() {} + @Override public void doLayout() { getShell().setDefaultButton(this.btn_authenticate); } + + @Override + public void reloadResources() { + SWTUtils.setLocalizedText(btn_authenticate, "mobileBKU.authorize"); + } +} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFingerprintComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFingerprintComposite.java index c0561fe4..14ca1dc7 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFingerprintComposite.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFingerprintComposite.java @@ -13,7 +13,7 @@ * See the Licence for the specific language governing permissions and * limitations under the Licence. */ -package at.asit.pdfover.gui.composites; +package at.asit.pdfover.gui.composites.mobilebku; // Imports import org.eclipse.swt.SWT; @@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory; import at.asit.pdfover.commons.Constants; import at.asit.pdfover.commons.Messages; +import at.asit.pdfover.gui.composites.StateComposite; import at.asit.pdfover.gui.utils.SWTUtils; import at.asit.pdfover.gui.workflow.states.State; diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUQRComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUQRComposite.java index 91765610..1b2600c8 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUQRComposite.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUQRComposite.java @@ -13,7 +13,7 @@ * See the Licence for the specific language governing permissions and * limitations under the Licence. */ -package at.asit.pdfover.gui.composites; +package at.asit.pdfover.gui.composites.mobilebku; // Imports import java.io.ByteArrayInputStream; @@ -40,6 +40,7 @@ import org.slf4j.LoggerFactory; import at.asit.pdfover.commons.Constants; import at.asit.pdfover.commons.Messages; +import at.asit.pdfover.gui.composites.StateComposite; import at.asit.pdfover.gui.utils.SWTUtils; import at.asit.pdfover.gui.workflow.states.State; diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/WaitingForAppComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/WaitingForAppComposite.java index 7d5b4dfd..ed311957 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/WaitingForAppComposite.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/WaitingForAppComposite.java @@ -13,7 +13,7 @@ * See the Licence for the specific language governing permissions and * limitations under the Licence. */ -package at.asit.pdfover.gui.composites; +package at.asit.pdfover.gui.composites.mobilebku; // Imports @@ -22,6 +22,8 @@ import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.ProgressBar; + +import at.asit.pdfover.gui.composites.StateComposite; import at.asit.pdfover.gui.utils.SWTUtils; import at.asit.pdfover.gui.workflow.states.State; import org.eclipse.swt.widgets.Button; diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/utils/SWTUtils.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/utils/SWTUtils.java index d276ecd6..c82e0309 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/utils/SWTUtils.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/utils/SWTUtils.java @@ -178,6 +178,13 @@ public final class SWTUtils { } } + /** + * @see SWTUtils#addSelectionListener(Object, Consumer) + */ + public static void addSelectionListener(Object swtObj, Runnable callback) { + addSelectionListener(swtObj, (e) -> { callback.run(); }); + } + public static void openURL(@Nullable URI uri) { try { if (uri == null) return; 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 48415ab5..f9a0d967 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 @@ -29,6 +29,8 @@ import javax.annotation.Nullable; // Imports import at.asit.pdfover.signer.UserCancelledException; import at.asit.pdfover.signer.pdfas.PdfAs4SigningState; +import at.asit.webauthn.PublicKeyCredential; +import at.asit.webauthn.responsefields.AuthenticatorAssertionResponse; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; @@ -45,18 +47,21 @@ import at.asit.pdfover.gui.MainWindowBehavior; import at.asit.pdfover.gui.bku.MobileBKUConnector; 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; -import at.asit.pdfover.gui.composites.MobileBKUQRComposite; import at.asit.pdfover.gui.composites.WaitingComposite; -import at.asit.pdfover.gui.composites.WaitingForAppComposite; +import at.asit.pdfover.gui.composites.mobilebku.MobileBKUEnterNumberComposite; +import at.asit.pdfover.gui.composites.mobilebku.MobileBKUEnterTANComposite; +import at.asit.pdfover.gui.composites.mobilebku.MobileBKUFido2Composite; +import at.asit.pdfover.gui.composites.mobilebku.MobileBKUFingerprintComposite; +import at.asit.pdfover.gui.composites.mobilebku.MobileBKUQRComposite; +import at.asit.pdfover.gui.composites.mobilebku.WaitingForAppComposite; import at.asit.pdfover.gui.controls.Dialog.BUTTONS; import at.asit.pdfover.gui.controls.ErrorDialog; import at.asit.pdfover.commons.Messages; import at.asit.pdfover.gui.workflow.StateMachine; import at.asit.pdfover.gui.workflow.config.ConfigurationManager; +import static at.asit.pdfover.commons.Constants.ISNOTNULL; + /** * Logical state for performing the BKU Request to the A-Trust Mobile BKU */ @@ -138,6 +143,16 @@ public class MobileBKUState extends State { return this.mobileBKUFingerprintComposite; } + MobileBKUFido2Composite mobileBKUFido2Composite = null; + MobileBKUFido2Composite getMobileBKUFido2Composite() { + if (this.mobileBKUFido2Composite == null) { + this.mobileBKUFido2Composite = getStateMachine() + .createComposite(MobileBKUFido2Composite.class, SWT.RESIZE, this); + } + + return this.mobileBKUFido2Composite; + } + /** * @return the signingState */ @@ -330,8 +345,8 @@ public class MobileBKUState extends State { private SMSTanResult(@Nonnull ResultType type) { this.type = type; this.smsTan = null; } } - public SMSTanResult getSMSTanFromUser(final @Nonnull String referenceValue, final int triesRemaining, final @Nullable URI signatureDataURI, final boolean showFido2, final @Nullable String errorMessage) throws UserCancelledException { - return Display.getDefault().syncCall(() -> { + public @Nonnull SMSTanResult getSMSTanFromUser(final @Nonnull String referenceValue, final int triesRemaining, final @Nullable URI signatureDataURI, final boolean showFido2, final @Nullable String errorMessage) throws UserCancelledException { + return ISNOTNULL(Display.getDefault().syncCall(() -> { MobileBKUEnterTANComposite tan = getMobileBKUEnterTANComposite(); tan.reset(); @@ -357,7 +372,7 @@ public class MobileBKUState extends State { return new SMSTanResult(SMSTanResult.ResultType.TO_FIDO2); return new SMSTanResult(tan.getTan()); - }); + })); } /** @@ -398,8 +413,8 @@ public class MobileBKUState extends State { UPDATE }; - public QRResult waitForQRCodeResult() throws UserCancelledException { - return Display.getDefault().syncCall(() -> { + public @Nonnull QRResult waitForQRCodeResult() throws UserCancelledException { + return ISNOTNULL(Display.getDefault().syncCall(() -> { MobileBKUQRComposite qr = getMobileBKUQRComposite(); Display display = getStateMachine().getMainShell().getDisplay(); @@ -423,7 +438,7 @@ public class MobileBKUState extends State { return QRResult.TO_FIDO2; return QRResult.UPDATE; - }); + })); } /** @@ -458,8 +473,8 @@ public class MobileBKUState extends State { UPDATE }; - public AppOpenResult waitForAppOpen() throws UserCancelledException { - return Display.getDefault().syncCall(() -> { + public @Nonnull AppOpenResult waitForAppOpen() throws UserCancelledException { + return ISNOTNULL(Display.getDefault().syncCall(() -> { WaitingForAppComposite wfa = getWaitingForAppComposite(); Display display = wfa.getDisplay(); @@ -482,7 +497,7 @@ public class MobileBKUState extends State { return AppOpenResult.TO_FIDO2; return AppOpenResult.UPDATE; - }); + })); } /** @@ -562,10 +577,50 @@ public class MobileBKUState extends State { * @return a boolean true if the user has pressed the sms tan button */ public boolean getSMSStatus() { - return this.getMobileBKUFingerprintComposite().isUserSMS(); } + public static class FIDO2Result { + public static enum ResultType { TO_SMS, CREDENTIAL }; + public final @Nonnull ResultType type; + public final @Nullable PublicKeyCredential credential; + + private FIDO2Result(@Nonnull ResultType type) { this.type = type; this.credential = null; } + private FIDO2Result(@Nonnull PublicKeyCredential cred) { this.type = ResultType.CREDENTIAL; this.credential = cred; } + } + + /** + * prompts user for fido2 auth and blocks until result is available + * @param fido2Options JSON data from A-Trust + * @return + * @throws UserCancelledException + */ + public @Nonnull FIDO2Result promptUserForFIDO2Auth(final @Nonnull String fido2Options, @Nullable URI signatureDataURI, final boolean showSmsTan) throws UserCancelledException { + return ISNOTNULL(Display.getDefault().syncCall(() -> { + MobileBKUFido2Composite fido2 = getMobileBKUFido2Composite(); + fido2.initialize(fido2Options); + // TODO signature data, sms tan support + + getStateMachine().display(fido2); + + Display display = fido2.getDisplay(); + while (!fido2.isDone()) { + if (!display.readAndDispatch()) + display.sleep(); + } + + getStateMachine().display(this.getWaitingComposite()); + + if (fido2.wasUserCancelClicked()) + throw new UserCancelledException(); + + if (fido2.wasUserSMSClicked()) + return new FIDO2Result(FIDO2Result.ResultType.TO_SMS); + + return new FIDO2Result(ISNOTNULL(fido2.getResultingCredential())); + })); + } + /* * (non-Javadoc) * diff --git a/pdf-over-gui/src/main/resources/at/asit/pdfover/gui/messages.properties b/pdf-over-gui/src/main/resources/at/asit/pdfover/gui/messages.properties index 2d5d74f1..524f6c32 100644 --- a/pdf-over-gui/src/main/resources/at/asit/pdfover/gui/messages.properties +++ b/pdf-over-gui/src/main/resources/at/asit/pdfover/gui/messages.properties @@ -114,6 +114,7 @@ common.browse=&Browse common.info=Information common.open=Open common.warning=Warning +common.working=Working... config.About=A&bout %s config.AboutText=This software is freely provided by A-SIT under the conditions of the EUPL.\nTerms and details at https\://technology.a-sit.at/en/terms-of-a-license/.\n\nNote that components may have different licenses, partly restricting their free use to EUPL-licensed software. config.LicenseURL=https://technology.a-sit.at/en/terms-of-a-license/ @@ -216,6 +217,7 @@ mobileBKU.tan_tries_exceeded=TAN tries exceeded, request a new TAN? mobileBKU.wrong_tan=TAN not accepted mobileBKU.rememberPassword=Re&member mobileBKU.rememberPasswordNote=If you check this, you will not be prompted for your password again until you re-start PDF-Over +mobileBKU.authorize=Begin authorization output.file_ask_overwrite=File %s already exists, do you want to overwrite it? output.link_open_message=You can open the signed file here. output.link_save_message=You can save the signed file diff --git a/pdf-over-gui/src/main/resources/at/asit/pdfover/gui/messages_de.properties b/pdf-over-gui/src/main/resources/at/asit/pdfover/gui/messages_de.properties index a75dfbb4..8173a13a 100644 --- a/pdf-over-gui/src/main/resources/at/asit/pdfover/gui/messages_de.properties +++ b/pdf-over-gui/src/main/resources/at/asit/pdfover/gui/messages_de.properties @@ -105,6 +105,7 @@ common.browse=&Durchsuchen common.info=Information common.open=Öffnen common.warning=Warnung +common.working=In Arbeit... config.About=Ü&ber %s config.AboutText=Diese Software wird von A-SIT unter den Bedingungen der EUPL frei zur Verfügung gestellt.\nLizenbedingungen unter https://technology.a-sit.at/lizenzbedingungen/.\n\nBeachten Sie, dass Komponenten unter eigenen Lizenzen zur Verfügung gestellt werden, die teilweise nur für EUPL-lizensierte Software zur freien Verwendung vorgesehen sind. config.LicenseURL=https://technology.a-sit.at/lizenzbedingungen/ @@ -207,6 +208,7 @@ mobileBKU.tan_tries_exceeded=Zu viele TAN-Versuche, neue TAN anfordern? mobileBKU.wrong_tan=TAN nicht akzeptiert mobileBKU.rememberPassword=Daten &merken mobileBKU.rememberPasswordNote=Wählen Sie diese Box aus, um bis zum nächsten Start von PDF-Over nicht erneut gefragt zu werden +mobileBKU.authorize=Autorisierung starten output.file_ask_overwrite=Datei %s existiert bereits, wollen Sie sie überschreiben? output.link_open_message=Sie können das signierte Dokument hier öffnen. output.link_save_message=Sie können das signierte Dokument speichern diff --git a/pdf-over-gui/src/main/resources/img/fido_logo.png b/pdf-over-gui/src/main/resources/img/fido_logo.png new file mode 100644 index 00000000..78ab7806 Binary files /dev/null and b/pdf-over-gui/src/main/resources/img/fido_logo.png differ diff --git a/pdf-over-gui/src/main/resources/img/webauthn-logo.png b/pdf-over-gui/src/main/resources/img/webauthn-logo.png new file mode 100644 index 00000000..f9024864 Binary files /dev/null and b/pdf-over-gui/src/main/resources/img/webauthn-logo.png differ -- cgit v1.2.3