diff options
21 files changed, 3204 insertions, 1 deletions
@@ -1,3 +1,56 @@ +2013-02-27 Jiri Vanek <[email protected]> + + Added backend and settings for extended applet security + * netx/net/sourceforge/jnlp/config/Defaults.java: deployment.security.level + added to defaults with its validator + * netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java: Added + deployment.security.level (KEY_SECURITY_LEVEL)key and + .appletTrustSettings (APPLET_TRUST_SETTINGS)filename with getters + * netx/net/sourceforge/jnlp/config/SecurityValueValidator.java: + Simple validator for value of deployment.security.level based on parsing + in AppletSecurityLevel.fromString + * netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java: + Incorporated UnsignedAppletsTrustingListPanel panel + * netx/net/sourceforge/jnlp/controlpanel/UnsignedAppletActionTableModel.java: + Backend for main tables in UnsignedAppletsTrustingListPanel + * netx/net/sourceforge/jnlp/controlpanel/UnsignedAppletsTrustingListPanel.java: + GUI for manipulate the deployment.security.level values and content of + .appletTrustSettings files + * netx/net/sourceforge/jnlp/resources/Messages.properties: + Added keys and values for new; user visible, strings + * netx/net/sourceforge/jnlp/security/appletextendedsecurity/AppletSecurityLevel.java: + Object representation of deployment.security.level value + * netx/net/sourceforge/jnlp/security/appletextendedsecurity/AppletStartupSecuritySettings.java: + Entrance singleton for current deployment.security.level policy and records. + * netx/net/sourceforge/jnlp/security/appletextendedsecurity/ExecuteUnsignedApplet.java: + Object representation of action upon record in .appletTrustSettings + * netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletActionEntry.java: + Object representation of one item in .appletTrustSettings + .appletTrustSettings by itw (except settings part) + * netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletActionStorage.java + Minimal set of functionality requested for accessing the + * netx/net/sourceforge/jnlp/security/appletextendedsecurity/UrlRegEx.java + Simple class which should help to distinguish between plain String + and String keeping UrlRegex + * netx/net/sourceforge/jnlp/security/appletextendedsecurity/impl/UnsignedAppletActionStorageExtendedImpl.java: + Extended implementation of UnsignedAppletActionStorageImpl which have + additional "for settings" functionality + * netx/net/sourceforge/jnlp/security/appletextendedsecurity/impl/UnsignedAppletActionStorageImpl.java: + Object representation of.appletTrustSettings file. It Should be multi-thread/app safe and + should be always actual. Based on LockingReaderWriter. + * netx/net/sourceforge/jnlp/util/lockingfile/LockedFile.java: + Utility class with functionality to lock file in muti-app/thread environment + * netx/net/sourceforge/jnlp/util/lockingfile/LockingReaderWriter.java: + Utility class with functionality to lock file during reading/writing + in muti-app/thread environment + * netx/net/sourceforge/jnlp/util/lockingfile/StorageIoException.java: + Wrapper for common, but rare IOException extending RuntimeExceptionaround + for LockingReaderWriter to avoid numerous declarations. + * tests/netx/unit/net/sourceforge/jnlp/security/appletextendedsecurity/impl/UnsignedAppletActionStorageImplTest.java: + Tests of main methods in UnsignedAppletActionStorageImplTest focused on matching + * tests/netx/unit/net/sourceforge/jnlp/util/lockingfile/LockingReaderWriterTest.java: + Tests of multithread read/write to LockingReaderWriter + 2013-02-25 Adam Domurad <[email protected]> * netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: diff --git a/netx/net/sourceforge/jnlp/config/Defaults.java b/netx/net/sourceforge/jnlp/config/Defaults.java index 8b9785a..9e51d78 100644 --- a/netx/net/sourceforge/jnlp/config/Defaults.java +++ b/netx/net/sourceforge/jnlp/config/Defaults.java @@ -42,6 +42,7 @@ import static net.sourceforge.jnlp.runtime.Translator.R; import java.io.File; import java.util.HashMap; import java.util.Map; +import net.sourceforge.jnlp.security.appletextendedsecurity.AppletSecurityLevel; import net.sourceforge.jnlp.ShortcutDesc; import net.sourceforge.jnlp.runtime.JNLPProxySelector; @@ -384,6 +385,12 @@ public class Defaults { DeploymentConfiguration.KEY_PLUGIN_JVM_ARGUMENTS, null, null + }, + //unsigned applet security level + { + DeploymentConfiguration.KEY_SECURITY_LEVEL, + new SecurityValueValidator(), + null } }; diff --git a/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java b/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java index c7e3e33..98dc88b 100644 --- a/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java +++ b/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java @@ -51,6 +51,7 @@ public final class DeploymentConfiguration { public static final String DEPLOYMENT_DIR = ".icedtea"; public static final String DEPLOYMENT_CONFIG = "deployment.config"; public static final String DEPLOYMENT_PROPERTIES = "deployment.properties"; + public static final String APPLET_TRUST_SETTINGS = ".appletTrustSettings"; public static final String DEPLOYMENT_COMMENT = "Netx deployment configuration"; @@ -105,6 +106,9 @@ public final class DeploymentConfiguration { /** Boolean. Only show security prompts to user if true */ public static final String KEY_SECURITY_PROMPT_USER = "deployment.security.askgrantdialog.show"; + //enum of AppletSecurityLevel in result + public static final String KEY_SECURITY_LEVEL = "deployment.security.level"; + public static final String KEY_SECURITY_TRUSTED_POLICY = "deployment.security.trusted.policy"; /** Boolean. Only give AWTPermission("showWindowWithoutWarningBanner") if true */ @@ -196,6 +200,17 @@ public final class DeploymentConfiguration { load(true); } + public static File getAppletTrustUserSettingsPath() { + return new File(System.getProperty("user.home") + File.separator + DEPLOYMENT_DIR + + File.separator + APPLET_TRUST_SETTINGS); + } + + public static File getAppletTrustGlobalSettingsPath() { + return new File(File.separator + "etc" + File.separator + ".java" + File.separator + + "deployment" + File.separator + APPLET_TRUST_SETTINGS); + + } + /** * Initialize this deployment configuration by reading configuration files. * Generally, it will try to continue and ignore errors it finds (such as file not found). diff --git a/netx/net/sourceforge/jnlp/config/SecurityValueValidator.java b/netx/net/sourceforge/jnlp/config/SecurityValueValidator.java new file mode 100644 index 0000000..099cabd --- /dev/null +++ b/netx/net/sourceforge/jnlp/config/SecurityValueValidator.java @@ -0,0 +1,73 @@ +/* Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ +package net.sourceforge.jnlp.config; + +import net.sourceforge.jnlp.security.appletextendedsecurity.AppletSecurityLevel; + +class SecurityValueValidator implements ValueValidator { + + public SecurityValueValidator() { + } + + @Override + public void validate(Object value) throws IllegalArgumentException { + if (value == null) { + throw new IllegalArgumentException("Value can't be null"); + } + if (value instanceof AppletSecurityLevel) { + //?? + return; + } + if (!(value instanceof String)) { + throw new IllegalArgumentException("Expected was String, was " + value.getClass()); + } + try { + AppletSecurityLevel validated = AppletSecurityLevel.fromString((String) value); + if (validated == null) { + throw new IllegalArgumentException("Result can't be null, was"); + } + //thrown by fromString + } catch (RuntimeException ex) { + throw new IllegalArgumentException(ex); + } + } + + @Override + public String getPossibleValues() { + return AppletSecurityLevel.allToString(); + } + +} diff --git a/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java b/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java index a53bb81..d56cfba 100644 --- a/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java +++ b/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java @@ -41,6 +41,7 @@ import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingConstants; @@ -230,7 +231,10 @@ public class ControlPanel extends JFrame { new SettingsPanel(Translator.R("CPTabNetwork"), createNetworkSettingsPanel()), // TODO: This is commented out since this is not implemented yet // new SettingsPanel(Translator.R("CPTabRuntimes"), createRuntimesSettingsPanel()), - new SettingsPanel(Translator.R("CPTabSecurity"), createSecuritySettingsPanel()), }; + new SettingsPanel(Translator.R("CPTabSecurity"), createSecuritySettingsPanel()), + //todo refactor to work with tmp file and apply as asu designed it + new SettingsPanel(Translator.R("APPEXTSECControlPanelExtendedAppletSecurityTitle"), new UnsignedAppletsTrustingListPanel(DeploymentConfiguration.getAppletTrustGlobalSettingsPath(),DeploymentConfiguration.getAppletTrustUserSettingsPath(), this.config) ) + }; // Add panels. final JPanel settingsPanel = new JPanel(new CardLayout()); @@ -360,6 +364,7 @@ public class ControlPanel extends JFrame { config.save(); } catch (IOException e) { e.printStackTrace(); + JOptionPane.showMessageDialog(this, e); } } diff --git a/netx/net/sourceforge/jnlp/controlpanel/UnsignedAppletActionTableModel.java b/netx/net/sourceforge/jnlp/controlpanel/UnsignedAppletActionTableModel.java new file mode 100644 index 0000000..759d3a8 --- /dev/null +++ b/netx/net/sourceforge/jnlp/controlpanel/UnsignedAppletActionTableModel.java @@ -0,0 +1,205 @@ +/* Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ +package net.sourceforge.jnlp.controlpanel; + +import java.util.Date; +import javax.swing.event.TableModelEvent; +import javax.swing.table.AbstractTableModel; +import net.sourceforge.jnlp.runtime.Translator; +import net.sourceforge.jnlp.security.appletextendedsecurity.ExecuteUnsignedApplet; +import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletActionEntry; +import net.sourceforge.jnlp.security.appletextendedsecurity.UrlRegEx; +import net.sourceforge.jnlp.security.appletextendedsecurity.impl.UnsignedAppletActionStorageExtendedImpl; + +public class UnsignedAppletActionTableModel extends AbstractTableModel { + + final UnsignedAppletActionStorageExtendedImpl back; + private final String[] columns = new String[]{Translator.R("APPEXTSECguiTableModelTableColumnAction"), + Translator.R("APPEXTSECguiTableModelTableColumnDateOfAction"), + Translator.R("APPEXTSECguiTableModelTableColumnDocumentBase"), + Translator.R("APPEXTSECguiTableModelTableColumnCodeBase"), + Translator.R("APPEXTSECguiTableModelTableColumnArchives")}; + + public UnsignedAppletActionTableModel(UnsignedAppletActionStorageExtendedImpl back) { + this.back = back; + } + + @Override + public int getRowCount() { + return back.toArray().length; + } + + @Override + public int getColumnCount() { + return columns.length; + } + + @Override + public String getColumnName(int columnIndex) { + return columns[columnIndex]; + } + + @Override + public Class<?> getColumnClass(int columnIndex) { + if (columnIndex == 0) { + return ExecuteUnsignedApplet.class; + } + if (columnIndex == 1) { + return Date.class; + } + if (columnIndex == 2) { + return UrlRegEx.class; + } + if (columnIndex == 3) { + return UrlRegEx.class; + } + if (columnIndex == 4) { + return String.class; + } + if (columnIndex == 5) { + return String.class; + } + return Object.class; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + if (back.isReadOnly()) { + return false; + } + if (columnIndex == 1) { + return false; + } + if (columnIndex == 0) { + return true; + } + if (getValueAt(rowIndex, columnIndex - 1) == null || getValueAt(rowIndex, columnIndex - 1).toString().trim().isEmpty()) { + return false; + } + return true; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + + UnsignedAppletActionEntry source = back.toArray()[rowIndex]; + if (columnIndex == 0) { + return source.getUnsignedAppletAction(); + } + if (columnIndex == 1) { + return source.getTimeStamp(); + } + if (columnIndex == 2) { + return source.getDocumentBase(); + } + if (columnIndex == 3) { + return source.getCodeBase(); + } + if (columnIndex == 4) { + return UnsignedAppletActionEntry.createArchivesString(source.getArchives()); + } + return null; + } + + @Override + public void setValueAt(final Object aValue, final int rowIndex, final int columnIndex) { + final UnsignedAppletActionEntry source = back.toArray()[rowIndex]; + back.modify(source, columnIndex, aValue); + + } + + public void addRow() { + int i = getRowCount()-1; + String s = "\\Qhttp://localhost:80/\\E.*"; + back.add(new UnsignedAppletActionEntry( + ExecuteUnsignedApplet.NEVER, + new Date(), + new UrlRegEx(s), + new UrlRegEx(s), + null)); + fireTableRowsInserted(i+1, i+1); + } + + public void removeRow(int i) { + int ii = getRowCount()-1; + if (ii<0){ + return; + } + if (i<0){ + return; + } + back.remove(i); + fireTableRowsDeleted(i, i); + } + + public void clear() { + int i = getRowCount()-1; + if (i<0){ + return; + } + back.clear(); + fireTableRowsDeleted(0, i); + } + + void removeByBehaviour(ExecuteUnsignedApplet unsignedAppletAction) { + int i = getRowCount()-1; + if (i<0){ + return; + } + back.removeByBehaviour(unsignedAppletAction); + fireTableRowsDeleted(0, i); + } + + int moveUp(int selectedRow) { + int i = getRowCount()-1; + if (i<0){ + return selectedRow; + } + int x = back.moveUp(selectedRow); + fireTableChanged(new TableModelEvent(this, 0, i)); + return x; + } + + int moveDown(int selectedRow) { + int i = getRowCount()-1; + if (i<0){ + return selectedRow; + } + int x = back.moveDown(selectedRow); + fireTableChanged(new TableModelEvent(this, 0, i)); + return x; + } +} diff --git a/netx/net/sourceforge/jnlp/controlpanel/UnsignedAppletsTrustingListPanel.java b/netx/net/sourceforge/jnlp/controlpanel/UnsignedAppletsTrustingListPanel.java new file mode 100644 index 0000000..d03ddda --- /dev/null +++ b/netx/net/sourceforge/jnlp/controlpanel/UnsignedAppletsTrustingListPanel.java @@ -0,0 +1,967 @@ +/* Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ +package net.sourceforge.jnlp.controlpanel; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.regex.Pattern; +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.RowFilter; +import javax.swing.RowFilter.Entry; +import javax.swing.RowSorter.SortKey; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableModel; +import javax.swing.table.TableRowSorter; +import net.sourceforge.jnlp.config.DeploymentConfiguration; +import net.sourceforge.jnlp.runtime.Translator; +import net.sourceforge.jnlp.security.appletextendedsecurity.AppletSecurityLevel; +import net.sourceforge.jnlp.security.appletextendedsecurity.ExecuteUnsignedApplet; +import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletActionEntry; +import net.sourceforge.jnlp.security.appletextendedsecurity.UrlRegEx; +import net.sourceforge.jnlp.security.appletextendedsecurity.impl.UnsignedAppletActionStorageExtendedImpl; + +public class UnsignedAppletsTrustingListPanel extends javax.swing.JPanel { + + private javax.swing.JButton helpButton; + private javax.swing.JButton deleteButton; + private javax.swing.JButton addRowButton; + private javax.swing.JButton validateTableButton; + private javax.swing.JButton testUrlButton; + private javax.swing.JButton invertSelectionButton; + private javax.swing.JButton moveRowUpButton; + private javax.swing.JButton moveRowDownButton; + private javax.swing.JCheckBox askBeforeActionCheckBox; + private javax.swing.JCheckBox filterRegexesCheckBox; + private javax.swing.JComboBox mainPolicyComboBox; + private javax.swing.JComboBox deleteTypeComboBox; + private javax.swing.JComboBox viewFilter; + private javax.swing.JLabel globalBehaviourLabel; + private javax.swing.JLabel securityLevelLabel; + private javax.swing.JScrollPane userTableScrollPane; + private javax.swing.JTabbedPane mainTabPanel; + private javax.swing.JTable userTable; + private javax.swing.JScrollPane globalTableScrollPane; + private javax.swing.JTable globalTable; + private final UnsignedAppletActionStorageExtendedImpl customBackEnd; + private final UnsignedAppletActionStorageExtendedImpl globalBackEnd; + private final UnsignedAppletActionTableModel customModel; + private final UnsignedAppletActionTableModel globalModel; + private final ByPermanencyFilter customFilter; + private final ByPermanencyFilter globalFilter; + private final DeploymentConfiguration conf; + private javax.swing.JTable currentTable; + private UnsignedAppletActionTableModel currentModel; + private String lastDoc; + private String lastCode; + private final UnsignedAppletsTrustingListPanel self; + + + /* + * for testing and playing + */ + public static void main(String args[]) { + final String defaultDir = System.getProperty("user.home") + "/Desktop/"; + final String defaultFileName1 = "terrorList1"; + final String defaultFileName2 = "terrorList2"; + final String defaultFile1 = defaultDir + defaultFileName1; + final String defaultFile2 = defaultDir + defaultFileName2; + java.awt.EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + try { + JFrame f = new JFrame(); + f.setSize(700, 300); + f.setLayout(new BorderLayout()); + f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + DeploymentConfiguration cc = new DeploymentConfiguration(); + cc.load(); + File ff1 = new File(defaultFile1); + File ff2 = new File(defaultFile2); + f.add(new UnsignedAppletsTrustingListPanel(ff2, ff1, cc)); + f.setVisible(true); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + }); + } + + public UnsignedAppletsTrustingListPanel(File globalSettings, File customSettings, DeploymentConfiguration conf) { + self = this; + customBackEnd = new UnsignedAppletActionStorageExtendedImpl(customSettings); + globalBackEnd = new UnsignedAppletActionStorageExtendedImpl(globalSettings); + customModel = new UnsignedAppletActionTableModel(customBackEnd); + globalModel = new UnsignedAppletActionTableModel(globalBackEnd); + customFilter = new ByPermanencyFilter(customModel); + globalFilter = new ByPermanencyFilter(globalModel); + initComponents(); + userTable.setRowSorter(customFilter); + globalTable.setRowSorter(globalFilter); + this.conf = conf; + AppletSecurityLevel gs = AppletSecurityLevel.getDefault(); + String s = conf.getProperty(DeploymentConfiguration.KEY_SECURITY_LEVEL); + if (s != null) { + gs = AppletSecurityLevel.fromString(s); + } + mainPolicyComboBox.setSelectedItem(gs); + userTable.getSelectionModel().addListSelectionListener(new SingleSelectionListenerImpl(userTable)); + globalTable.getSelectionModel().addListSelectionListener(new SingleSelectionListenerImpl(globalTable)); + + userTable.addKeyListener(new DeleteAdapter(userTable)); + globalTable.addKeyListener(new DeleteAdapter(globalTable)); + currentTable = userTable; + currentModel = customModel; + setButtons((!currentModel.back.isReadOnly())); + } + + public String appletItemsToCaption(List<UnsignedAppletActionEntry> ii, String caption) { + StringBuilder sb = new StringBuilder(); + for (UnsignedAppletActionEntry i : ii) { + sb.append(appletItemToCaption(i, caption)).append("\n"); + } + return sb.toString(); + } + + public static String appletItemToCaption(UnsignedAppletActionEntry i, String caption) { + return Translator.R("APPEXTSECguiPanelAppletInfoHederPart1", caption, i.getDocumentBase().getFilteredRegEx()) + + "\n (" + Translator.R("APPEXTSECguiPanelAppletInfoHederPart2", i.getUnsignedAppletAction(), DateFormat.getInstance().format(i.getTimeStamp())) + + "\n " + Translator.R("APPEXTSECguiTableModelTableColumnDocumentBase") + ": " + i.getDocumentBase().getFilteredRegEx() + + "\n " + Translator.R("APPEXTSECguiTableModelTableColumnCodeBase") + ": " + i.getCodeBase().getFilteredRegEx() + + "\n " + Translator.R("APPEXTSECguiTableModelTableColumnArchives") + ": " + UnsignedAppletActionEntry.createArchivesString(i.getArchives()); + } + + public void removeSelectedFromTable(JTable table) { + removeSelectedFromTable(table, askBeforeActionCheckBox.isSelected(), currentModel, this); + } + + public static void removeSelectedFromTable(JTable table, boolean ask, UnsignedAppletActionTableModel data, Component forDialog) { + int[] originalIndexes = table.getSelectedRows(); + List<Integer> newIndexes = new ArrayList<Integer>(originalIndexes.length); + for (int i = 0; i < originalIndexes.length; i++) { + //we need to remap values first + int modelRow = table.convertRowIndexToModel(originalIndexes[i]); + newIndexes.add(modelRow); + } + //now to sort so we can incrementaly dec safely + Collections.sort(newIndexes); + if (ask) { + String s = Translator.R("APPEXTSECguiPanelConfirmDeletionOf", newIndexes.size()) + ": \n"; + UnsignedAppletActionEntry[] items = data.back.toArray(); + for (int i = 0; i < newIndexes.size(); i++) { + Integer integer = newIndexes.get(i); + s += appletItemToCaption(items[integer], " ") + "\n"; + } + int a = JOptionPane.showConfirmDialog(forDialog, s); + if (a != JOptionPane.OK_OPTION) { + return; + } + } + int sub = 0; + for (int i = 0; i < newIndexes.size(); i++) { + Integer integer = newIndexes.get(i); + data.removeRow(integer.intValue() + sub); + sub--; + } + } + + public void removeAllItemsFromTable(JTable table, UnsignedAppletActionTableModel model) { + table.clearSelection(); + + if (askBeforeActionCheckBox.isSelected()) { + UnsignedAppletActionEntry[] items = model.back.toArray(); + String s = Translator.R("APPEXTSECguiPanelConfirmDeletionOf", items.length) + ": \n"; + for (int i = 0; i < items.length; i++) { + s += appletItemToCaption(items[i], " ") + "\n"; + } + int a = JOptionPane.showConfirmDialog(this, s); + if (a != JOptionPane.OK_OPTION) { + return; + } + } + model.clear(); + } + + private void initComponents() { + + userTableScrollPane = new javax.swing.JScrollPane(); + globalTableScrollPane = new javax.swing.JScrollPane(); + userTable = createTbale(customModel); + globalTable = createTbale(globalModel); + helpButton = new javax.swing.JButton(); + mainPolicyComboBox = new JComboBox(new AppletSecurityLevel[]{ + AppletSecurityLevel.DENY_ALL, + AppletSecurityLevel.DENY_UNSIGNED, + AppletSecurityLevel.ASK_UNSIGNED, + AppletSecurityLevel.ALLOW_UNSIGNED + }); + mainPolicyComboBox.setSelectedItem(AppletSecurityLevel.getDefault()); + securityLevelLabel = new javax.swing.JLabel(); + globalBehaviourLabel = new javax.swing.JLabel(); + deleteTypeComboBox = new javax.swing.JComboBox(); + viewFilter = new javax.swing.JComboBox(); + deleteButton = new javax.swing.JButton(); + testUrlButton = new javax.swing.JButton(); + addRowButton = new javax.swing.JButton(); + validateTableButton = new javax.swing.JButton(); + askBeforeActionCheckBox = new javax.swing.JCheckBox(); + filterRegexesCheckBox = new javax.swing.JCheckBox(); + invertSelectionButton = new javax.swing.JButton(); + moveRowUpButton = new javax.swing.JButton(); + moveRowDownButton = new javax.swing.JButton(); + mainTabPanel = new javax.swing.JTabbedPane(); + + userTableScrollPane.setViewportView(userTable); + + globalTableScrollPane.setViewportView(globalTable); + + helpButton.setText(Translator.R("APPEXTSECguiPanelHelpButton")); + helpButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + helpButtonActionPerformed(evt); + } + }); + + mainPolicyComboBox.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + mainPolicyComboBoxActionPerformed(evt); + } + }); + + viewFilter.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + userTable.getRowSorter().setSortKeys(null); + userTable.getRowSorter().setSortKeys(null); + int i = viewFilter.getSelectedIndex(); + switch (i) { + case 0: + customFilter.setRowFilter(ByPermanencyFilter.showPermanents); + globalFilter.setRowFilter(ByPermanencyFilter.showPermanents); + break; + case 1: + customFilter.setRowFilter(ByPermanencyFilter.showTemporarilyDecisions); + globalFilter.setRowFilter(ByPermanencyFilter.showTemporarilyDecisions); + break; + case 2: + customFilter.setRowFilter(ByPermanencyFilter.showAll); + globalFilter.setRowFilter(ByPermanencyFilter.showAll); + break; + case 3: + customFilter.setRowFilter(ByPermanencyFilter.showPermanentA); + globalFilter.setRowFilter(ByPermanencyFilter.showPermanentA); + break; + case 4: + customFilter.setRowFilter(ByPermanencyFilter.showPermanentN); + globalFilter.setRowFilter(ByPermanencyFilter.showPermanentN); + break; + case 5: + customFilter.setRowFilter(ByPermanencyFilter.showHasChosenYes); + globalFilter.setRowFilter(ByPermanencyFilter.showHasChosenYes); + break; + case 6: + customFilter.setRowFilter(ByPermanencyFilter.showHasChosenNo); + globalFilter.setRowFilter(ByPermanencyFilter.showHasChosenNo); + break; + } + + } + }); + + + securityLevelLabel.setText(Translator.R("APPEXTSECguiPanelSecurityLevel")); + + globalBehaviourLabel.setText(Translator.R("APPEXTSECguiPanelGlobalBehaviourCaption")); + + deleteTypeComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[]{ + Translator.R("APPEXTSECguiPanelDeleteMenuSelected"), + Translator.R("APPEXTSECguiPanelDeleteMenuAllA"), + Translator.R("APPEXTSECguiPanelDeleteMenuAllN"), + Translator.R("APPEXTSECguiPanelDeleteMenuAlly"), + Translator.R("APPEXTSECguiPanelDeleteMenuAlln"), + Translator.R("APPEXTSECguiPanelDeleteMenuAllAll")})); + + viewFilter.setModel(new javax.swing.DefaultComboBoxModel(new String[]{ + Translator.R("APPEXTSECguiPanelShowOnlyPermanent"), + Translator.R("APPEXTSECguiPanelShowOnlyTemporal"), + Translator.R("APPEXTSECguiPanelShowAll"), + Translator.R("APPEXTSECguiPanelShowOnlyPermanentA"), + Translator.R("APPEXTSECguiPanelShowOnlyPermanentN"), + Translator.R("APPEXTSECguiPanelShowOnlyTemporalY"), + Translator.R("APPEXTSECguiPanelShowOnlyTemporalN")})); + + deleteButton.setText(Translator.R("APPEXTSECguiPanelDeleteButton")); + deleteButton.setToolTipText(Translator.R("APPEXTSECguiPanelDeleteButtonToolTip")); + deleteButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + deleteButtonActionPerformed(evt); + } + }); + + testUrlButton.setText(Translator.R("APPEXTSECguiPanelTestUrlButton")); + testUrlButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + testUrlButtonActionPerformed(evt); + } + }); + + addRowButton.setText(Translator.R("APPEXTSECguiPanelAddRowButton")); + addRowButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + addRowButtonActionPerformed(evt); + } + }); + + validateTableButton.setText(Translator.R("APPEXTSECguiPanelValidateTableButton")); + validateTableButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + validateTableButtonActionPerformed(evt); + } + }); + + askBeforeActionCheckBox.setSelected(true); + askBeforeActionCheckBox.setText(Translator.R("APPEXTSECguiPanelAskeforeActionBox")); + + filterRegexesCheckBox.setText(Translator.R("APPEXTSECguiPanelShowRegExesBox")); + filterRegexesCheckBox.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + filterRegexesCheckBoxActionPerformed(evt); + } + }); + + invertSelectionButton.setText(Translator.R("APPEXTSECguiPanelInverSelection")); + invertSelectionButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + invertSelectionButtonActionPerformed(evt); + } + }); + + moveRowUpButton.setText(Translator.R("APPEXTSECguiPanelMoveRowUp")); + moveRowUpButton.setEnabled(false); + moveRowUpButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + moveRowUpButtonActionPerformed(evt); + } + }); + + moveRowDownButton.setText(Translator.R("APPEXTSECguiPanelMoveRowDown")); + moveRowDownButton.setEnabled(false); + moveRowDownButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + moveRowDownButtonActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup().addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(mainTabPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 583, Short.MAX_VALUE) + .addComponent(globalBehaviourLabel, javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(securityLevelLabel).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(mainPolicyComboBox, 0, 474, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(addRowButton).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(validateTableButton).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(testUrlButton).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 94, Short.MAX_VALUE) + .addComponent(moveRowDownButton).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(moveRowUpButton)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(deleteButton).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deleteTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(invertSelectionButton)) + .addGroup(layout.createSequentialGroup() + .addComponent(askBeforeActionCheckBox).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(filterRegexesCheckBox).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 93, Short.MAX_VALUE) + .addComponent(viewFilter))).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(helpButton, javax.swing.GroupLayout.PREFERRED_SIZE, 108, javax.swing.GroupLayout.PREFERRED_SIZE))).addContainerGap())); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup().addContainerGap() + .addComponent(globalBehaviourLabel).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(securityLevelLabel) + .addComponent(mainPolicyComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(deleteButton) + .addComponent(deleteTypeComboBox) + .addComponent(invertSelectionButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(askBeforeActionCheckBox) + .addComponent(filterRegexesCheckBox) + .addComponent(viewFilter))) + .addComponent(helpButton, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE)).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(mainTabPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 161, Short.MAX_VALUE).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(addRowButton) + .addComponent(validateTableButton) + .addComponent(testUrlButton) + .addComponent(moveRowUpButton) + .addComponent(moveRowDownButton)).addContainerGap())); + + JPanel userPanel = new JPanel(new BorderLayout()); + JPanel globalPanel = new JPanel(new BorderLayout()); + userPanel.add(userTableScrollPane); + globalPanel.add(globalTableScrollPane); + mainTabPanel.add(userPanel); + mainTabPanel.add(globalPanel); + mainTabPanel.setTitleAt(0, Translator.R("APPEXTSECguiPanelCustomDefs")); + mainTabPanel.setTitleAt(1, Translator.R("APPEXTSECguiPanelGlobalDefs")); + mainTabPanel.setToolTipTextAt(0, DeploymentConfiguration.getAppletTrustUserSettingsPath().getAbsolutePath()); + mainTabPanel.setToolTipTextAt(1, DeploymentConfiguration.getAppletTrustGlobalSettingsPath().getAbsolutePath()); + mainTabPanel.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + switch (mainTabPanel.getSelectedIndex()) { + case 0: + currentModel = customModel; + currentTable = userTable; + break; + case 1: + currentModel = globalModel; + currentTable = globalTable; + break; + } + setButtons((!currentModel.back.isReadOnly())); + } + }); + } + + private void mainPolicyComboBoxActionPerformed(java.awt.event.ActionEvent evt) { + try { + conf.setProperty(DeploymentConfiguration.KEY_SECURITY_LEVEL, ((AppletSecurityLevel) mainPolicyComboBox.getSelectedItem()).toChars()); + conf.save(); + } catch (Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(this, ex); + } + } + + private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) { + + if (deleteTypeComboBox.getSelectedIndex() == 0) { + removeSelectedFromTable(currentTable); + } + if (deleteTypeComboBox.getSelectedIndex() == 1) { + removeByBehaviour(ExecuteUnsignedApplet.ALWAYS); + } + if (deleteTypeComboBox.getSelectedIndex() == 2) { + removeByBehaviour(ExecuteUnsignedApplet.NEVER); + } + if (deleteTypeComboBox.getSelectedIndex() == 3) { + removeByBehaviour(ExecuteUnsignedApplet.YES); + } + if (deleteTypeComboBox.getSelectedIndex() == 4) { + removeByBehaviour(ExecuteUnsignedApplet.NO); + } + if (deleteTypeComboBox.getSelectedIndex() == 5) { + removeAllItemsFromTable(currentTable, customModel); + } + } + + private void testUrlButtonActionPerformed(java.awt.event.ActionEvent evt) { + + String s1 = JOptionPane.showInputDialog(Translator.R("APPEXTSECguiPanelDocTest"), lastDoc); + String s2 = JOptionPane.showInputDialog(Translator.R("APPEXTSECguiPanelCodeTest"), lastCode); + lastDoc = s1; + lastCode = s2; + try { + List<UnsignedAppletActionEntry> i = currentModel.back.getMatchingItems(s1, s2, null); + if (i == null || i.isEmpty()) { + JOptionPane.showMessageDialog(this, Translator.R("APPEXTSECguiPanelNoMatch")); + } else { + JOptionPane.showMessageDialog(this, Translator.R("APPEXTSECguiPanelMatchingNote") + "\n" + appletItemsToCaption(i, Translator.R("APPEXTSECguiPanelMatched") + ": ")); + } + } catch (Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(this, Translator.R("APPEXTSECguiPanelMatchingError", ex)); + } + + } + + private void addRowButtonActionPerformed(java.awt.event.ActionEvent evt) { + + currentModel.addRow(); + } + + private void validateTableButtonActionPerformed(java.awt.event.ActionEvent evt) { + + File f = null; + try { + f = File.createTempFile("appletTable", "validation"); + } catch (Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(this, Translator.R("APPEXTSECguiPanelCanNOtValidate", ex.toString())); + return; + } + try { + currentModel.back.writeContentsLocked(); + BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), "UTF-8")); + currentModel.back.writeContent(bw); + bw.flush(); + bw.close(); + UnsignedAppletActionStorageExtendedImpl copy = new UnsignedAppletActionStorageExtendedImpl(f); + UnsignedAppletActionEntry[] items = copy.toArray(); + for (int i = 0; i < items.length; i++) { + UnsignedAppletActionEntry unsignedAppletActionEntry = items[i]; + if (unsignedAppletActionEntry.getDocumentBase() != null && !unsignedAppletActionEntry.getDocumentBase().getRegEx().trim().isEmpty()) { + Pattern p = Pattern.compile(unsignedAppletActionEntry.getDocumentBase().getRegEx()); + p.matcher("someInput").find(); + } else { + throw new RuntimeException(Translator.R("APPEXTSECguiPanelEmptyDoc")); + } + if (unsignedAppletActionEntry.getCodeBase() != null && !unsignedAppletActionEntry.getCodeBase().getRegEx().trim().isEmpty()) { + Pattern p = Pattern.compile(unsignedAppletActionEntry.getCodeBase().getRegEx()); + p.matcher("someInput").find(); + } else { + throw new RuntimeException(Translator.R("APPEXTSECguiPanelEmptyCode")); + } + UnsignedAppletActionEntry.createArchivesString(UnsignedAppletActionEntry.createArchivesList(UnsignedAppletActionEntry.createArchivesString(unsignedAppletActionEntry.getArchives()))); + + } + JOptionPane.showMessageDialog(this, Translator.R("APPEXTSECguiPanelTableValid")); + } catch (Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(this, Translator.R("APPEXTSECguiPanelTableInvalid ", ex.toString())); + } finally { + f.delete(); + } + + } + + private void filterRegexesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) { + + reloadTable(); + } + + private void invertSelectionButtonActionPerformed(java.awt.event.ActionEvent evt) { + int[] selectedIndexs = currentTable.getSelectedRows(); + currentTable.selectAll(); + + for (int i = 0; i < currentTable.getRowCount(); i++) { + for (int selectedIndex : selectedIndexs) { + if (selectedIndex == i) { + currentTable.removeRowSelectionInterval(i, i); + break; + } + } + } + } + + private void moveRowUpButtonActionPerformed(java.awt.event.ActionEvent evt) { + int orig = currentTable.getSelectedRow(); + if (orig < 0 || orig >= currentTable.getRowCount()) { + return; + } + int nw = 0; + while (true) { + int i = currentTable.convertRowIndexToModel(orig); + int nwx = currentModel.moveUp(i); + reloadTable(); + nw = currentTable.convertRowIndexToView(nwx); + if (i == nwx) { + break; + } + if (nw != orig) { + break; + } + } + //System.out.println(+orig+" "+i+" "+nwx+" "+nw+" "); + if (nw != orig) { + if (orig >= 1) { + currentTable.getSelectionModel().setSelectionInterval(orig - 1, orig - 1); + } + } else { + currentTable.getSelectionModel().setSelectionInterval(orig, orig); + } + } + + private void moveRowDownButtonActionPerformed(java.awt.event.ActionEvent evt) { + int orig = currentTable.getSelectedRow(); + if (orig < 0 || orig >= currentTable.getRowCount()) { + return; + } + int nw = 0; + while (true) { + int i = currentTable.convertRowIndexToModel(orig); + int nwx = currentModel.moveDown(i); + reloadTable(); + nw = currentTable.convertRowIndexToView(nwx); + if (i == nwx) { + break; + } + if (nw != orig) { + break; + } + } + // System.out.println(+orig+" "+i+" "+nwx+" "+nw+" "); + if (nw != orig) { + if (orig < currentModel.getRowCount()) { + currentTable.getSelectionModel().setSelectionInterval(orig + 1, orig + 1); + } + } else { + currentTable.getSelectionModel().setSelectionInterval(orig, orig); + } + } + + private void helpButtonActionPerformed(java.awt.event.ActionEvent evt) { + } + + private void setButtons(boolean b) { + deleteButton.setEnabled(b); + addRowButton.setEnabled(b); + invertSelectionButton.setEnabled(b); + moveRowUpButton.setEnabled(b); + moveRowDownButton.setEnabled(b); + } + + private JTable createTbale(final TableModel model) { + JTable jt = new JTable() { + @Override + public TableCellEditor getCellEditor(int row, int column) { + int columnx = convertColumnIndexToModel(column); + if (columnx == 0) { + return new DefaultCellEditor(new JComboBox(new ExecuteUnsignedApplet[]{ExecuteUnsignedApplet.ALWAYS, ExecuteUnsignedApplet.NEVER, ExecuteUnsignedApplet.YES, ExecuteUnsignedApplet.NO})); + } + if (columnx == 2) { + column = convertColumnIndexToModel(column); + row = convertRowIndexToModel(row); + return new DefaultCellEditor(new MyTextField((UrlRegEx) (model.getValueAt(row, column)))); + } + if (columnx == 3) { + column = convertColumnIndexToModel(column); + row = convertRowIndexToModel(row); + return new DefaultCellEditor(new MyTextField((UrlRegEx) (model.getValueAt(row, column)))); + } + return super.getCellEditor(row, column); + } + + @Override + public TableCellRenderer getCellRenderer(int row, int column) { + int columnx = convertColumnIndexToModel(column); + if (columnx == 1) { + column = convertColumnIndexToModel(column); + row = convertRowIndexToModel(row); + return new UrlRegexCellRenderer.MyDateCellRenderer((Date) (model.getValueAt(row, column))); + } + if (columnx == 2) { + if (!filterRegexesCheckBox.isSelected()) { + column = convertColumnIndexToModel(column); + row = convertRowIndexToModel(row); + return new UrlRegexCellRenderer((UrlRegEx) (model.getValueAt(row, column))); + } + } + if (columnx == 3) { + if (!filterRegexesCheckBox.isSelected()) { + column = convertColumnIndexToModel(column); + row = convertRowIndexToModel(row); + return new UrlRegexCellRenderer((UrlRegEx) (model.getValueAt(row, column))); + } + } + return super.getCellRenderer(row, column); + } + }; + jt.setRowHeight(jt.getRowHeight() + jt.getRowHeight() / 2); + jt.setModel(model); + return jt; + + } + + private void reloadTable() { + List<? extends SortKey> l = currentTable.getRowSorter().getSortKeys(); + currentTable.setModel(new DefaultTableModel()); + currentTable.setModel(currentModel); + { + currentTable.getRowSorter().setSortKeys(l); + + } + + } + + private void removeByBehaviour(ExecuteUnsignedApplet unsignedAppletAction) { + UnsignedAppletActionEntry[] items = currentModel.back.toArray(); + if (askBeforeActionCheckBox.isSelected()) { + List<UnsignedAppletActionEntry> toBeDeleted = new ArrayList(); + for (int i = 0; i < items.length; i++) { + UnsignedAppletActionEntry unsignedAppletActionEntry = items[i]; + if (unsignedAppletActionEntry.getUnsignedAppletAction() == unsignedAppletAction) { + toBeDeleted.add(unsignedAppletActionEntry); + } + + } + String s = Translator.R("APPEXTSECguiPanelConfirmDeletionOf", toBeDeleted.size()) + ": \n"; + for (int i = 0; i < toBeDeleted.size(); i++) { + s += appletItemToCaption(toBeDeleted.get(i), " ") + "\n"; + } + int a = JOptionPane.showConfirmDialog(this, s); + if (a != JOptionPane.OK_OPTION) { + return; + } + } + currentModel.removeByBehaviour(unsignedAppletAction); + } + + public static final class MyTextField extends JTextField { + + private final UrlRegEx keeper; + + private MyTextField(UrlRegEx urlRegEx) { + if (urlRegEx == null) { + keeper = new UrlRegEx(""); + } else { + this.keeper = urlRegEx; + } + setText(keeper.getFilteredRegEx()); + } + + @Override + public void setText(String t) { + super.setText(keeper.getRegEx()); + } + } + + public static final class UrlRegexCellRenderer extends DefaultTableCellRenderer { + + private final UrlRegEx keeper; + + private UrlRegexCellRenderer(UrlRegEx urlRegEx) { + if (urlRegEx == null) { + keeper = new UrlRegEx(""); + } else { + this.keeper = urlRegEx; + } + setText(keeper.getFilteredRegEx()); + } + + @Override + public void setText(String t) { + if (keeper == null) { + super.setText(""); + } else { + super.setText(keeper.getFilteredRegEx()); + } + } + + public static final class MyDateCellRenderer extends DefaultTableCellRenderer { + + private final Date keeper; + + private MyDateCellRenderer(Date d) { + this.keeper = d; + setText(DateFormat.getInstance().format(d)); + } + + @Override + public void setText(String t) { + if (keeper == null) { + super.setText(""); + } else { + super.setText(DateFormat.getInstance().format(keeper)); + } + } + } + } + + private final class SingleSelectionListenerImpl implements ListSelectionListener { + + private final JTable table; + + public SingleSelectionListenerImpl(JTable table) { + this.table = table; + } + + @Override + public void valueChanged(ListSelectionEvent e) { + if (table.getSelectedRows().length == 1 && !currentModel.back.isReadOnly()) { + moveRowUpButton.setEnabled(true); + moveRowDownButton.setEnabled(true); + } else { + moveRowUpButton.setEnabled(false); + moveRowDownButton.setEnabled(false); + } + } + } + + private final class DeleteAdapter implements KeyListener { + + private final JTable table; + + public DeleteAdapter(JTable table) { + this.table = table; + } + + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_DELETE && !currentModel.back.isReadOnly()) { + removeSelectedFromTable(table, askBeforeActionCheckBox.isSelected(), (UnsignedAppletActionTableModel) table.getModel(), self); + } + } + + @Override + public void keyReleased(KeyEvent e) { + } + } + + private abstract static class MyCommonSorter extends RowFilter<UnsignedAppletActionTableModel, Integer> { + + + } + private static final class ByPermanencyFilter extends TableRowSorter<UnsignedAppletActionTableModel> { + + private static final class ShowAll extends MyCommonSorter { + + @Override + public boolean include(Entry<? extends UnsignedAppletActionTableModel, ? extends Integer> entry) { + return true; + } + } + + private static final class ShowPermanents extends MyCommonSorter { + + @Override + public boolean include(Entry<? extends UnsignedAppletActionTableModel, ? extends Integer> entry) { + ExecuteUnsignedApplet o = (ExecuteUnsignedApplet) entry.getModel().getValueAt(entry.getIdentifier(), 0); + return (o.equals(ExecuteUnsignedApplet.ALWAYS) || o.equals(ExecuteUnsignedApplet.NEVER)); + } + } + + private static final class ShowPermanentA extends MyCommonSorter { + @Override + public boolean include(Entry<? extends UnsignedAppletActionTableModel, ? extends Integer> entry) { + ExecuteUnsignedApplet o = (ExecuteUnsignedApplet) entry.getModel().getValueAt(entry.getIdentifier(), 0); + return (o.equals(ExecuteUnsignedApplet.ALWAYS)); + } + } + + private static final class ShowPermanentN extends MyCommonSorter { + + @Override + public boolean include(Entry<? extends UnsignedAppletActionTableModel, ? extends Integer> entry) { + ExecuteUnsignedApplet o = (ExecuteUnsignedApplet) entry.getModel().getValueAt(entry.getIdentifier(), 0); + return (o.equals(ExecuteUnsignedApplet.NEVER)); + } + } + + private static final class ShowTemporarilyDecisions extends MyCommonSorter { + + @Override + public boolean include(Entry<? extends UnsignedAppletActionTableModel, ? extends Integer> entry) { + ExecuteUnsignedApplet o = (ExecuteUnsignedApplet) entry.getModel().getValueAt(entry.getIdentifier(), 0); + return (o.equals(ExecuteUnsignedApplet.YES) || o.equals(ExecuteUnsignedApplet.NO)); + } + } + + private static final class ShowHasChosenYes extends MyCommonSorter { + + @Override + public boolean include(Entry<? extends UnsignedAppletActionTableModel, ? extends Integer> entry) { + ExecuteUnsignedApplet o = (ExecuteUnsignedApplet) entry.getModel().getValueAt(entry.getIdentifier(), 0); + return (o.equals(ExecuteUnsignedApplet.YES)); + } + + + } + + private static final class ShowHasChosenNo extends MyCommonSorter { + + @Override + public boolean include(Entry<? extends UnsignedAppletActionTableModel, ? extends Integer> entry) { + ExecuteUnsignedApplet o = (ExecuteUnsignedApplet) entry.getModel().getValueAt(entry.getIdentifier(), 0); + return (o.equals(ExecuteUnsignedApplet.NO)); + } + + } + public static final ShowAll showAll = new ShowAll(); + public static final ShowPermanents showPermanents = new ShowPermanents(); + public static final ShowPermanentA showPermanentA = new ShowPermanentA(); + public static final ShowPermanentN showPermanentN = new ShowPermanentN(); + public static final ShowTemporarilyDecisions showTemporarilyDecisions = new ShowTemporarilyDecisions(); + public static final ShowHasChosenYes showHasChosenYes = new ShowHasChosenYes(); + public static final ShowHasChosenNo showHasChosenNo = new ShowHasChosenNo(); + + public ByPermanencyFilter(UnsignedAppletActionTableModel model) { + super(model); + setRowFilter(showPermanents); + } + } +} diff --git a/netx/net/sourceforge/jnlp/resources/Messages.properties b/netx/net/sourceforge/jnlp/resources/Messages.properties index 2386dfc..8518ea6 100644 --- a/netx/net/sourceforge/jnlp/resources/Messages.properties +++ b/netx/net/sourceforge/jnlp/resources/Messages.properties @@ -474,3 +474,64 @@ SPLASHdefaultHomepage = Unspecified homepage, verify source rather SPLASHerrorInInformation = Error during loading of information element, verify source rather SPLASHmissingInformation = Information element is missing, verify source rather SPLASHchainWas = This is the list of exceptions that occurred launching your applet. Please note, those exceptions can be from multiple applets. For a good bug report, be sure to run only one applet. + +APPEXTSECappletSecurityLevelExtraHighId=Disable running of all java applets +APPEXTSECappletSecurityLevelVeryHighId=Very High Security +APPEXTSECappletSecurityLevelHighId=High Security +APPEXTSECappletSecurityLevelLowId=Low Security +APPEXTSECappletSecurityLevelExtraHighExplanation=No applet will be run +APPEXTSECappletSecurityLevelVeryHighExplanation=No unsigned applets will be run +APPEXTSECappletSecurityLevelHighExplanation=User will be prompted for each unsigned applet +APPEXTSECappletSecurityLevelLowExplanation=All, even unsigned, applets will be run +APPEXTSECunsignedAppletActionAlways=Always trust this (matching) applet(s) +APPEXTSECunsignedAppletActionNever=Never trust this (matching) applet(s) +APPEXTSECunsignedAppletActionYes=This applet was visited and allowed +APPEXTSECunsignedAppletActionNo=This applet was visited and denied +APPEXTSECControlPanelExtendedAppletSecurityTitle=Extended applet security +APPEXTSECguiTableModelTableColumnAction=Action +APPEXTSECguiTableModelTableColumnDateOfAction=Date of action +APPEXTSECguiTableModelTableColumnDocumentBase=Document-base +APPEXTSECguiTableModelTableColumnCodeBase=Code-base +APPEXTSECguiTableModelTableColumnArchives=Archives +APPEXTSECguiPanelAppletInfoHederPart1={0} {1} +APPEXTSECguiPanelAppletInfoHederPart2={0} from {1} +APPEXTSECguiPanelConfirmDeletionOf=Are you sure you want to delete following {0} items +APPEXTSECguiPanelHelpButton=Help +APPEXTSECguiPanelSecurityLevel=Security Level +APPEXTSECguiPanelGlobalBehaviourCaption=Settings of global behavior for applets +APPEXTSECguiPanelDeleteMenuSelected=selected +APPEXTSECguiPanelDeleteMenuAllA=all allowed (A) +APPEXTSECguiPanelDeleteMenuAllN=all forbidden (N) +APPEXTSECguiPanelDeleteMenuAlly=all approved (y) +APPEXTSECguiPanelDeleteMenuAlln=all rejected (n) +APPEXTSECguiPanelDeleteMenuAllAll=absolute all +APPEXTSECguiPanelDeleteButton=Delete +APPEXTSECguiPanelDeleteButtonToolTip=You can press delete key during browsing the table. It will act as delete selected +APPEXTSECguiPanelTestUrlButton=Test url +APPEXTSECguiPanelAddRowButton=Add new row +APPEXTSECguiPanelValidateTableButton=Validate table +APPEXTSECguiPanelAskeforeActionBox=Ask me before action +APPEXTSECguiPanelShowRegExesBox=Show full regular expressions +APPEXTSECguiPanelInverSelection=Invert selection +APPEXTSECguiPanelMoveRowUp=Move row up +APPEXTSECguiPanelMoveRowDown=Move row down +APPEXTSECguiPanelCustomDefs=Custom definitions +APPEXTSECguiPanelGlobalDefs=Global definitions +APPEXTSECguiPanelDocTest=Type document base URL +APPEXTSECguiPanelCodeTest=Type code base URL +APPEXTSECguiPanelNoMatch=Nothing matched +APPEXTSECguiPanelMatchingNote=Please note, that only first matched result will be considered as result. +APPEXTSECguiPanelMatched=Matched +APPEXTSECguiPanelMatchingError=Error during matching: {0} +APPEXTSECguiPanelCanNotValidate=Can not validate, can not create tmp file - {0} +APPEXTSECguiPanelEmptyDoc=All document-bases must be full +APPEXTSECguiPanelEmptyCode=All code-bases must be full +APPEXTSECguiPanelTableValid=Table looks valid +APPEXTSECguiPanelTableInvalid=Invalid with following error: {0} +APPEXTSECguiPanelShowOnlyPermanent=Show only permanent records +APPEXTSECguiPanelShowOnlyTemporal=Show only previously temporarily decided records +APPEXTSECguiPanelShowAll=Show all records +APPEXTSECguiPanelShowOnlyPermanentA=Show only allowed permanent records +APPEXTSECguiPanelShowOnlyPermanentN=Show only forbidden permanent records +APPEXTSECguiPanelShowOnlyTemporalY=Show previously allowed applets records +APPEXTSECguiPanelShowOnlyTemporalN=Show previously denied applets records
\ No newline at end of file diff --git a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/AppletSecurityLevel.java b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/AppletSecurityLevel.java new file mode 100644 index 0000000..59cb799 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/AppletSecurityLevel.java @@ -0,0 +1,78 @@ +/* Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ +package net.sourceforge.jnlp.security.appletextendedsecurity; + +import net.sourceforge.jnlp.runtime.Translator; + +public enum AppletSecurityLevel { + + DENY_ALL, DENY_UNSIGNED, ASK_UNSIGNED, ALLOW_UNSIGNED; + + public static String allToString() { + return DENY_ALL.toChars() + " " + DENY_UNSIGNED.toChars() + " " + ASK_UNSIGNED.toChars() + " " + ALLOW_UNSIGNED.toChars(); + } + + public String toChars() { + return this.name(); + } + + public String toExplanation() { + switch (this) { + case DENY_ALL: + return Translator.R("APPEXTSECappletSecurityLevelExtraHighId") + " - " + Translator.R("APPEXTSECappletSecurityLevelExtraHighExplanation"); + case DENY_UNSIGNED: + return Translator.R("APPEXTSECappletSecurityLevelVeryHighId") + " - " + Translator.R("APPEXTSECappletSecurityLevelVeryHighExplanation"); + case ASK_UNSIGNED: + return Translator.R("APPEXTSECappletSecurityLevelHighId") + " - " + Translator.R("APPEXTSECappletSecurityLevelHighExplanation"); + case ALLOW_UNSIGNED: + return Translator.R("APPEXTSECappletSecurityLevelLowId") + " - " + Translator.R("APPEXTSECappletSecurityLevelLowExplanation"); + } + throw new RuntimeException("Unknown AppletSecurityLevel"); + } + + public static AppletSecurityLevel fromString(String s) { + return AppletSecurityLevel.valueOf(s.toUpperCase()); + } + + @Override + public String toString() { + return toExplanation(); + } + + public static AppletSecurityLevel getDefault() { + return ASK_UNSIGNED; + } +} diff --git a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/AppletStartupSecuritySettings.java b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/AppletStartupSecuritySettings.java new file mode 100644 index 0000000..2d82ed1 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/AppletStartupSecuritySettings.java @@ -0,0 +1,97 @@ +/* Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ +package net.sourceforge.jnlp.security.appletextendedsecurity; + +import javax.naming.ConfigurationException; +import net.sourceforge.jnlp.security.appletextendedsecurity.AppletSecurityLevel; +import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletActionStorage; +import net.sourceforge.jnlp.security.appletextendedsecurity.impl.UnsignedAppletActionStorageImpl; +import net.sourceforge.jnlp.config.DeploymentConfiguration; +import net.sourceforge.jnlp.runtime.JNLPRuntime; +import net.sourceforge.jnlp.util.lockingfile.StorageIoException; + +public class AppletStartupSecuritySettings { + + private static final AppletStartupSecuritySettings instance = new AppletStartupSecuritySettings(); + private UnsignedAppletActionStorageImpl globalInstance; + private UnsignedAppletActionStorageImpl customInstance; + + public static AppletStartupSecuritySettings getInstance() { + return instance; + } + + public static AppletSecurityLevel getHardcodedDefaultSecurityLevel() { + return AppletSecurityLevel.getDefault(); + } + + /** + * + * @return storage with global items from /etc/ + */ + public UnsignedAppletActionStorage getUnsignedAppletActionGlobalStorage() { + if (globalInstance == null) { + globalInstance = new UnsignedAppletActionStorageImpl(DeploymentConfiguration.getAppletTrustGlobalSettingsPath()); + } + return globalInstance; + } + + /** + * + * @return storage with custom items from /home/ + */ + public UnsignedAppletActionStorage getUnsignedAppletActionCustomStorage() { + if (customInstance == null) { + customInstance = new UnsignedAppletActionStorageImpl(DeploymentConfiguration.getAppletTrustUserSettingsPath()); + } + return customInstance; + } + + /** + * + * @return user-set security level or default one if user-set do not exists + */ + public AppletSecurityLevel getSecurityLevel() { + DeploymentConfiguration conf = JNLPRuntime.getConfiguration(); + if (conf == null) { + throw new StorageIoException("JNLPRuntime configuration is null. Try to reinstall IcedTea-Web"); + } + String s = conf.getProperty(DeploymentConfiguration.KEY_SECURITY_LEVEL); + if (s == null) { + return getHardcodedDefaultSecurityLevel(); + } + return AppletSecurityLevel.fromString(s); + } +} diff --git a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/ExecuteUnsignedApplet.java b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/ExecuteUnsignedApplet.java new file mode 100644 index 0000000..ed410a4 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/ExecuteUnsignedApplet.java @@ -0,0 +1,90 @@ +/* Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ +package net.sourceforge.jnlp.security.appletextendedsecurity; + +import net.sourceforge.jnlp.runtime.Translator; + +public enum ExecuteUnsignedApplet { + + ALWAYS, NEVER, YES, NO; + + public String toChar() { + switch (this) { + case ALWAYS: + return "A"; + case NEVER: + return "N"; + case YES: + return "y"; + case NO: + return "n"; + } + throw new RuntimeException("Unknown ExecuteUnsignedApplet"); + } + + public String toExplanation() { + switch (this) { + case ALWAYS: + return Translator.R("APPEXTSECunsignedAppletActionAlways"); + case NEVER: + return Translator.R("APPEXTSECunsignedAppletActionNever"); + case YES: + return Translator.R("APPEXTSECunsignedAppletActionYes"); + case NO: + return Translator.R("APPEXTSECunsignedAppletActionNo"); + } + throw new RuntimeException("Unknown UnsignedAppletAction"); + } + + public static ExecuteUnsignedApplet fromString(String s) { + if (s.startsWith("A")) { + return ExecuteUnsignedApplet.ALWAYS; + } else if (s.startsWith("N")) { + return ExecuteUnsignedApplet.NEVER; + } else if (s.startsWith("y")) { + return ExecuteUnsignedApplet.YES; + } else if (s.startsWith("n")) { + return ExecuteUnsignedApplet.NO; + } else { + throw new RuntimeException("Unknown ExecuteUnsignedApplet for " + s); + } + } + + @Override + public String toString() { + return toChar() + " - " + toExplanation(); + } +} diff --git a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletActionEntry.java b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletActionEntry.java new file mode 100644 index 0000000..44700c0 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletActionEntry.java @@ -0,0 +1,174 @@ +/* Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ +package net.sourceforge.jnlp.security.appletextendedsecurity; + +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class UnsignedAppletActionEntry { + + private ExecuteUnsignedApplet unsignedAppletAction; + private Date timeStamp; + private UrlRegEx documentBase; + private UrlRegEx codeBase; + private List<String> archives; + + public static UnsignedAppletActionEntry createFromString(String s) { + String[] split = s.split("\\s+"); + UnsignedAppletActionEntry nw = new UnsignedAppletActionEntry( + ExecuteUnsignedApplet.fromString(split[0]), + new Date(new Long(split[1])), + new UrlRegEx(split[2]), + null, + null); + if (split.length > 3) { + nw.setCodeBase(new UrlRegEx(split[3])); + } + if (split.length > 4) { + nw.setArchives(createArchivesList(s.substring(s.lastIndexOf(split[3]) + split[3].length()).trim())); + } + return nw; + } + + public UnsignedAppletActionEntry(ExecuteUnsignedApplet unsignedAppletAction, Date timeStamp, UrlRegEx documentBase, UrlRegEx codeBase, List<String> archives) { + this.unsignedAppletAction = unsignedAppletAction; + this.timeStamp = timeStamp; + this.documentBase = documentBase; + this.codeBase = codeBase; + this.archives = archives; + + } + + @Override + public String toString() { + return this.serializeToReadableAndParseableString(); + + } + + public void write(Writer bw) throws IOException { + bw.write(this.serializeToReadableAndParseableString()); + } + + private String serializeToReadableAndParseableString() { + return unsignedAppletAction.toChar() + + " " + ((timeStamp == null) ? "1" : timeStamp.getTime()) + + " " + ((documentBase == null) ? "" : documentBase.getRegEx()) + + " " + ((codeBase == null) ? "" : codeBase.getRegEx()) + + " " + createArchivesString(archives); + } + + public Date getTimeStamp() { + return timeStamp; + } + + public UrlRegEx getDocumentBase() { + return documentBase; + } + + public void setTimeStamp(Date timeStamp) { + this.timeStamp = timeStamp; + } + + public void setDocumentBase(UrlRegEx documentBase) { + this.documentBase = documentBase; + } + + public ExecuteUnsignedApplet getUnsignedAppletAction() { + return unsignedAppletAction; + } + + public void setUnsignedAppletAction(ExecuteUnsignedApplet unsignedAppletAction) { + this.unsignedAppletAction = unsignedAppletAction; + } + + public UrlRegEx getCodeBase() { + return codeBase; + } + + public void setCodeBase(UrlRegEx codeBase) { + this.codeBase = codeBase; + } + + public List<String> getArchives() { + return archives; + } + + public void setArchives(List<String> archives) { + this.archives = archives; + } + + public static String createArchivesString(List<String> listOfArchives) { + if (listOfArchives == null) { + return ""; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < listOfArchives.size(); i++) { + String string = listOfArchives.get(i); + if (string.trim().isEmpty()) { + continue; + } + sb.append(string); + if (i != listOfArchives.size() - 1) { + sb.append(","); + } + } + return sb.toString(); + } + + public static List<String> createArchivesList(String commedArchives) { + if (commedArchives == null) { + return null; + } + if (commedArchives.trim().isEmpty()) { + return null; + } + String[] items = commedArchives.trim().split(","); + List<String> r = new ArrayList<String>(items.length); + for (int i = 0; i < items.length; i++) { + String string = items[i]; + if (string.trim().isEmpty()) { + continue; + } + r.add(string); + + } + return r; + + } +} diff --git a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletActionStorage.java b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletActionStorage.java new file mode 100644 index 0000000..8ce6500 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletActionStorage.java @@ -0,0 +1,125 @@ +/* Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ +package net.sourceforge.jnlp.security.appletextendedsecurity; + +import java.util.List; + + +/** + * This is abstract access to white/blacklist created from some permanent storage. + * + * It is daclaring adding, updating and searching. Intentionally not removing as + * during plugin runtime no deletations should be done. + * + * Implementations of this interface (unless dummy ones:) should ensure correct + * communication with permanent storage and be prepared for multiple instances + * read/write the same storage at time + * + */ +public interface UnsignedAppletActionStorage { + + /** + * This methods iterates through records in + * DeploymentConfiguration.getAppletTrustSettingsPath(), and is mathing + * regexes saved here against params. so parameters here are NOR tegexes, + * but are matched against saved regexes + * + * Null or empty values are dangerously ignored, user, be aware of it. eg: + * match only codeBase will be null someCodeBase null null match only + * documentBase will be someDocBase null null null match only applet not + * regarding code or document base will be null null mainClass archives + * + * @param documentBase + * @param codeBase + * @param mainClass + * @param archives + * @return + */ + public UnsignedAppletActionEntry getMatchingItem(String documentBase, String codeBase, List<String> archives); + + /** + * Shortcut getMatchingItem(documentBase, null,null,null) + * + * @param documentBase + * @return + */ + public UnsignedAppletActionEntry getMatchingItemByDocumentBase(String documentBase); + + /** + * Shortcut getMatchingItem(null, codeBase,null,null) + * + * @param codeBase + * @return + */ + public UnsignedAppletActionEntry getMatchingItemByCodeBase(String codeBase); + + /** + * Shortcut getMatchingItem(documentBase, codeBase,null,null) + * + * @param documentBase + * @param codeBase + * @return + */ + public UnsignedAppletActionEntry getMatchingItemByBases(String documentBase, String codeBase); + + /** + * Will add new record. Note that regexes are stored for bases matching. + * + * eg UnsignedAppletActionEntry which will deny some applet no matter of + * page will be new UnsignedAppletActionEntry(UnsignedAppletAction.NEVER, + * new Date(), null, null, someMain, someArchives) + * + * eg UnsignedAppletActionEntry which will allow all applets on page with + * same codebase will be new + * UnsignedAppletActionEntry(UnsignedAppletAction.NEVER, new Date(), ".*", + * ".*", null, null); + * + * @param item + */ + public void add(final UnsignedAppletActionEntry item); + + /** + * Will replace (current impl is matching by object's hashcode This is not + * reloading the list(but still saving after), so StorageIoEception can be + * thrown if it was not loaded before. + * + * Imho this should be used only to actualise timestamps or change + * UnsignedAppletAction + * + * @param item + */ + public void update(final UnsignedAppletActionEntry item); +} diff --git a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UrlRegEx.java b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UrlRegEx.java new file mode 100644 index 0000000..f71f82a --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UrlRegEx.java @@ -0,0 +1,62 @@ +/* Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ +package net.sourceforge.jnlp.security.appletextendedsecurity; + +public class UrlRegEx { + + String regEx; + + public UrlRegEx(String s) { + regEx = s; + } + + @Override + public String toString() { + return getRegEx(); + } + + public String getRegEx() { + return regEx; + } + + public String getFilteredRegEx() { + return regEx.replaceAll("\\\\Q", "").replaceAll("\\\\E", ""); + } + + public void setRegEx(String regEx) { + this.regEx = regEx; + } +} diff --git a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/impl/UnsignedAppletActionStorageExtendedImpl.java b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/impl/UnsignedAppletActionStorageExtendedImpl.java new file mode 100644 index 0000000..66e16ee --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/impl/UnsignedAppletActionStorageExtendedImpl.java @@ -0,0 +1,188 @@ +/* Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ +package net.sourceforge.jnlp.security.appletextendedsecurity.impl; + +import java.io.File; +import java.io.IOException; +import java.util.Date; +import net.sourceforge.jnlp.security.appletextendedsecurity.ExecuteUnsignedApplet; +import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletActionEntry; +import net.sourceforge.jnlp.security.appletextendedsecurity.UrlRegEx; +import net.sourceforge.jnlp.util.lockingfile.StorageIoException; + +public class UnsignedAppletActionStorageExtendedImpl extends UnsignedAppletActionStorageImpl { + + public UnsignedAppletActionStorageExtendedImpl(String location) { + this(new File(location)); + } + + public UnsignedAppletActionStorageExtendedImpl(File location) { + super(location); + } + + public UnsignedAppletActionEntry[] toArray() { + lock(); + try { + readContents(); + return items.toArray(new UnsignedAppletActionEntry[items.size()]); + } catch (IOException e) { + throw new StorageIoException(e); + } finally { + unlock(); + } + } + + public void clear() { + doLocked(new Runnable() { + public void run() { + try { + items.clear(); + writeContents(); + } catch (IOException e) { + throw new StorageIoException(e); + } + } + }); + } + + public void removeByBehaviour(final ExecuteUnsignedApplet unsignedAppletAction) { + doLocked(new Runnable() { + public void run() { + try { + readContents(); + for (int i = 0; i < items.size(); i++) { + UnsignedAppletActionEntry unsignedAppletActionEntry = items.get(i); + if (unsignedAppletActionEntry.getUnsignedAppletAction() == unsignedAppletAction) { + items.remove(i); + i--; + } + + } + writeContents(); + } catch (IOException e) { + throw new StorageIoException(e); + } + } + }); + } + + private void swap(final int i, final int ii) { + doLocked(new Runnable() { + public void run() { + try { + readContents(); + UnsignedAppletActionEntry backup = items.get(i); + items.set(i, items.get(ii)); + items.set(ii, backup); + writeContents(); + } catch (IOException e) { + throw new StorageIoException(e); + } + } + }); + + } + + public int moveUp(int selectedRow) { + if (selectedRow <= 0) { + return selectedRow; + } + swap(selectedRow, selectedRow - 1); + return selectedRow-1; + } + + public int moveDown(int selectedRow) { + if (selectedRow >= items.size() - 1) { + return selectedRow; + } + swap(selectedRow, selectedRow + 1); + return selectedRow+1; + } + + public void remove(final int item) { + doLocked(new Runnable() { + public void run() { + try { + readContents(); + items.remove(item); + writeContents(); + } catch (IOException ex) { + throw new StorageIoException(ex); + } + } + }); + } + + public void modify(final UnsignedAppletActionEntry source, final int columnIndex, final Object aValue) { + Runnable r = new Runnable() { + public void run() { + + try { + if (!items.contains(source)) { + throw new StorageIoException("Item to be modified not found in storage"); + } + + if (columnIndex == 0) { + source.setUnsignedAppletAction((ExecuteUnsignedApplet) aValue); + } + if (columnIndex == 1) { + source.setTimeStamp((Date) aValue); + } + if (columnIndex == 2) { + source.setDocumentBase(new UrlRegEx((String) aValue)); + } + if (columnIndex == 3) { + source.setCodeBase(new UrlRegEx((String) aValue)); + } + if (columnIndex == 4) { + source.setArchives(UnsignedAppletActionEntry.createArchivesList((String) aValue)); + } + + writeContents(); + } catch (IOException ex) { + throw new StorageIoException(ex); + } + } + }; + doLocked(r); + + } + + @Override + public synchronized void writeContentsLocked() throws IOException { + super.writeContentsLocked(); + } +} diff --git a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/impl/UnsignedAppletActionStorageImpl.java b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/impl/UnsignedAppletActionStorageImpl.java new file mode 100644 index 0000000..7f71b50 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/impl/UnsignedAppletActionStorageImpl.java @@ -0,0 +1,240 @@ +/* Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ +package net.sourceforge.jnlp.security.appletextendedsecurity.impl; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import net.sourceforge.jnlp.security.appletextendedsecurity.ExecuteUnsignedApplet; +import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletActionEntry; +import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletActionStorage; +import net.sourceforge.jnlp.util.lockingfile.LockingReaderWriter; +import net.sourceforge.jnlp.util.lockingfile.StorageIoException; + +public class UnsignedAppletActionStorageImpl extends LockingReaderWriter implements UnsignedAppletActionStorage { + + protected List<UnsignedAppletActionEntry> items; + + public UnsignedAppletActionStorageImpl(String location) { + this(new File(location)); + } + + public UnsignedAppletActionStorageImpl(File location) { + super(location); + } + + @Override + public void writeContents() throws IOException { + super.writeContents(); + } + + @Override + public synchronized void writeContentsLocked() throws IOException { + super.writeContentsLocked(); + } + + @Override + protected void readContents() throws IOException { + if (items == null) { + items = new ArrayList<UnsignedAppletActionEntry>(); + } else { + items.clear(); + } + super.readContents(); + } + + @Override + protected void readLine(String line) { + if (line.trim().length() != 0) { + this.items.add(UnsignedAppletActionEntry.createFromString(line)); + } + } + + @Override + public void writeContent(BufferedWriter bw) throws IOException { + for (UnsignedAppletActionEntry item : items) { + item.write(bw); + bw.newLine(); + } + } + + @Override + public void add(final UnsignedAppletActionEntry item) { + doLocked(new Runnable() { + @Override + public void run() { + try { + readContents(); + items.add(item); + writeContents(); + } catch (IOException ex) { + throw new StorageIoException(ex); + } + } + }); + } + + @Override + public void update(final UnsignedAppletActionEntry item) { + doLocked(new Runnable() { + @Override + public void run() { + try { + if (items == null) { + throw new StorageIoException("Storage is not initialised, can not update"); + } + if (!items.contains(item)) { + throw new StorageIoException("Storage does not contain item you are updating. can not update"); + } + writeContents(); + } catch (IOException ex) { + throw new StorageIoException(ex); + } + } + }); + } + + @Override + public UnsignedAppletActionEntry getMatchingItem(String documentBase, String codeBase, List<String> archives) { + List<UnsignedAppletActionEntry> results = getMatchingItems(documentBase, codeBase, archives); + if (results == null || results.isEmpty()) { + return null; + } + // Chose the first result, unless we find a 'stronger' result + // Actions such as 'always accept' or 'always reject' are 'stronger' than + // the hints 'was accepted' or 'was rejected'. + for (UnsignedAppletActionEntry candidate : results) { + if (candidate.getUnsignedAppletAction() == ExecuteUnsignedApplet.ALWAYS + || candidate.getUnsignedAppletAction() == ExecuteUnsignedApplet.NEVER) { + //return first found strong + return candidate; + } + } + //no strong found, return first + return results.get(0); + } + + public List<UnsignedAppletActionEntry> getMatchingItems(String documentBase, String codeBase, List<String> archives) { + List<UnsignedAppletActionEntry> result = new ArrayList(); + lock(); + try { + readContents(); + if (items == null) { + return result; + } + for (UnsignedAppletActionEntry unsignedAppletActionEntry : items) { + if (isMatching(unsignedAppletActionEntry, documentBase, codeBase, archives)) { + result.add(unsignedAppletActionEntry); + } + } + } catch (IOException e) { + throw new StorageIoException(e); + } finally { + unlock(); + } + return result; + } + + private boolean isMatching(UnsignedAppletActionEntry unsignedAppletActionEntry, String documentBase, String codeBase, List<String> archives) { + boolean result = true; + if (documentBase != null && !documentBase.trim().isEmpty()) { + result = result && documentBase.matches(unsignedAppletActionEntry.getDocumentBase().getRegEx()); + } + if (codeBase != null && !codeBase.trim().isEmpty()) { + result = result && codeBase.matches(unsignedAppletActionEntry.getCodeBase().getRegEx()); + } + if (archives != null) { + result = result && compareArchives(archives, unsignedAppletActionEntry.getArchives()); + } + return result; + } + + @Override + public String toString() { + return getBackingFile() + " " + super.toString(); + } + + private boolean compareArchives(List<String> archives, List<String> saved) { + if (archives == null && saved !=null){ + return false; + } + if (archives != null && saved ==null){ + return false; + } + if (archives == null && saved ==null){ + return true; + } + if (archives.size() != saved.size()) { + return false; + } + Collections.sort(archives); + Collections.sort(saved); + for (int i = 0; i < saved.size(); i++) { + String string1 = saved.get(i); + String string2 = archives.get(i); + //intentional reference compare + if (string1 == string2) { + continue; + } + if (string1 == null || string2 == null) { + return false; + } + if (string1.trim().equals(string2.trim())) { + continue; + } + return false; + } + return true; + } + + @Override + public UnsignedAppletActionEntry getMatchingItemByDocumentBase(String documentBase) { + return getMatchingItem(documentBase, null, null); + } + + @Override + public UnsignedAppletActionEntry getMatchingItemByCodeBase(String codeBase) { + return getMatchingItem(null, codeBase, null); + } + + @Override + public UnsignedAppletActionEntry getMatchingItemByBases(String documentBase, String codeBase) { + return getMatchingItem(documentBase, codeBase, null); + } +} diff --git a/netx/net/sourceforge/jnlp/util/lockingfile/LockedFile.java b/netx/net/sourceforge/jnlp/util/lockingfile/LockedFile.java new file mode 100644 index 0000000..2941dd9 --- /dev/null +++ b/netx/net/sourceforge/jnlp/util/lockingfile/LockedFile.java @@ -0,0 +1,159 @@ +/* + Copyright (C) 2013 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ +package net.sourceforge.jnlp.util.lockingfile; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.locks.ReentrantLock; + +/* + * Process & thread locked access to a file. Creates file if it does not already exist. + */ +public class LockedFile { + + // The file for access + private RandomAccessFile randomAccessFile; + private FileChannel fileChannel; + private File file; + // A file lock will protect against locks for multiple + // processes, while a thread lock is still needed within a single JVM. + private FileLock processLock = null; + private ReentrantLock threadLock = new ReentrantLock(); + private boolean readOnly; + + private LockedFile(File file) { + this.file = file; + try { + //just try to create + this.file.createNewFile(); + } catch (Exception ex) { + //intentionaly silent + } + if (!this.file.isFile() && file.getParentFile() != null && !file.getParentFile().canWrite()) { + readOnly = true; + } else { + this.readOnly = !file.canWrite(); + if (!readOnly && file.getParentFile() != null && !file.getParentFile().canWrite()) { + readOnly = true; + } + } + } + + public boolean isReadOnly() { + return readOnly; + } + // Provide shared access to LockedFile's via weak map + static private final Map<File, LockedFile> instanceCache = new WeakHashMap<File, LockedFile>(); + + /** + * Get a LockedFile for a given File. Ensures that we share the same + * instance for all threads + * + * @param file the file to lock + * @return a LockedFile instance + */ + synchronized public static LockedFile getInstance(File file) { + if (!instanceCache.containsKey(file)) { + instanceCache.put(file, new LockedFile(file)); + } + + return instanceCache.get(file); + } + + /** + * Get the file being locked. + * + * @return the file + */ + public File getFile() { + return file; + } + + /** + * Lock access to the file. Lock is reentrant. + */ + public void lock() throws IOException { + // Create if does not already exist, cannot lock non-existing file + if (!isReadOnly()) { + this.file.createNewFile(); + } + + this.threadLock.lock(); + + if (this.processLock != null) { + return; + } + + if (this.file.exists()) { + this.randomAccessFile = new RandomAccessFile(this.file, isReadOnly() ? "r" : "rws"); + this.fileChannel = randomAccessFile.getChannel(); + if (!isReadOnly()){ + this.processLock = this.fileChannel.lock(); + } + } + } + + /** + * Unlock access to the file. Lock is reentrant. + */ + public void unlock() throws IOException { + boolean releaseProcessLock = (this.threadLock.getHoldCount() == 1); + try { + if (releaseProcessLock) { + if (this.processLock != null){ + this.processLock.release(); + } + this.processLock = null; + //necessary for read only file + if (this.randomAccessFile != null){ + this.randomAccessFile.close(); + } + //necessary for not existing parent direcotry + if (this.fileChannel != null){ + this.fileChannel.close(); + } + } + } finally { + this.threadLock.unlock(); + } + } +}
\ No newline at end of file diff --git a/netx/net/sourceforge/jnlp/util/lockingfile/LockingReaderWriter.java b/netx/net/sourceforge/jnlp/util/lockingfile/LockingReaderWriter.java new file mode 100644 index 0000000..16fbaa6 --- /dev/null +++ b/netx/net/sourceforge/jnlp/util/lockingfile/LockingReaderWriter.java @@ -0,0 +1,200 @@ +/* +Copyright (C) 2013 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ +package net.sourceforge.jnlp.util.lockingfile; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; + +/** + * Process-locked string storage backed by a file. + * Each string is stored on its own line. + * Any new-lines must be encoded somehow if they are to be stored. + */ +public abstract class LockingReaderWriter { + + private LockedFile lockedFile; + + /** + * Create locking file-backed storage. + * @param file the storage file + */ + public LockingReaderWriter(File file) { + this.lockedFile = LockedFile.getInstance(file); + } + + /** + * Get the underlying file. + * Any access to this file should use lock() & unlock(). + * + * @return the file + */ + public File getBackingFile() { + return this.lockedFile.getFile(); + } + + public boolean isReadOnly() { + return this.lockedFile.isReadOnly(); + } + + /** + * Lock the underlying storage. Lock is reentrant. + */ + public void lock() { + try { + lockedFile.lock(); + } catch (IOException e) { + throw new StorageIoException(e); + } + } + + /** + * Unlock the underlying storage. Lock is reentrant. + */ + public void unlock() { + try { + lockedFile.unlock(); + } catch (IOException e) { + throw new StorageIoException(e); + } + } + + /** + * Writes stored contents to file. Assumes lock is held. + * @throws IOException + */ + protected void writeContents() throws IOException { + if (!getBackingFile().isFile()){ + return; + } + if (isReadOnly()){ + return; + } + BufferedWriter writer = null; + try { + writer = new BufferedWriter(new OutputStreamWriter( + new FileOutputStream(getBackingFile()), "UTF-8")); + writeContent(writer); + writer.flush(); + } finally { + if (writer != null) { + writer.close(); + } + } + } + + protected abstract void writeContent(BufferedWriter writer) throws IOException; + + /** + * Reads contents from file. Assumes lock is held. + * @throws IOException + */ + protected void readContents() throws IOException { + if (!getBackingFile().isFile()){ + return; + } + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader( + new FileInputStream(getBackingFile()), "UTF-8")); + + while (true) { + String line = reader.readLine(); + if (line == null) { + break; + } + readLine(line); + } + } finally { + if (reader != null) { + reader.close(); + } + } + } + + /** + * Reads contents from the file, first acquring a lock. + * @throws IOException + */ + protected synchronized void readContentsLocked() throws IOException { + doLocked(new Runnable() { + + @Override + public void run() { + try { + readContents(); + } catch (IOException ex) { + throw new StorageIoException(ex); + } + } + }); + } + + /** + * Write contents to the file, first acquring a lock. + * @throws IOException + */ + protected synchronized void writeContentsLocked() throws IOException { + doLocked(new Runnable() { + + public void run() { + try { + writeContents(); + } catch (IOException ex) { + throw new StorageIoException(ex); + } + } + }); + + } + + protected void doLocked(Runnable r) { + lock(); + try { + r.run(); + } finally { + unlock(); + } + } + + protected abstract void readLine(String line); +} diff --git a/netx/net/sourceforge/jnlp/util/lockingfile/StorageIoException.java b/netx/net/sourceforge/jnlp/util/lockingfile/StorageIoException.java new file mode 100644 index 0000000..e0087a2 --- /dev/null +++ b/netx/net/sourceforge/jnlp/util/lockingfile/StorageIoException.java @@ -0,0 +1,58 @@ +/* Copyright (C) 2013 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ + +package net.sourceforge.jnlp.util.lockingfile; + +/** + * Thrown when an exception occurs using the storage (namely IOException) + */ +public class StorageIoException extends RuntimeException { + + LockingReaderWriter outer; + + public StorageIoException(Exception e) { + super(e); + } + + public StorageIoException(String e) { + super(e); + } + + public StorageIoException(Exception e, LockingReaderWriter outer) { + super(e); + this.outer = outer; + } +} diff --git a/tests/netx/unit/net/sourceforge/jnlp/security/appletextendedsecurity/impl/UnsignedAppletActionStorageImplTest.java b/tests/netx/unit/net/sourceforge/jnlp/security/appletextendedsecurity/impl/UnsignedAppletActionStorageImplTest.java new file mode 100644 index 0000000..cd89b63 --- /dev/null +++ b/tests/netx/unit/net/sourceforge/jnlp/security/appletextendedsecurity/impl/UnsignedAppletActionStorageImplTest.java @@ -0,0 +1,114 @@ +/* Copyright (C) 2013 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ + +package net.sourceforge.jnlp.security.appletextendedsecurity.impl; + +import net.sourceforge.jnlp.security.appletextendedsecurity.impl.UnsignedAppletActionStorageImpl; +import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletActionEntry; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import net.sourceforge.jnlp.ServerAccess; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class UnsignedAppletActionStorageImplTest { + + private static File f1; + private static File f2; + private static File f3; + private static File f4; + + @BeforeClass + public static void preapreTestFiles() throws IOException { + f1 = File.createTempFile("itwMatching", "testFile1"); + f2 = File.createTempFile("itwMatching", "testFile2"); + f3 = File.createTempFile("itwMatching", "testFile3"); + f4 = File.createTempFile("itwMatching", "testFile4"); + ServerAccess.saveFile("A 123456 .* .* jar1,jar2", f1); + ServerAccess.saveFile("A 123456 .* \\Qbla\\E jar1,jar2", f2); + } + + @Test + public void allMatchingDocAndCode() { + UnsignedAppletActionStorageImpl i1 = new UnsignedAppletActionStorageImpl(f1); + UnsignedAppletActionEntry r1 = i1.getMatchingItem("bla", "blaBla", Arrays.asList(new String[]{"jar1", "jar2"})); + Assert.assertNotNull("r1 should be found", r1); + UnsignedAppletActionEntry r3 = i1.getMatchingItem("blah", "blaBla", Arrays.asList(new String[]{"jar2", "jar1"})); + Assert.assertNotNull("r3 should be found", r1); + UnsignedAppletActionEntry r4 = i1.getMatchingItem("blha", "blaBlam", Arrays.asList(new String[]{"jar2", "wrong_jar"})); + Assert.assertNull("r4 should NOT be found", r4); + UnsignedAppletActionEntry r5 = i1.getMatchingItem("blaBla", "blaBlaBla", Arrays.asList(new String[]{"jar2"})); + Assert.assertNull("r5 should NOT be found", r5); + + } + + @Test + public void allMatchingDocAndStrictCode() { + UnsignedAppletActionStorageImpl i1 = new UnsignedAppletActionStorageImpl(f2); + UnsignedAppletActionEntry r1 = i1.getMatchingItem("whatever", "bla", Arrays.asList(new String[]{"jar1", "jar2"})); + Assert.assertNotNull("r1 should be found", r1); + UnsignedAppletActionEntry r3 = i1.getMatchingItem("whatever", null, Arrays.asList(new String[]{"jar2", "jar1"})); + Assert.assertNotNull("r3 should be found", r1); + UnsignedAppletActionEntry r2 = i1.getMatchingItem("bla", "blaBlam", Arrays.asList(new String[]{"jar1", "jar2"})); + Assert.assertNull("r2 should NOT be found", r2); + UnsignedAppletActionEntry r4 = i1.getMatchingItem(null, "blaBlam", null); + Assert.assertNull("r4 should NOT be found", r4); + + } + + @Test + public void allMatchingDocAndCodeWithNulls() { + UnsignedAppletActionStorageImpl i1 = new UnsignedAppletActionStorageImpl(f1); + UnsignedAppletActionEntry r1 = i1.getMatchingItem("bla", "blaBla", null); + Assert.assertNotNull("r1 should be found", r1); + UnsignedAppletActionEntry r3 = i1.getMatchingItem("bla", "whatever", null); + Assert.assertNotNull("r3 should be found", r1); + UnsignedAppletActionEntry r2 = i1.getMatchingItem("bla", "blaBla", Arrays.asList(new String[]{"jar2", "jar1"})); + Assert.assertNotNull("r2 should be found", r2); + UnsignedAppletActionEntry r4 = i1.getMatchingItem("bla", "blaBla", null); + Assert.assertNotNull("r4 should be found", r4); + UnsignedAppletActionEntry r5 = i1.getMatchingItem("", "blaBla", Arrays.asList(new String[]{"jar2", "jar1"})); + Assert.assertNotNull("r5 should be found", r5); + UnsignedAppletActionEntry r6 = i1.getMatchingItem(null, null, Arrays.asList(new String[]{"jar2", "jar1"})); + Assert.assertNotNull("r6 should be found", r6); + UnsignedAppletActionEntry r7 = i1.getMatchingItem(null, null, Arrays.asList(new String[]{"jar2", "jar11"})); + Assert.assertNull("r7 should NOT be found", r7); + + + } +} diff --git a/tests/netx/unit/net/sourceforge/jnlp/util/lockingfile/LockingReaderWriterTest.java b/tests/netx/unit/net/sourceforge/jnlp/util/lockingfile/LockingReaderWriterTest.java new file mode 100644 index 0000000..b834f88 --- /dev/null +++ b/tests/netx/unit/net/sourceforge/jnlp/util/lockingfile/LockingReaderWriterTest.java @@ -0,0 +1,232 @@ +/* +Copyright (C) 2013 Red Hat + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package net.sourceforge.jnlp.util.lockingfile; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.junit.Assert; +import org.junit.Test; + +public class LockingReaderWriterTest { + + private static File storagefile; + + private static TestStringReaderWriter newInstance() { + return new TestStringReaderWriter(storagefile); + } + + @Before + public void setUp() throws IOException { + storagefile = File.createTempFile("foo", "bar"); + } + + @Test + public void testSimpleActions() throws IOException { + TestStringReaderWriter storage = newInstance(); + + storage.add("teststring"); + assertTrue(storage.contains("teststring")); + storage.remove("teststring"); + assertFalse(storage.contains("teststring")); + } + + @Test + public void testInterleavedActions() throws IOException { + TestStringReaderWriter storage1 = newInstance(); + TestStringReaderWriter storage2 = newInstance(); + + storage1.add("teststring"); + assertTrue(storage2.contains("teststring")); + storage2.remove("teststring"); + assertFalse(storage1.contains("teststring")); + } + + static class TestThread extends Thread { + String testString; + int iterations; + Throwable error = null; + + TestThread(String testString, int iterations) { + this.testString = testString; + this.iterations = iterations; + } + + @Override + public void run() { + try { + TestStringReaderWriter storage = newInstance(); + for (int i = 0; i < iterations; i++) { + assertTrue(storage.contains(this.testString)); + storage.add(this.testString); + storage.remove(this.testString); + assertTrue(storage.contains(this.testString)); + } + } catch (Throwable error) { + error.printStackTrace(); + this.error = error; + } + } + } + + private void concurrentReadWrites(int threadAmount, int iterations, + String testString) throws InterruptedException { + TestStringReaderWriter storage = newInstance(); + + storage.add(testString); + + List<TestThread> testThreads = new ArrayList<TestThread>(); + + for (int i = 0; i < threadAmount; i++) { + TestThread thread = new TestThread(testString, iterations); + testThreads.add(thread); + thread.start(); + } + + for (int i = 0; i < threadAmount; i++) { + testThreads.get(i).join(); + } + + assertTrue(storage.contains(testString)); + storage.remove(testString); + + // So long as number adds == number writes, we should be left with + // nothing at end. + assertFalse(storage.contains(testString)); + } + + // Long testing string, the contents are not important + private String makeLongTestString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 1000; i++) { + sb.append(Integer.toString(i)); + } + return sb.toString(); + } + + @Test + public void testManyReadWrite() throws Exception { + int oneThread = 1; + String shortString = "teststring"; + + // This was causing 'too many open files' because FileUtils#getFileLock + // leaks file descriptors. No longer used. + concurrentReadWrites(oneThread, 500 /* iterations */, shortString); + } + + @Test + public void testManyThreads() throws Exception { + int threadAmount = 25; + String shortString = "teststring"; + String longString = makeLongTestString(); + + concurrentReadWrites(threadAmount, 10 /* per-thread iterations */, + shortString); + concurrentReadWrites(threadAmount, 2 /* per-thread iterations */, + longString); + } + + /** + * Concrete implementation to aid in testing LockingReaderWriter + */ + public static class TestStringReaderWriter extends LockingReaderWriter { + + private List<String> cachedContents = new ArrayList<String>(); + + public TestStringReaderWriter(File file) { + super(file); + } + + @Override + public void writeContent(BufferedWriter writer) throws IOException { + for (String string : cachedContents) { + writer.write(string); + writer.newLine(); + } + } + + @Override + protected void readLine(String line) { + this.cachedContents.add(line); + } + + @Override + protected void readContents() throws IOException { + cachedContents.clear(); + super.readContents(); + } + + /* + * Atomic container abstraction methods. + */ + synchronized public void add(final String line) { + doLocked(new Runnable() { + + public void run() { + try { + readContents(); + cachedContents.add(line); + writeContents(); + } catch (IOException ex) { + throw new StorageIoException(ex); + } + } + }); + } + + synchronized public boolean contains(final String line) { + final boolean[] doesContain = { false }; + doLocked(new Runnable() { + + public void run() { + try { + readContents(); + doesContain[0] = cachedContents.contains(line); + } catch (IOException e) { + throw new StorageIoException(e); + } + } + }); + return doesContain[0]; + } + + synchronized public boolean remove(final String line) { + final boolean[] didRemove = { false }; + + doLocked(new Runnable() { + public void run() { + try { + readContents(); + didRemove[0] = cachedContents.remove(line); + writeContents(); + } catch (IOException e) { + throw new StorageIoException(e); + } + } + }); + + return didRemove[0]; + } + } +}
\ No newline at end of file |