Mercurial > hg > release > icedtea-web-1.8
changeset 1248:7e1e9ab4824d
All dialogs are able to accept answer from standard input and thus works in headless mode
* netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java: turned headless/logic order. Headless is now only hanging output, not behavior.
* netx/net/sourceforge/jnlp/resources/Messages.properties: Changed KSheadlesWarning added HeadlessDialogues AWPstdoutHint1-3 PAPstdinInfo and HDwrongValue keys for headless dialogues.
* netx/net/sourceforge/jnlp/security/KeystorePasswordAttempter.java: headelss error changed to stdin reading. Shared code extracted to addPnewPassword
* netx/net/sourceforge/jnlp/security/SecurityDialog.java: small refactroings createTitle, new methods, and one more abstraction upon getPanel
* netx/net/sourceforge/jnlp/security/SecurityDialogMessageHandler.java: added and called processMessageInHeadless
* netx/net/sourceforge/jnlp/security/dialogresults/AccessWarningPaneComplexReturn.java: added method returning string with all possible values
* netx/net/sourceforge/jnlp/security/dialogresults/NamePassword.java: (readValue) got logic
* netx/net/sourceforge/jnlp/security/dialogs/AccessWarningPane.java: implemented readFromStdIn and helpToStdIn
* netx/net/sourceforge/jnlp/security/dialogs/AppletWarningPane.java: same
* netx/net/sourceforge/jnlp/security/dialogs/CertWarningPane.java: same
* netx/net/sourceforge/jnlp/security/dialogs/CertsInfoPane.java: same
* netx/net/sourceforge/jnlp/security/dialogs/MissingALACAttributePanel.java: same
* netx/net/sourceforge/jnlp/security/dialogs/MissingPermissionsAttributePanel.java: same
* netx/net/sourceforge/jnlp/security/dialogs/MoreInfoPane.java: same
* netx/net/sourceforge/jnlp/security/dialogs/PasswordAuthenticationPane.java: same
* netx/net/sourceforge/jnlp/security/dialogs/apptrustwarningpanel/AppTrustWarningPanel.java: same
* netx/net/sourceforge/jnlp/security/dialogs/apptrustwarningpanel/PartiallySignedAppTrustWarningPanel.java: same
* netx/net/sourceforge/jnlp/security/dialogs/remember/RememberDialog.java: logic of setOrUpdateRememberedState splited to two methods to allow headless to save added
* netx/net/sourceforge/jnlp/security/dialogs/SecurityDialogPanel.java: written default getText method, which creates stdout message from already done gui implementations
* netx/net/sourceforge/jnlp/util/logging/OutputController.java: added readLine method to allow simple reading of standard in
* tests/netx/unit/net/sourceforge/jnlp/security/SecurityDialogsTest.java: become NoStdOutErrTest. Disabled most partiallYsignedTests. Hard to mock certVerifier and securityDelegate
* tests/test-extensions/net/sourceforge/jnlp/util/logging/NoStdOutErrTest.java: enhanced to handle also stdout/err not jsut logger
line wrap: on
line diff
--- a/ChangeLog Wed Jun 17 17:15:52 2015 +0200 +++ b/ChangeLog Thu Jun 18 12:29:34 2015 +0200 @@ -1,3 +1,50 @@ +2015-06-18 Jiri Vanek <jvanek@redhat.com> + + All dialogs are able to accept answer from standard input and thus works in headless mode + * netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java: turned headless/logic + order. Headless is now only hanging output, not behavior. + * netx/net/sourceforge/jnlp/resources/Messages.properties: Changed KSheadlesWarning + added HeadlessDialogues AWPstdoutHint1-3 PAPstdinInfo and HDwrongValue keys + for headless dialogues. + * netx/net/sourceforge/jnlp/security/KeystorePasswordAttempter.java: headelss + error changed to stdin reading. Shared code extracted to addPnewPassword + * netx/net/sourceforge/jnlp/security/SecurityDialog.java: small refactroings + createTitle, new methods, and one more abstraction upon getPanel + * netx/net/sourceforge/jnlp/security/SecurityDialogMessageHandler.java: added + and called processMessageInHeadless + * netx/net/sourceforge/jnlp/security/dialogresults/AccessWarningPaneComplexReturn.java: + added method returning string with all possible values + * netx/net/sourceforge/jnlp/security/dialogresults/NamePassword.java: (readValue) + got logic + * netx/net/sourceforge/jnlp/security/dialogs/AccessWarningPane.java: implemented + readFromStdIn and helpToStdIn + * netx/net/sourceforge/jnlp/security/dialogs/AppletWarningPane.java: same + * netx/net/sourceforge/jnlp/security/dialogs/CertWarningPane.java: same + * netx/net/sourceforge/jnlp/security/dialogs/CertsInfoPane.java: same + * netx/net/sourceforge/jnlp/security/dialogs/MissingALACAttributePanel.java: same + * netx/net/sourceforge/jnlp/security/dialogs/MissingPermissionsAttributePanel.java: + same + * netx/net/sourceforge/jnlp/security/dialogs/MoreInfoPane.java: same + * netx/net/sourceforge/jnlp/security/dialogs/PasswordAuthenticationPane.java: + same + * netx/net/sourceforge/jnlp/security/dialogs/apptrustwarningpanel/AppTrustWarningPanel.java: + same + * netx/net/sourceforge/jnlp/security/dialogs/apptrustwarningpanel/PartiallySignedAppTrustWarningPanel.java: + same + * netx/net/sourceforge/jnlp/security/dialogs/remember/RememberDialog.java: logic + of setOrUpdateRememberedState splited to two methods to allow headless to save + added + * netx/net/sourceforge/jnlp/security/dialogs/SecurityDialogPanel.java: written + default getText method, which creates stdout message from already done gui implementations + * netx/net/sourceforge/jnlp/util/logging/OutputController.java: added readLine + method to allow simple reading of standard in + * tests/netx/unit/net/sourceforge/jnlp/security/SecurityDialogsTest.java: + become NoStdOutErrTest. Disabled most partiallYsignedTests. Hard to mock + certVerifier and securityDelegate + * tests/test-extensions/net/sourceforge/jnlp/util/logging/NoStdOutErrTest.java: + enhanced to handle also stdout/err not jsut logger + + 2015-06-16 Jiri Vanek <jvanek@redhat.com> All headless, xtrustatAll/None, shouldPrompt dialogue decisions moved into shared place
--- a/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java Thu Jun 18 12:29:34 2015 +0200 @@ -832,8 +832,9 @@ } //this call should endure even if (ever) will migration code be removed DirectoryValidator.DirectoryCheckResults r = new DirectoryValidator().ensureDirs(); - if (!JNLPRuntime.isHeadless()) { - if (r.getFailures() > 0) { + if (r.getFailures() > 0) { + OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, r.getMessage()); + if (!JNLPRuntime.isHeadless()) { JOptionPane.showMessageDialog(null, r.getMessage()); } }
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/resources/Messages.properties Thu Jun 18 12:29:34 2015 +0200 @@ -525,8 +525,14 @@ # KeyStores: set password KSresultUntilNow=Got {0} during keystore operation {1}. Attempts to unlock: {2} KSinvalidPassword=Invalid password? -KSheadlesWarning=Headless mode currently does not support runtime-passwords +KSheadlesWarning=Type new password and press ok. Give up by pressing return on empty line. KSnwPassHelp=Type new password and press ok. Give up by pressing anything else. +HeadlessDialogues=Type `exit` to terminate ITW, or type one of the below values. Prefix answer by "R " to remember decision and by "RC " to do so for whole codebase. +AWPstdoutHint1=You can type YES/NO or complex answer parseable by AccessWarningPaneComplexReturn.readValue. +AWPstdoutHint2=eg: YES,D(not_found_browser,false,null,true,)M(firefox,false,null,false,) +AWPstdoutHint3=where: global_answer,desktop_shortcut(browser_bin,fixJnlpHref,type:null_or_one_of{0},really_create)same_for_menu... +PAPstdinInfo=Type NAME space PASSWORD. Sorry, no spaces in name, no security, keep your screen safe: +HDwrongValue=Probably wrong value? # Deployment Configuration messages DCIncorrectValue=Property "{0}" has incorrect value "{1}". Possible values {2}.
--- a/netx/net/sourceforge/jnlp/security/KeystorePasswordAttempter.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/KeystorePasswordAttempter.java Thu Jun 18 12:29:34 2015 +0200 @@ -167,17 +167,20 @@ OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, s1); OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, Translator.R("KSinvalidPassword")); if (JNLPRuntime.isHeadless()) { - OutputController.getLogger().log(Translator.R("KSheadlesWarning")); - finish(firstEx); + OutputController.getLogger().printOutLn(s1 + "\n" + Translator.R("KSheadlesWarning")); + String s = OutputController.getLogger().readLine(); + if (s == null || s.trim().isEmpty()) { + finish(firstEx); + } + //if input is null or empty , exception is thrown from finish method + addPnewPassword(s, localPases); } else { String s = JOptionPane.showInputDialog(s1 + "\n" + Translator.R("KSnwPassHelp")); if (s == null) { finish(firstEx); } //if input is null, exception is thrown from finish method - SavedPassword users = new SavedPassword(s.toCharArray()); - passes.add(users); - localPases.add(users); + addPnewPassword(s, localPases); } //user already read all messages, now show only last one messages = ""; @@ -187,6 +190,12 @@ return null; } + private void addPnewPassword(String s, List<SavedPassword> localPases) { + SavedPassword users = new SavedPassword(s.toCharArray()); + passes.add(users); + localPases.add(users); + } + private void finish(Exception ex) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException, IOException, CertificateException { if (ex instanceof KeyStoreException) { throw (KeyStoreException) ex;
--- a/netx/net/sourceforge/jnlp/security/SecurityDialog.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/SecurityDialog.java Thu Jun 18 12:29:34 2015 +0200 @@ -223,24 +223,7 @@ } private void initDialog() { - String dialogTitle = ""; - if (dialogType == DialogType.CERT_WARNING) { - if (accessType == AccessType.VERIFIED) - dialogTitle = "Security Approval Required"; - else - dialogTitle = "Security Warning"; - } else if (dialogType == DialogType.MORE_INFO) - dialogTitle = "More Information"; - else if (dialogType == DialogType.CERT_INFO) - dialogTitle = "Details - Certificate"; - else if (dialogType == DialogType.ACCESS_WARNING) - dialogTitle = "Security Warning"; - else if (dialogType == DialogType.APPLET_WARNING) - dialogTitle = "Applet Warning"; - else if (dialogType == DialogType.PARTIALLYSIGNED_WARNING) - dialogTitle = "Security Warning"; - else if (dialogType == DialogType.AUTHENTICATION) - dialogTitle = "Authentication Required"; + String dialogTitle = createTitle(); setTitle(dialogTitle); setModalityType(ModalityType.MODELESS); @@ -277,6 +260,31 @@ addWindowFocusListener(adapter); } + private String createTitle() { + return createTitle(dialogType, accessType); + } + private static String createTitle(DialogType dtype, AccessType atype) { + String dialogTitle = ""; + if (dtype == DialogType.CERT_WARNING) { + if (atype == AccessType.VERIFIED) + dialogTitle = "Security Approval Required"; + else + dialogTitle = "Security Warning"; + } else if (dtype == DialogType.MORE_INFO) + dialogTitle = "More Information"; + else if (dtype == DialogType.CERT_INFO) + dialogTitle = "Details - Certificate"; + else if (dtype == DialogType.ACCESS_WARNING) + dialogTitle = "Security Warning"; + else if (dtype == DialogType.APPLET_WARNING) + dialogTitle = "Applet Warning"; + else if (dtype == DialogType.PARTIALLYSIGNED_WARNING) + dialogTitle = "Security Warning"; + else if (dtype == DialogType.AUTHENTICATION) + dialogTitle = "Authentication Required"; + return dialogTitle; + } + public AccessType getAccessType() { return accessType; } @@ -303,31 +311,35 @@ /* * find appropriate JPanel to given Dialog, based on {@link DialogType}. */ - private static SecurityDialogPanel getPanel(SecurityDialog sd) { + static SecurityDialogPanel getPanel(SecurityDialog sd) { + return getPanel(sd.dialogType, sd); + } + + static SecurityDialogPanel getPanel(DialogType type, SecurityDialog sd) { SecurityDialogPanel lpanel = null; - if (sd.dialogType == DialogType.CERT_WARNING) { + if (type == DialogType.CERT_WARNING) { lpanel = new CertWarningPane(sd, sd.certVerifier, (SecurityDelegate) sd.extras[0]); - } else if (sd.dialogType == DialogType.MORE_INFO) { + } else if (type == DialogType.MORE_INFO) { lpanel = new MoreInfoPane(sd, sd.certVerifier); - } else if (sd.dialogType == DialogType.CERT_INFO) { + } else if (type == DialogType.CERT_INFO) { lpanel = new CertsInfoPane(sd, sd.certVerifier); - } else if (sd.dialogType == DialogType.SINGLE_CERT_INFO) { + } else if (type == DialogType.SINGLE_CERT_INFO) { lpanel = new SingleCertInfoPane(sd, sd.certVerifier); - } else if (sd.dialogType == DialogType.ACCESS_WARNING) { + } else if (type == DialogType.ACCESS_WARNING) { lpanel = new AccessWarningPane(sd, sd.extras, sd.certVerifier); - } else if (sd.dialogType == DialogType.APPLET_WARNING) { + } else if (type == DialogType.APPLET_WARNING) { lpanel = new AppletWarningPane(sd, sd.certVerifier); - } else if (sd.dialogType == DialogType.PARTIALLYSIGNED_WARNING) { + } else if (type == DialogType.PARTIALLYSIGNED_WARNING) { lpanel = AppTrustWarningDialog.partiallySigned(sd, sd.file, (SecurityDelegate) sd.extras[0]); - } else if (sd.dialogType == DialogType.UNSIGNED_WARNING) { + } else if (type == DialogType.UNSIGNED_WARNING) { lpanel = AppTrustWarningDialog.unsigned(sd, sd.file); // Only necessary for applets on 'high security' or above - } else if (sd.dialogType == DialogType.AUTHENTICATION) { + } else if (type == DialogType.AUTHENTICATION) { lpanel = new PasswordAuthenticationPane(sd, sd.extras); - } else if (sd.dialogType == DialogType.UNSIGNED_EAS_NO_PERMISSIONS_WARNING) { + } else if (type == DialogType.UNSIGNED_EAS_NO_PERMISSIONS_WARNING) { lpanel = new MissingPermissionsAttributePanel(sd, sd.file.getTitle(), sd.file.getCodeBase().toExternalForm()); - } else if (sd.dialogType == DialogType.MISSING_ALACA) { + } else if (type == DialogType.MISSING_ALACA) { lpanel = new MissingALACAttributePanel(sd, sd.file.getTitle(), (String) sd.extras[0], (String) sd.extras[1]); - } else if (sd.dialogType == DialogType.MATCHING_ALACA) { + } else if (type == DialogType.MATCHING_ALACA) { lpanel = AppTrustWarningDialog.matchingAlaca(sd, sd.file, (String) sd.extras[0], (String) sd.extras[1]); } else { throw new RuntimeException("Unknown value of " + sd.dialogType + ". Panel will be null. Tahts not allowed."); @@ -410,4 +422,16 @@ return panel.getDefaultPositiveAnswer(); } + String getText() { + return panel.getText(); + } + + DialogResult readFromStdIn(String what){ + return panel.readFromStdIn(what); + } + + String helpToStdIn(){ + return panel.helpToStdIn(); + } + }
--- a/netx/net/sourceforge/jnlp/security/SecurityDialogMessageHandler.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/SecurityDialogMessageHandler.java Thu Jun 18 12:29:34 2015 +0200 @@ -37,6 +37,8 @@ package net.sourceforge.jnlp.security; +import java.io.IOException; + import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.security.AccessController; @@ -45,7 +47,9 @@ import java.util.concurrent.LinkedBlockingQueue; import net.sourceforge.jnlp.config.DeploymentConfiguration; import net.sourceforge.jnlp.runtime.JNLPRuntime; +import net.sourceforge.jnlp.runtime.Translator; import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletTrustConfirmation; +import net.sourceforge.jnlp.security.dialogresults.BasicDialogValue; import net.sourceforge.jnlp.security.dialogs.remember.RememberDialog; import net.sourceforge.jnlp.security.dialogs.remember.RememberableDialog; import net.sourceforge.jnlp.security.dialogs.remember.SavedRememberAction; @@ -124,9 +128,11 @@ unlockMessagesClient(message); } else { - if (!shouldPromptUser() || isHeadless()) { + if (!shouldPromptUser()) { message.userResponse = dialog.getDefaultNegativeAnswer(); unlockMessagesClient(message); + } else if (isHeadless()) { + processMessageInHeadless(dialog, message); } else { processMessageInGui(dialog, found, message); } @@ -166,6 +172,65 @@ dialog.setVisible(true); } + private void processMessageInHeadless(final SecurityDialog dialog, final SecurityDialogMessage message) { + try { + boolean keepGoing = true; + boolean repeatAll = true; + do { + try { + if (repeatAll){ + OutputController.getLogger().printOutLn(dialog.getText()); + } + OutputController.getLogger().printOutLn(Translator.R("HeadlessDialogues")); + OutputController.getLogger().printOutLn(dialog.helpToStdIn()); + String s = OutputController.getLogger().readLine(); + if (s == null) { + throw new IOException("Stream closed"); + } + if (s.trim().toLowerCase().equals("exit")) { + JNLPRuntime.exit(0); + } + boolean codebase = false; + boolean remember = false; + if (s.startsWith("RC ")){ + codebase = true; + remember = true; + s=s.substring(3); + } + if (s.startsWith("R ")){ + remember = true; + s=s.substring(2); + } + message.userResponse = dialog.readFromStdIn(s); + keepGoing = false; + try { + String value = BasicDialogValue.writeNUll(); + if (message.userResponse != null) { + value = message.userResponse.writeValue(); + } + RememberDialog.getInstance().setOrUpdateRememberedState(dialog, codebase, new SavedRememberAction(RememberDialog.createAction(remember, message.userResponse), value)); + } catch (Exception ex) { + OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, ex); + } + } catch (IOException eex) { + OutputController.getLogger().log(eex); + keepGoing = false; + } catch (IllegalArgumentException eeex){ + OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, eeex.toString()); + OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, eeex); + OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, Translator.R("HDwrongValue")); + repeatAll = false; + } catch (Exception ex) { + OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, ex.toString()); + OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex); + repeatAll = true; + } + } while (keepGoing); + } finally { + unlockMessagesClient(message); + } + } + protected void unlockMessagesClient(final SecurityDialogMessage msg) { /* Allow the client to continue on the other side */ if (msg.toDispose != null) {
--- a/netx/net/sourceforge/jnlp/security/dialogresults/AccessWarningPaneComplexReturn.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogresults/AccessWarningPaneComplexReturn.java Thu Jun 18 12:29:34 2015 +0200 @@ -36,6 +36,7 @@ */ package net.sourceforge.jnlp.security.dialogresults; +import java.util.EnumSet; import java.util.Objects; public class AccessWarningPaneComplexReturn implements DialogResult { @@ -102,6 +103,11 @@ public static enum Shortcut { BROWSER, GENERATED_JNLP, JNLP_HREF, JAVAWS_HTML; + + public static String allValues() { + EnumSet<Shortcut> all = EnumSet.of(BROWSER, GENERATED_JNLP, JNLP_HREF, JAVAWS_HTML); + return all.toString(); + } } @Override
--- a/netx/net/sourceforge/jnlp/security/dialogresults/NamePassword.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogresults/NamePassword.java Thu Jun 18 12:29:34 2015 +0200 @@ -69,7 +69,8 @@ public static NamePassword readValue(String s) { - throw new UnsupportedOperationException("Not supported yet."); + int i = s.indexOf(" "); + return new NamePassword(s.substring(0,i), s.substring(i+1).toCharArray()); } @Override
--- a/netx/net/sourceforge/jnlp/security/dialogs/AccessWarningPane.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/AccessWarningPane.java Thu Jun 18 12:29:34 2015 +0200 @@ -68,16 +68,19 @@ import net.sourceforge.jnlp.ShortcutDesc; import net.sourceforge.jnlp.config.DeploymentConfiguration; import net.sourceforge.jnlp.runtime.JNLPRuntime; +import net.sourceforge.jnlp.runtime.Translator; import net.sourceforge.jnlp.security.CertVerifier; import net.sourceforge.jnlp.security.SecurityDialog; import net.sourceforge.jnlp.security.SecurityDialogs.AccessType; import net.sourceforge.jnlp.security.dialogresults.AccessWarningPaneComplexReturn; import net.sourceforge.jnlp.security.dialogresults.BasicDialogValue; import net.sourceforge.jnlp.security.dialogresults.DialogResult; +import net.sourceforge.jnlp.security.dialogresults.YesNo; import net.sourceforge.jnlp.security.dialogs.remember.RememberPanelResult; import net.sourceforge.jnlp.security.dialogs.remember.RememberableDialog; import net.sourceforge.jnlp.util.FileUtils; import net.sourceforge.jnlp.util.XDesktopEntry; +import net.sourceforge.jnlp.util.docprovider.formatters.formatters.PlainTextFormatter; /** * Provides a panel to show inside a SecurityDialog. These dialogs are @@ -519,4 +522,21 @@ return new AccessWarningPaneComplexReturn(true); } + @Override + public DialogResult readFromStdIn(String what) { + return AccessWarningPaneComplexReturn.readValue(what); + } + + @Override + public String helpToStdIn() { + if (parent.getAccessType() == AccessType.CREATE_DESTKOP_SHORTCUT){ + return Translator.R("AWPstdoutHint1") + PlainTextFormatter.getLineSeparator() + + Translator.R("AWPstdoutHint2") + PlainTextFormatter.getLineSeparator() + + Translator.R("AWPstdoutHint3", AccessWarningPaneComplexReturn.ShortcutResult.Shortcut.allValues()) + PlainTextFormatter.getLineSeparator() + + Translator.R("AWPstdoutHint1") + PlainTextFormatter.getLineSeparator(); + } else { + return YesNo.yes().getAllowedValues().toString(); + } + } + }
--- a/netx/net/sourceforge/jnlp/security/dialogs/AppletWarningPane.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/AppletWarningPane.java Thu Jun 18 12:29:34 2015 +0200 @@ -126,4 +126,13 @@ return YesNoCancel.yes(); } + @Override + public DialogResult readFromStdIn(String what) { + return YesNoCancel.readValue(what); + } + @Override + public String helpToStdIn() { + return YesNoCancel.cancel().getAllowedValues().toString(); + } + }
--- a/netx/net/sourceforge/jnlp/security/dialogs/CertWarningPane.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/CertWarningPane.java Thu Jun 18 12:29:34 2015 +0200 @@ -374,5 +374,14 @@ public DialogResult getDefaultPositiveAnswer() { return YesNoSandbox.yes(); } + + @Override + public DialogResult readFromStdIn(String what) { + return YesNoSandbox.readValue(what); + } + @Override + public String helpToStdIn() { + return YesNoSandbox.sandbox().getAllowedValues().toString(); + } }
--- a/netx/net/sourceforge/jnlp/security/dialogs/CertsInfoPane.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/CertsInfoPane.java Thu Jun 18 12:29:34 2015 +0200 @@ -360,4 +360,14 @@ public DialogResult getDefaultPositiveAnswer() { return new Yes(); } + + @Override + public DialogResult readFromStdIn(String what) { + return Yes.readValue(what); + } + + @Override + public String helpToStdIn() { + return new Yes().getAllowedValues().toString(); + } }
--- a/netx/net/sourceforge/jnlp/security/dialogs/MissingALACAttributePanel.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/MissingALACAttributePanel.java Thu Jun 18 12:29:34 2015 +0200 @@ -202,4 +202,13 @@ return YesNo.yes(); } + @Override + public DialogResult readFromStdIn(String what) { + return YesNo.readValue(what); + } + + @Override + public String helpToStdIn() { + return YesNo.no().getAllowedValues().toString(); + } }
--- a/netx/net/sourceforge/jnlp/security/dialogs/MissingPermissionsAttributePanel.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/MissingPermissionsAttributePanel.java Thu Jun 18 12:29:34 2015 +0200 @@ -193,4 +193,14 @@ return YesNo.yes(); } + @Override + public DialogResult readFromStdIn(String what) { + return YesNo.readValue(what); + } + + @Override + public String helpToStdIn() { + return YesNo.no().getAllowedValues().toString(); + } + }
--- a/netx/net/sourceforge/jnlp/security/dialogs/MoreInfoPane.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/MoreInfoPane.java Thu Jun 18 12:29:34 2015 +0200 @@ -139,4 +139,13 @@ return new Yes(); } + @Override + public DialogResult readFromStdIn(String what) { + return Yes.readValue(what); + } + + @Override + public String helpToStdIn() { + return new Yes().getAllowedValues().toString(); + } }
--- a/netx/net/sourceforge/jnlp/security/dialogs/PasswordAuthenticationPane.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/PasswordAuthenticationPane.java Thu Jun 18 12:29:34 2015 +0200 @@ -50,6 +50,7 @@ import javax.swing.JLabel; import javax.swing.JPasswordField; import javax.swing.JTextField; +import net.sourceforge.jnlp.runtime.Translator; import net.sourceforge.jnlp.security.SecurityDialog; import net.sourceforge.jnlp.security.dialogresults.DialogResult; import net.sourceforge.jnlp.security.dialogresults.NamePassword; @@ -195,4 +196,14 @@ return null; } + @Override + public DialogResult readFromStdIn(String what) { + return NamePassword.readValue(what); + } + + @Override + public String helpToStdIn() { + return Translator.R("PAPstdinInfo"); + } + }
--- a/netx/net/sourceforge/jnlp/security/dialogs/SecurityDialogPanel.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/SecurityDialogPanel.java Thu Jun 18 12:29:34 2015 +0200 @@ -38,12 +38,21 @@ package net.sourceforge.jnlp.security.dialogs; import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.lang.reflect.Method; +import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JPanel; +import javax.swing.JRadioButton; import net.sourceforge.jnlp.security.CertVerifier; import net.sourceforge.jnlp.security.SecurityDialog; import net.sourceforge.jnlp.security.dialogresults.DialogResult; +import net.sourceforge.jnlp.util.docprovider.formatters.formatters.PlainTextFormatter; +import net.sourceforge.jnlp.util.logging.OutputController; +import net.sourceforge.jnlp.util.logging.TeeOutputStream; /** * Provides a JPanel for use in JNLP warning dialogs. @@ -92,5 +101,95 @@ public abstract DialogResult getDefaultPositiveAnswer(); + /** this is default SecurityDialog "toString". + * All extending panels are recommended to override this. + * However, this method is reading possible shown gui, and printing it to output + * so free of code, this to string have pretty nice results + * @return text gathered from components placed on this panel and cleaned from some html tags + */ + public String getText() { + String s = traverse(this); + if (s != null) { + s = s.replace("<html>", "").replace("</html>", "") + .replace("<head>", "").replace("</head>", "") + .replace("<body>", "").replace("</body>", "") + .replace("<br>", PlainTextFormatter.getLineSeparator()) + .replace("<BR>", PlainTextFormatter.getLineSeparator()) + .replace("<br/>", PlainTextFormatter.getLineSeparator()) + .replace("<BR/>", PlainTextFormatter.getLineSeparator()); //see htmlWrap and its usages.. but eg a href is ok to keep + s = s.replaceAll("(?m)^\\s+$", ""); + while (s.contains(PlainTextFormatter.getLineSeparator() + PlainTextFormatter.getLineSeparator())) { + s = s.replace(PlainTextFormatter.getLineSeparator() + PlainTextFormatter.getLineSeparator(), PlainTextFormatter.getLineSeparator()); + } + } + + return s; + } + + private String traverse(Container co) { + return traverse(co, true, JButton.class, JRadioButton.class, JCheckBox.class); + } + + private String traverse(Container co, boolean skipClassName, Class... skipClasses) { + StringBuilder sb = new StringBuilder(); + Component[] c = co.getComponents(); + compIter: + for (Component c1 : c) { + //searching to depth is important + if (c1 instanceof Container){ + String s = traverse((Container) c1); + sb.append(s); + } + //eg jlabel is also container + for (Class clazz : skipClasses) { + if (c1.getClass() == clazz){ + continue compIter; + } + } + String s; + Method getText = getGetText(c1.getClass()); + if (getText != null) { + s = getText(c1, getText); + } else { + s = c1.toString(); + } + if (s != null) { + s = s.trim(); + if (s.isEmpty()){ + continue; + } + if (!skipClassName){ + sb.append(s).append(PlainTextFormatter.getLineSeparator()); + } else + if (!s.contains(c1.getClass().getSimpleName())) { + sb.append(s).append(PlainTextFormatter.getLineSeparator()); + } + } + } + return sb.toString(); + } + + private Method getGetText(Class aClass) { + try { + String methodName = "getText"; + return aClass.getMethod(methodName); + } catch (Exception ex) { + OutputController.getLogger().log(ex); + return null; + } + } + + private String getText(Component c1, Method getText) { + try { + return (String) getText.invoke(c1); + } catch (Exception ex) { + OutputController.getLogger().log(ex); + return null; + } + } + + public abstract DialogResult readFromStdIn(String what); + + public abstract String helpToStdIn() ; }
--- a/netx/net/sourceforge/jnlp/security/dialogs/apptrustwarningpanel/AppTrustWarningPanel.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/apptrustwarningpanel/AppTrustWarningPanel.java Thu Jun 18 12:29:34 2015 +0200 @@ -309,4 +309,14 @@ return YesNoSandboxLimited.yes(); } + @Override + public DialogResult readFromStdIn(String what) { + return YesNoSandboxLimited.readValue(what); + } + + @Override + public String helpToStdIn() { + return YesNoSandboxLimited.yes().getAllowedValues().toString(); + } + }
--- a/netx/net/sourceforge/jnlp/security/dialogs/apptrustwarningpanel/PartiallySignedAppTrustWarningPanel.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/apptrustwarningpanel/PartiallySignedAppTrustWarningPanel.java Thu Jun 18 12:29:34 2015 +0200 @@ -182,4 +182,13 @@ return YesNoSandbox.yes(); } + @Override + public DialogResult readFromStdIn(String what) { + return YesNoSandbox.readValue(what); + } + @Override + public String helpToStdIn() { + return YesNoSandbox.sandbox().getAllowedValues().toString(); + } + }
--- a/netx/net/sourceforge/jnlp/security/dialogs/remember/RememberDialog.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/remember/RememberDialog.java Thu Jun 18 12:29:34 2015 +0200 @@ -48,12 +48,26 @@ public void setOrUpdateRememberedState(SecurityDialog dialog) { RememberableDialog found = findRememberablePanel(dialog); + if (found == null) { + return; + } String value = BasicDialogValue.writeNUll(); if (found.getValue()!=null){ value = found.getValue().writeValue(); } SavedRememberAction action = new SavedRememberAction(createAction(found.getRemeberAction().isRemember(), found.getValue()), value); - UnsignedAppletTrustConfirmation.updateAppletAction(found.getFile(), action, found.getRemeberAction().isCodebase(), (Class<RememberableDialog>) found.getClass()); + setOrUpdateRememberedState(dialog, found.getRemeberAction().isCodebase(), action); + } + + /* + * for headless dialogues + */ + public void setOrUpdateRememberedState(SecurityDialog dialog, boolean wholeCodebase, SavedRememberAction action) { + RememberableDialog found = findRememberablePanel(dialog); + if (found == null) { + return; + } + UnsignedAppletTrustConfirmation.updateAppletAction(found.getFile(), action, wholeCodebase, (Class<RememberableDialog>) found.getClass()); } public SavedRememberAction getRememberedState(SecurityDialog dialog) { @@ -95,7 +109,7 @@ return null; } - private ExecuteAppletAction createAction(boolean pernament, DialogResult value) { + public static ExecuteAppletAction createAction(boolean pernament, DialogResult value) { if (value == null){ return ExecuteAppletAction.NO; }
--- a/netx/net/sourceforge/jnlp/util/logging/OutputController.java Wed Jun 17 17:15:52 2015 +0200 +++ b/netx/net/sourceforge/jnlp/util/logging/OutputController.java Thu Jun 18 12:29:34 2015 +0200 @@ -35,6 +35,9 @@ */ package net.sourceforge.jnlp.util.logging; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; @@ -105,6 +108,8 @@ private List<MessageWithHeader> messageQue = new LinkedList<MessageWithHeader>(); private MessageQueConsumer messageQueConsumer = new MessageQueConsumer(); Thread consumerThread; + /*stdin reader for headless dialogues*/ + private BufferedReader br; //bounded to instance private class MessageQueConsumer implements Runnable { @@ -406,5 +411,12 @@ SystemLogHolder.INSTANCE = sysLog; } + public synchronized String readLine() throws IOException { + if (br == null) { + br = new BufferedReader(new InputStreamReader(System.in)); + } + return br.readLine(); + } + }
--- a/tests/netx/unit/net/sourceforge/jnlp/security/SecurityDialogsTest.java Wed Jun 17 17:15:52 2015 +0200 +++ b/tests/netx/unit/net/sourceforge/jnlp/security/SecurityDialogsTest.java Thu Jun 18 12:29:34 2015 +0200 @@ -36,8 +36,10 @@ */ package net.sourceforge.jnlp.security; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Field; import java.net.MalformedURLException; import java.net.URL; @@ -56,8 +58,8 @@ import net.sourceforge.jnlp.security.dialogresults.BasicDialogValue; import net.sourceforge.jnlp.security.dialogresults.NamePassword; import net.sourceforge.jnlp.security.dialogresults.YesNo; -import net.sourceforge.jnlp.security.dialogresults.YesNoSandbox; import net.sourceforge.jnlp.util.FileUtils; +import net.sourceforge.jnlp.util.logging.NoStdOutErrTest; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; @@ -65,7 +67,7 @@ import org.junit.BeforeClass; import org.junit.Test; -public class SecurityDialogsTest { +public class SecurityDialogsTest extends NoStdOutErrTest { private static boolean wasHeadless; private static boolean wasTrustAll; @@ -212,11 +214,11 @@ testAllDialogs(ExpectedResults.PositiveResults); checkUnsignedActing(true); setAS(AppletSecurityLevel.ASK_UNSIGNED); - checkUnsignedActing(true, false); + checkUnsignedActing(true, null); setAS(AppletSecurityLevel.DENY_ALL); - checkUnsignedActing(false); + checkUnsignedActing(false, null); setAS(AppletSecurityLevel.DENY_UNSIGNED); - checkUnsignedActing(false); + checkUnsignedActing(false, null); } finally { resetQueue(); } @@ -230,17 +232,20 @@ setPrompt(true); //should not metter becasue is headless setAS(AppletSecurityLevel.ALLOW_UNSIGNED); fakeQueue(); + InputStream backup = System.in; try { fakeQueue(); - testAllDialogs(ExpectedResults.NegativeResults); + System.setIn(new ByteArrayInputStream(new byte[0])); + testAllDialogsNullResaults(); checkUnsignedActing(true); setAS(AppletSecurityLevel.ASK_UNSIGNED); - checkUnsignedActing(false); + checkUnsignedActing(false, null); setAS(AppletSecurityLevel.DENY_ALL); - checkUnsignedActing(false); + checkUnsignedActing(false, null); setAS(AppletSecurityLevel.DENY_UNSIGNED); - checkUnsignedActing(false); + checkUnsignedActing(false, null); } finally { + System.setIn(backup); resetQueue(); } } @@ -257,11 +262,11 @@ testAllDialogs(ExpectedResults.PositiveResults); checkUnsignedActing(true); setAS(AppletSecurityLevel.ASK_UNSIGNED); - checkUnsignedActing(true, false); + checkUnsignedActing(true, null); setAS(AppletSecurityLevel.DENY_ALL); - checkUnsignedActing(false); + checkUnsignedActing(false, null); setAS(AppletSecurityLevel.DENY_UNSIGNED); - checkUnsignedActing(false); + checkUnsignedActing(false, null); } finally { resetQueue(); } @@ -279,11 +284,11 @@ testAllDialogs(ExpectedResults.NegativeResults); checkUnsignedActing(true); setAS(AppletSecurityLevel.ASK_UNSIGNED); - checkUnsignedActing(false); + checkUnsignedActing(false, null); setAS(AppletSecurityLevel.DENY_ALL); - checkUnsignedActing(false); + checkUnsignedActing(false, null); setAS(AppletSecurityLevel.DENY_UNSIGNED); - checkUnsignedActing(false); + checkUnsignedActing(false, null); } finally { resetQueue(); } @@ -313,18 +318,46 @@ Assert.assertEquals(r.b, r9); } - private void checkUnsignedActing(boolean b) throws MalformedURLException { + private void testAllDialogsNullResaults() throws MalformedURLException { + //anything but shoertcut + AccessWarningPaneComplexReturn r1 = SecurityDialogs.showAccessWarningDialog(SecurityDialogs.AccessType.PRINTER, crtJnlpF(), null); + Assert.assertEquals(null, r1); + //shortcut + AccessWarningPaneComplexReturn r2 = SecurityDialogs.showAccessWarningDialog(SecurityDialogs.AccessType.CREATE_DESTKOP_SHORTCUT, crtJnlpF(), null); + Assert.assertEquals(null, r2); + YesNo r3 = SecurityDialogs.showUnsignedWarningDialog(crtJnlpF()); + Assert.assertEquals(null, r3); + //cant emualte security delegate now + //YesNoSandbox r4 = SecurityDialogs.showCertWarningDialog(SecurityDialogs.AccessType.UNVERIFIED, crtJnlpF(), null, null); + //Assert.assertEquals(r.p, r4.getValue()); + //YesNo r5 = SecurityDialogs.showPartiallySignedWarningDialog(crtJnlpF(), null, null); + //Assert.assertEquals(r.ea, r5); + NamePassword r6 = SecurityDialogs.showAuthenicationPrompt(null, 123456, null, null); + Assert.assertEquals(null, r6); + boolean r7 = SecurityDialogs.showMissingALACAttributePanel(crtJnlpF(), null, new HashSet<URL>()); + Assert.assertEquals(false, r7); + boolean r8 = SecurityDialogs.showMatchingALACAttributePanel(crtJnlpF(), url, new HashSet<URL>()); + Assert.assertEquals(false, r8); + boolean r9 = SecurityDialogs.showMissingPermissionsAttributeDialogue(crtJnlpF()); + Assert.assertEquals(false, r9); + } + + private void checkUnsignedActing(Boolean b) throws MalformedURLException { checkUnsignedActing(b, b); } /* * testPartiallySignedBehaviour(); needs security delegate to set sandbox, so somtetimes results are strange */ - private void checkUnsignedActing(boolean b1, boolean b2) throws MalformedURLException { - boolean r10 = testUnsignedBehaviour(); - Assert.assertEquals(b1, r10); - boolean r11 = testPartiallySignedBehaviour(); - Assert.assertEquals(b2, r11); + private void checkUnsignedActing(Boolean b1, Boolean b2) throws MalformedURLException { + if (b1 != null) { + boolean r10 = testUnsignedBehaviour(); + Assert.assertEquals(b1.booleanValue(), r10); + } + if (b2 != null) { + boolean r11 = testPartiallySignedBehaviour(); + Assert.assertEquals(b2.booleanValue(), r11); + } } private boolean testUnsignedBehaviour() throws MalformedURLException { @@ -419,32 +452,43 @@ Assert.assertEquals(metcounter, npecounter + allowedRuns); } - private void checkUnsignedNPE(boolean b) throws MalformedURLException { + private void checkUnsignedNPE(Boolean b) throws MalformedURLException { checkUnsignedNPE(b, b); } /* testPartiallySignedBehaviour(); needs security delegate to set sandbox, so somtetimes results are strange */ - private void checkUnsignedNPE(boolean b1, boolean b2) throws MalformedURLException { + private void checkUnsignedNPE(Boolean b1, Boolean b2) throws MalformedURLException { int metcounter = 0; + int maxcount = 0; boolean ex1 = false; boolean ex2 = false; - try { - metcounter++; - testPartiallySignedBehaviour(); - } catch (NullPointerException ex) { - ex1 = true; + if (b1 != null) { + maxcount++; + try { + metcounter++; + testPartiallySignedBehaviour(); + } catch (NullPointerException ex) { + ex1 = true; + } } - try { - metcounter++; - testUnsignedBehaviour(); - } catch (NullPointerException ex) { - ex2 = true; + if (b2 != null) { + maxcount++; + try { + metcounter++; + testUnsignedBehaviour(); + } catch (NullPointerException ex) { + ex2 = true; + } } - Assert.assertEquals(2, metcounter); - Assert.assertEquals(b1, ex1); - Assert.assertEquals(b2, ex2); + Assert.assertEquals(maxcount, metcounter); + if (b1 != null) { + Assert.assertEquals(b1.booleanValue(), ex1); + } + if (b2 != null) { + Assert.assertEquals(b2.booleanValue(), ex2); + } } @Test(timeout = 10000)//if gui pops up @@ -479,11 +523,11 @@ setAS(AppletSecurityLevel.ASK_UNSIGNED); try { fakeQueue(); - checkUnsignedActing(true, false); + checkUnsignedActing(true, null); setAS(AppletSecurityLevel.DENY_ALL); - checkUnsignedActing(false); + checkUnsignedActing(false, null); setAS(AppletSecurityLevel.DENY_UNSIGNED); - checkUnsignedActing(false); + checkUnsignedActing(false, null); } finally { resetQueue(); } @@ -532,15 +576,15 @@ fakeQueue(); boolean r10 = testUnsignedBehaviour(); Assert.assertEquals(false, r10); - checkUnsignedNPE(false); + checkUnsignedNPE(null, false); setAS(AppletSecurityLevel.DENY_ALL); boolean r11 = testUnsignedBehaviour(); Assert.assertEquals(false, r11); - checkUnsignedNPE(false); + checkUnsignedNPE(null, false); setAS(AppletSecurityLevel.DENY_UNSIGNED); boolean r12 = testUnsignedBehaviour(); Assert.assertEquals(false, r12); - checkUnsignedNPE(false); + checkUnsignedNPE(null, false); } finally { resetQueue(); }
--- a/tests/test-extensions/net/sourceforge/jnlp/util/logging/NoStdOutErrTest.java Wed Jun 17 17:15:52 2015 +0200 +++ b/tests/test-extensions/net/sourceforge/jnlp/util/logging/NoStdOutErrTest.java Thu Jun 18 12:29:34 2015 +0200 @@ -37,6 +37,9 @@ package net.sourceforge.jnlp.util.logging; +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.reflect.Field; import java.lang.reflect.Method; import net.sourceforge.jnlp.ServerAccess; import org.junit.AfterClass; @@ -60,7 +63,16 @@ /* * "printed" exceptions are otherwise consumed via junit if thrown :-/ */ + private static Object origOut; + private static Object origErr; + private static PrintStream dummy = new PrintStream(new OutputStream() { + @Override + public void write(int b) { + //DO NOTHING + } + }); + @BeforeClass public static synchronized void disableStds() { try { @@ -73,6 +85,7 @@ OutputController.getLogger().flush(); origialStds = LogConfig.getLogConfig().isLogToStreams(); invokeSetLogToStreams(false); + removeStreams(); } catch (Exception ex) { ServerAccess.logException(ex); } @@ -83,6 +96,7 @@ try { OutputController.getLogger().flush(); invokeSetLogToStreams(origialStds); + resetStreams(); } catch (Exception ex) { ServerAccess.logException(ex); } @@ -97,4 +111,32 @@ ServerAccess.logException(ex); } } + + private static synchronized void removeStreams() { + try { + Field lcs1 = OutputController.class.getDeclaredField("outLog"); + lcs1.setAccessible(true); + origOut = lcs1.get(OutputController.getLogger()); + Field lcs2 = OutputController.class.getDeclaredField("errLog"); + lcs2.setAccessible(true); + origErr = lcs1.get(OutputController.getLogger()); + lcs1.set(OutputController.getLogger(), new PrintStreamLogger(dummy)); + lcs2.set(OutputController.getLogger(), new PrintStreamLogger(dummy)); + } catch (Exception ex) { + ServerAccess.logException(ex); + } + } + + private static synchronized void resetStreams() { + try { + Field lcs1 = OutputController.class.getDeclaredField("outLog"); + lcs1.setAccessible(true); + Field lcs2 = OutputController.class.getDeclaredField("errLog"); + lcs2.setAccessible(true); + lcs1.set(OutputController.getLogger(), origOut); + lcs2.set(OutputController.getLogger(), origErr); + } catch (Exception ex) { + ServerAccess.logException(ex); + } + } }