diff options
14 files changed, 138 insertions, 44 deletions
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 c3d1eb84..1d482fcf 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 @@ -222,6 +222,8 @@ public class Constants { /** The theme */ public static final String CFG_THEME = "THEME"; + public static final String CFG_FIDO2_BY_DEFAULT = "FIDO2_DEFAULT"; + /** Download URL for accepted Certificates*/ public static final String CFG_DOWNLOAD_URL="DOWNLOAD_URL"; 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 3efecb4c..6d7c2cd7 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 @@ -56,6 +56,7 @@ public class MobileBKUConnector implements BkuSlConnector { private final @Nonnull MobileBKUState state; public MobileBKUConnector(@Nonnull MobileBKUState state) { this.state = state; + this.wantsFido2Default = state.getConfig().getFido2ByDefault(); state.storeRememberedCredentialsTo(this.credentials); } @@ -281,6 +282,7 @@ public class MobileBKUConnector implements BkuSlConnector { } + private boolean wantsFido2Default; /** * Main lifting function for MobileBKU UX * @return the next request to make, or null if the current response should be returned @@ -291,6 +293,11 @@ public class MobileBKUConnector implements BkuSlConnector { state.rememberCredentialsIfNecessary(this.credentials); } + if (wantsFido2Default && (html.fido2Link != null)) { + wantsFido2Default = false; + return new HttpGet(html.fido2Link); + } + if (html.interstitialBlock != null) { this.state.showInformationMessage(html.interstitialBlock.interstitialMessage); return buildFormSubmit(html, html.interstitialBlock.submitButton); diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/ConfigurationComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/ConfigurationComposite.java index c6ff31cc..20173ea8 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/ConfigurationComposite.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/ConfigurationComposite.java @@ -34,6 +34,7 @@ import at.asit.pdfover.gui.controls.Dialog.BUTTONS; import at.asit.pdfover.gui.composites.configuration.AboutComposite; import at.asit.pdfover.gui.composites.configuration.AdvancedConfigurationComposite; import at.asit.pdfover.gui.composites.configuration.ConfigurationCompositeBase; +import at.asit.pdfover.gui.composites.configuration.Fido2ConfigurationComposite; import at.asit.pdfover.gui.composites.configuration.KeystoreConfigurationComposite; import at.asit.pdfover.gui.composites.configuration.SimpleConfigurationComposite; import at.asit.pdfover.gui.controls.ErrorDialog; @@ -74,6 +75,8 @@ public class ConfigurationComposite extends StateComposite { */ ConfigurationCompositeBase keystoreConfigComposite = null; + ConfigurationCompositeBase fido2ConfigComposite; + /** * about page composite */ @@ -86,7 +89,7 @@ public class ConfigurationComposite extends StateComposite { int i = 0; @Override public boolean hasNext() { - return i < 4; + return i < 5; } @Override @@ -96,7 +99,8 @@ public class ConfigurationComposite extends StateComposite { case 1: return simpleConfigComposite; case 2: return advancedConfigComposite; case 3: return keystoreConfigComposite; - case 4: return aboutConfigComposite; + case 4: return fido2ConfigComposite; + case 5: return aboutConfigComposite; } throw new NoSuchElementException(); } @@ -141,6 +145,8 @@ public class ConfigurationComposite extends StateComposite { private TabItem keystoreTabItem; + private TabItem fido2TabItem; + private TabItem aboutTabItem; private Button btnSpeichern; @@ -167,7 +173,6 @@ public class ConfigurationComposite extends StateComposite { SWTUtils.setFontHeight(tabFolder, Constants.TEXT_SIZE_NORMAL); this.simpleTabItem = new TabItem(this.tabFolder, SWT.NONE); - ScrolledComposite simpleCompositeScr = new ScrolledComposite(this.tabFolder, (SWT.H_SCROLL | SWT.V_SCROLL)); this.simpleTabItem.setControl(simpleCompositeScr); this.simpleConfigComposite = new SimpleConfigurationComposite(simpleCompositeScr, SWT.NONE, state, configurationContainer); @@ -177,7 +182,6 @@ public class ConfigurationComposite extends StateComposite { simpleCompositeScr.setMinSize(simpleConfigComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); this.advancedTabItem = new TabItem(this.tabFolder, SWT.NONE); - ScrolledComposite advancedCompositeScr = new ScrolledComposite(this.tabFolder, (SWT.H_SCROLL | SWT.V_SCROLL)); this.advancedTabItem.setControl(advancedCompositeScr); this.advancedConfigComposite = new AdvancedConfigurationComposite(advancedCompositeScr, SWT.NONE, state, configurationContainer, this); @@ -186,8 +190,20 @@ public class ConfigurationComposite extends StateComposite { advancedCompositeScr.setExpandVertical(true); advancedCompositeScr.setMinSize(advancedConfigComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); - this.aboutTabItem = new TabItem(this.tabFolder, SWT.NONE); + this.fido2TabItem = new TabItem(this.tabFolder, SWT.NONE); + ScrolledComposite fido2CompositeScr = new ScrolledComposite(this.tabFolder, (SWT.H_SCROLL | SWT.V_SCROLL)); + this.fido2TabItem.setControl(fido2CompositeScr); + this.fido2ConfigComposite = new Fido2ConfigurationComposite(fido2CompositeScr, SWT.NONE, state, configurationContainer); + fido2CompositeScr.setContent(fido2ConfigComposite); + fido2CompositeScr.setExpandHorizontal(true); + fido2CompositeScr.setExpandVertical(true); + fido2CompositeScr.addListener(SWT.Resize, (e) -> { + int widthHint = fido2CompositeScr.getClientArea().width - 50; /* offset for scroll bar */ + fido2CompositeScr.setMinSize(null); + fido2CompositeScr.setMinSize(fido2CompositeScr.computeSize(widthHint, SWT.DEFAULT)); + }); + this.aboutTabItem = new TabItem(this.tabFolder, SWT.NONE); ScrolledComposite aboutCompositeScr = new ScrolledComposite(this.tabFolder, (SWT.H_SCROLL | SWT.V_SCROLL)); this.aboutTabItem.setControl(aboutCompositeScr); this.aboutConfigComposite = new AboutComposite(aboutCompositeScr, SWT.NONE, state, configurationContainer); @@ -377,6 +393,7 @@ public class ConfigurationComposite extends StateComposite { public void reloadResources() { SWTUtils.setLocalizedText(simpleTabItem, "config.Simple"); SWTUtils.setLocalizedText(advancedTabItem, "config.Advanced"); + SWTUtils.setLocalizedText(fido2TabItem, "config.FIDO2"); SWTUtils.setLocalizedText(aboutTabItem, "config.About", Constants.APP_NAME); if (this.keystoreConfigComposite != null) SWTUtils.setLocalizedText(keystoreTabItem, "config.Keystore"); diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/AboutComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/AboutComposite.java index 07b62421..2dced6ac 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/AboutComposite.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/AboutComposite.java @@ -95,15 +95,6 @@ public class AboutComposite extends ConfigurationCompositeBase { reloadResources(); } - - /* (non-Javadoc) - * @see at.asit.pdfover.gui.composites.StateComposite#doLayout() - */ - @Override - public void doLayout() { - // Nothing to do here - } - private void RefreshUpdateStatusText() { SWTUtils.setLocalizedText(lnkUpdateCheckStatus, "config.UpdateStatus." + latestUpdateStatus.name()); } diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/AdvancedConfigurationComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/AdvancedConfigurationComposite.java index d9ea02ed..6d1a85d2 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/AdvancedConfigurationComposite.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/AdvancedConfigurationComposite.java @@ -503,16 +503,6 @@ public class AdvancedConfigurationComposite extends ConfigurationCompositeBase { this.configurationContainer.setProxyPort(port); } - /* - * (non-Javadoc) - * - * @see at.asit.pdfover.gui.composites.StateComposite#doLayout() - */ - @Override - public void doLayout() { - // Nothing to do here - } - @Override public void initConfiguration(ConfigurationManager provider) { this.configurationContainer.autoPositionSignature = provider.getAutoPositionSignaturePersistent(); diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/ConfigurationCompositeBase.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/ConfigurationCompositeBase.java index 54207292..1eaa7d87 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/ConfigurationCompositeBase.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/ConfigurationCompositeBase.java @@ -74,4 +74,6 @@ public abstract class ConfigurationCompositeBase extends StateComposite { * @throws Exception */ public abstract void validateSettings(int resumeFrom) throws Exception; + + @Override public final void doLayout() { this.layout(true, true); } } diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/Fido2ConfigurationComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/Fido2ConfigurationComposite.java new file mode 100644 index 00000000..36e2931b --- /dev/null +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/Fido2ConfigurationComposite.java @@ -0,0 +1,78 @@ +package at.asit.pdfover.gui.composites.configuration; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Link; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.asit.pdfover.commons.Constants; +import at.asit.pdfover.commons.Messages; +import at.asit.pdfover.gui.utils.SWTUtils; +import at.asit.pdfover.gui.workflow.config.ConfigurationDataInMemory; +import at.asit.pdfover.gui.workflow.config.ConfigurationManager; +import at.asit.pdfover.gui.workflow.states.State; + +public class Fido2ConfigurationComposite extends ConfigurationCompositeBase { + private static final Logger log = LoggerFactory.getLogger(Fido2ConfigurationComposite.class); + + private Link lnkInfoText; + // TODO information about unsupported/installing deps? + + private Group grpFidoSettings; + private Button btnFido2ByDefault; + + public Fido2ConfigurationComposite(Composite parent, int style, State state, ConfigurationDataInMemory container) { + super(parent, style, state, container); + setLayout(new FormLayout()); + + this.lnkInfoText = new Link(this, SWT.WRAP); + SWTUtils.anchor(lnkInfoText).top(0,5).left(0,5).right(100,-5); + SWTUtils.setFontHeight(lnkInfoText, Constants.TEXT_SIZE_NORMAL); + SWTUtils.addSelectionListener(lnkInfoText, () -> { SWTUtils.openURL(Messages.getString("config.fido2.InfoURL")); }); + + FormLayout STANDARD_LAYOUT = new FormLayout(); + STANDARD_LAYOUT.marginHeight = 10; + STANDARD_LAYOUT.marginWidth = 5; + + this.grpFidoSettings = new Group(this, SWT.NONE); + this.grpFidoSettings.setLayout(STANDARD_LAYOUT); + SWTUtils.anchor(grpFidoSettings).top(lnkInfoText,5).left(0,5).right(100,-5); + SWTUtils.setFontHeight(grpFidoSettings, Constants.TEXT_SIZE_NORMAL); + + this.btnFido2ByDefault = new Button(this.grpFidoSettings, SWT.CHECK); + SWTUtils.anchor(btnFido2ByDefault).top(0).left(0,5).right(100,-5); + SWTUtils.setFontHeight(btnFido2ByDefault, Constants.TEXT_SIZE_BUTTON); + SWTUtils.addSelectionListener(btnFido2ByDefault, () -> { this.configurationContainer.fido2ByDefault = btnFido2ByDefault.getSelection(); }); + + reloadResources(); + } + + @Override + public void reloadResources() { + SWTUtils.setLocalizedText(lnkInfoText, "config.fido2.AboutFIDO"); + SWTUtils.setLocalizedText(grpFidoSettings, "config.fido2.Group"); + SWTUtils.setLocalizedText(btnFido2ByDefault, "config.fido2.ByDefault"); + } + + @Override + public void initConfiguration(ConfigurationManager provider) { + this.configurationContainer.fido2ByDefault = provider.getFido2ByDefault(); + } + + @Override + public void loadConfiguration() { + btnFido2ByDefault.setSelection(this.configurationContainer.fido2ByDefault); + } + + @Override + public void storeConfiguration(ConfigurationManager store) { + store.setFido2ByDefaultPersistent(this.configurationContainer.fido2ByDefault); + } + + @Override + public void validateSettings(int resumeIndex) throws Exception {} +} diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/KeystoreConfigurationComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/KeystoreConfigurationComposite.java index 862fc424..1a0d4f0f 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/KeystoreConfigurationComposite.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/KeystoreConfigurationComposite.java @@ -427,16 +427,6 @@ public class KeystoreConfigurationComposite extends ConfigurationCompositeBase { this.txtKeystoreKeyPass.setText(keypass); } - /* - * (non-Javadoc) - * - * @see at.asit.pdfover.gui.composites.StateComposite#doLayout() - */ - @Override - public void doLayout() { - layout(true, true); - } - @Override public void initConfiguration(ConfigurationManager provider) { ConfigurationDataInMemory config = this.configurationContainer; diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/SimpleConfigurationComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/SimpleConfigurationComposite.java index 8437dbc3..a1d43f07 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/SimpleConfigurationComposite.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/SimpleConfigurationComposite.java @@ -597,16 +597,6 @@ public class SimpleConfigurationComposite extends ConfigurationCompositeBase { signatureBlockPreviewChanged(); } - /* - * (non-Javadoc) - * - * @see at.asit.pdfover.gui.composites.StateComposite#doLayout() - */ - @Override - public void doLayout() { - layout(true, true); - } - @Override public void initConfiguration(ConfigurationManager provider) { this.configurationContainer.setMobileNumber(provider.getDefaultMobileNumberPersistent()); 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 492c1c30..adf03913 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 @@ -190,4 +190,7 @@ public class ConfigurationDataInMemory { public @Nonnull String saveFilePostFix = Constants.DEFAULT_POSTFIX; + /** whether fido2 authentication should be selected by default */ + public boolean fido2ByDefault = false; + } 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 fd5085f7..cdb50c97 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 @@ -271,6 +271,8 @@ public class ConfigurationManager { String updateCheck = diskConfig.getProperty(Constants.CFG_UPDATE_CHECK); if (updateCheck != null) setUpdateCheckPersistent(!updateCheck.equalsIgnoreCase(Constants.FALSE)); + + setFido2ByDefaultPersistent(Constants.TRUE.equalsIgnoreCase(diskConfig.getProperty(Constants.CFG_FIDO2_BY_DEFAULT))); log.info("Successfully loaded config from: " + getConfigurationFileName()); loaded = true; @@ -368,6 +370,9 @@ public class ConfigurationManager { if (!getUpdateCheck()) setProperty(props, Constants.CFG_UPDATE_CHECK, Constants.FALSE); + + if (getFido2ByDefault()) + setProperty(props, Constants.CFG_FIDO2_BY_DEFAULT, Constants.TRUE); setProperty(props, Constants.SIGNATURE_PROFILE, ISNOTNULL(getSignatureProfile().name())); @@ -902,6 +907,12 @@ public class ConfigurationManager { return this.configuration.enabledPlaceholderUsage; } + public void setFido2ByDefaultPersistent(boolean bool) { + this.configuration.fido2ByDefault = bool; + } + public boolean getFido2ByDefault() { + return this.configuration.fido2ByDefault; + } } diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/State.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/State.java index a6cca51f..c039f21a 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/State.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/State.java @@ -17,6 +17,7 @@ package at.asit.pdfover.gui.workflow.states; //Imports import at.asit.pdfover.gui.workflow.StateMachine; +import at.asit.pdfover.gui.workflow.config.ConfigurationManager; /** * Base state class @@ -39,6 +40,8 @@ public abstract class State { this.nextState = this; } + public ConfigurationManager getConfig() { return this.stateMachine.configProvider; } + /** * Gets the next logical state or null if this their is no state transition * @return the next state (or null) 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 4b38ada0..73cdf4ca 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 @@ -121,6 +121,7 @@ config.LicenseURL=https://technology.a-sit.at/en/terms-of-a-license/ config.DataProtection=Data Protection Statement config.DataProtectionStatement=The software PDF-Over processes the data required for the signature process locally on the installed device. The signature process with the citizen card is carried out locally. During the signature process with the Handy-Signatur, the PDF document to be signed is sent to the company A-Trust. The storage period and further data protection information on the mobile phone signature can be found in the data protection declaration of A-Trust at <a>https://www.a-trust.at/MediaProvider/2357/datenschutzerklaerung.pdf</a>. config.DataProtectionURL=https://www.a-trust.at/MediaProvider/2357/datenschutzerklaerung.pdf +config.FIDO2=&FIDO2 config.Advanced=Ad&vanced config.Keystore=&Keystore config.Simple=Basi&c @@ -266,3 +267,7 @@ config.UpdateStatus.CHECKING=Checking for updates... config.UpdateStatus.OUTDATED=New version available. <a>Update now</a>? config.UpdateStatus.UP_TO_DATE=PDF-Over is up to date. <a>Check again</a>? config.UpdateStatus.FAILED=Update check failed. <a>Retry</a>? +config.fido2.AboutFIDO=ID Austria users can optionally substitute a suitable hardware security token for app authentication.\n\nThis does not replace username/password entry. However, instead of confirming the signature in the smartphone app, the user instead confirms it using their security token.\n\nFurther information regarding supported tokens is available at <a>oesterreich.gv.at</a>. +config.fido2.InfoURL=https://www.oesterreich.gv.at/id-austria/haeufige-fragen/allgemeines-zu-id-austria#fido +config.fido2.Group=FIDO2 settings +config.fido2.ByDefault=Select FIDO2 authentication by default 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 957b3c20..b09b249c 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 @@ -112,10 +112,15 @@ config.LicenseURL=https://technology.a-sit.at/lizenzbedingungen/ config.DataProtection=Datenschutzinformation config.DataProtectionStatement=Die Software PDF-Over verarbeitet für den Signaturvorgang benötigte Daten lokal auf dem installierten Gerät. Der Signaturvorgang mit der Bürgerkarte wird lokal durchgeführt. Beim Signaturvorgang mit der Handy-Signatur wird das zu signierende PDF Dokument an die Firma A-Trust gesendet. Die Speicherdauer sowie weitere Datenschutzinformationen zur Handy-Signatur entnehmen Sie bitte der Datenschutzerklärung der Firma A-Trust: <a>https://www.a-trust.at/MediaProvider/2357/datenschutzerklaerung.pdf</a>. config.DataProtectionURL=https://www.a-trust.at/MediaProvider/2357/datenschutzerklaerung.pdf +config.FIDO2=&FIDO2 config.Advanced=Er&weitert config.Keystore=&Keystore config.Simple=&Einfach config.ShowLogDirectory=Logs anzeigen +config.fido2.AboutFIDO=Nutzer:innen mit ID Austria können einen Hardware-Sicherheitstoken als Ersatz zum Smartphone zur Auslösung von PDF-Signaturen verwenden.\n\nDie Eingabe von Benutzername und Passwort ist weiterhin notwendig, aber die Freigabe über die App wird durch die Freigabe über den Hardware-Token ersetzt.\n\nWeitere Informationen erhalten Sie auf <a>der Informationsseite der ID-Austria</a>. +config.fido2.InfoURL=https://www.oesterreich.gv.at/id-austria/haeufige-fragen/allgemeines-zu-id-austria#fido +config.fido2.Group=FIDO2-Einstellungen +config.fido2.ByDefault=FIDO2 standardmäßig auswählen dataSourceSelection.DropLabel=Dokument hierher ziehen dataSourceSelection.DropLabel2=oder... dataSourceSelection.browse=&Durchsuchen um ein Dokument zu wählen |