diff options
| author | clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2009-08-13 09:19:28 +0000 | 
|---|---|---|
| committer | clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2009-08-13 09:19:28 +0000 | 
| commit | 79016a7b2f9d89e52e991b0abdfc73ad24e60979 (patch) | |
| tree | 96c5a625181af1f4d8da241eb53281bf22bbbda1 /BKUWebStart/src/main/java | |
| parent | ec680d62e3e2564d0854b2d34827d7d61f84b709 (diff) | |
| download | mocca-79016a7b2f9d89e52e991b0abdfc73ad24e60979.tar.gz mocca-79016a7b2f9d89e52e991b0abdfc73ad24e60979.tar.bz2 mocca-79016a7b2f9d89e52e991b0abdfc73ad24e60979.zip | |
[#433] update BKU Web Start CertStore 
WebStart configuration refactored
git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@423 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
Diffstat (limited to 'BKUWebStart/src/main/java')
6 files changed, 1151 insertions, 432 deletions
| diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/BKULauncher.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/BKULauncher.java deleted file mode 100644 index abc0b8ee..00000000 --- a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/BKULauncher.java +++ /dev/null @@ -1,418 +0,0 @@ -package at.gv.egiz.bku.webstart;
 -
 -import iaik.asn1.CodingException;
 -import java.io.File;
 -import java.io.FileNotFoundException;
 -import java.io.FileOutputStream;
 -import java.io.IOException;
 -import java.io.InputStream;
 -import java.io.OutputStream;
 -import java.net.MalformedURLException;
 -import java.security.KeyStore;
 -import java.security.KeyStoreException;
 -import java.security.NoSuchAlgorithmException;
 -import java.security.cert.CertificateException;
 -import java.util.Enumeration;
 -import java.util.Locale;
 -import java.util.MissingResourceException;
 -import java.util.ResourceBundle;
 -import java.util.logging.Level;
 -import java.util.logging.Logger;
 -import java.util.zip.ZipEntry;
 -import java.util.zip.ZipFile;
 -
 -//import org.apache.commons.cli.CommandLine;
 -//import org.apache.commons.cli.CommandLineParser;
 -//import org.apache.commons.cli.HelpFormatter;
 -//import org.apache.commons.cli.Options;
 -//import org.apache.commons.cli.ParseException;
 -//import org.apache.commons.cli.PosixParser;
 -import org.apache.commons.logging.Log;
 -import org.apache.commons.logging.LogFactory;
 -
 -import at.gv.egiz.bku.webstart.ui.BKUControllerInterface;
 -import at.gv.egiz.bku.webstart.ui.TrayIconDialog;
 -import at.gv.egiz.bku.utils.StreamUtil;
 -import java.awt.Desktop;
 -import java.io.BufferedInputStream;
 -import java.io.BufferedOutputStream;
 -import java.io.BufferedReader;
 -import java.io.BufferedWriter;
 -import java.io.FileInputStream;
 -import java.io.FileReader;
 -import java.io.FileWriter;
 -import java.net.BindException;
 -import java.net.URI;
 -import java.net.URL;
 -import java.security.GeneralSecurityException;
 -import java.util.UUID;
 -import java.util.jar.Attributes;
 -import java.util.jar.Manifest;
 -import java.util.zip.ZipOutputStream;
 -import org.mortbay.util.MultiException;
 -
 -public class BKULauncher implements BKUControllerInterface {
 -
 -  /** configurations with less than this (major) version will be backuped and updated */
 -  public static final String MIN_CONFIG_VERSION = "1.0.3";
 -  public static final String CONFIG_DIR = ".mocca/conf/";
 -  public static final String CONF_TEMPLATE_FILE = "configuration.zip";
 -  public static final String CONF_TEMPLATE_RESOURCE = "at/gv/egiz/bku/webstart/conf/configuration.zip";
 -  public static final String WEBAPP_RESOURCE = "BKULocal.war";
 -  public static final String WEBAPP_FILE = "BKULocal.war";
 -  public static final String KEYSTORE_FILE = "keystore.ks";
 -  public static final String MESSAGES_RESOURCE = "at/gv/egiz/bku/webstart/ui/UIMessages";
 -  public static final String PASSWD_FILE = ".secret";
 -  /** resource bundle messages */
 -  public static final String GREETING_CAPTION = "Greetings.Caption";
 -  public static final String GREETING_MESSAGE = "Greetings.Message";
 -  public static final String STARTUP_CAPTION = "Startup.Caption";
 -  public static final String ERROR_CAPTION = "Error.Caption";
 -  public static final String STARTUP_MESSAGE = "Startup.Message";
 -  public static final String ERROR_STARTUP_MESSAGE = "Error.Startup.Message";
 -  public static final String ERROR_CONF_MESSAGE = "Error.Conf.Message";
 -  public static final String ERROR_BIND_MESSAGE = "Error.Bind.Message";
 -  public static final String VERSION_FILE = ".version";
 -  private static Log log = LogFactory.getLog(BKULauncher.class);
 -  private ResourceBundle resourceBundle = null;
 -  private Container server;
 -
 -  private void createConfig(File configDir, File versionFile, String version) throws IOException, CertificateException, GeneralSecurityException, KeyStoreException, FileNotFoundException, NoSuchAlgorithmException {
 -    log.debug("creating config directory: " + configDir);
 -    configDir.mkdirs();
 -    InputStream is = getClass().getClassLoader().getResourceAsStream(CONF_TEMPLATE_RESOURCE);
 -    OutputStream os = new FileOutputStream(new File(configDir, CONF_TEMPLATE_FILE));
 -    StreamUtil.copyStream(is, os);
 -    os.close();
 -    File confTemplateFile = new File(configDir, CONF_TEMPLATE_FILE);
 -    unzip(confTemplateFile);
 -    confTemplateFile.delete();
 -    writeVersionFile(versionFile, version);
 -  }
 -
 -  private void createCertificates(File configDir) throws IOException, GeneralSecurityException, CodingException {
 -    char[] password = UUID.randomUUID().toString().toCharArray();
 -    File passwdFile = new File(configDir, PASSWD_FILE);
 -    FileWriter passwdWriter = new FileWriter(passwdFile);
 -    passwdWriter.write(password);
 -    passwdWriter.close();
 -    if (!passwdFile.setReadable(true, true)) {
 -      passwdFile.delete();
 -      throw new IOException("failed to make " + passwdFile + " owner readable only, deleting file");
 -    }
 -    TLSServerCA ca = new TLSServerCA();
 -    KeyStore ks = ca.generateKeyStore(password);
 -    FileOutputStream fos = new FileOutputStream(new File(configDir, KEYSTORE_FILE));
 -    ks.store(fos, password);
 -    fos.close();
 -  }
 -
 -  private String getFileVersion(File versionFile) throws FileNotFoundException, IOException {
 -    //TODO no file?
 -    if (versionFile.exists() && versionFile.canRead()) {
 -      BufferedReader versionReader = new BufferedReader(new FileReader(versionFile));
 -      String versionString = null;
 -      while ((versionString = versionReader.readLine().trim()) != null) {
 -        if (versionString.length() > 0 && !versionString.startsWith("#")) {
 -          log.debug("found existing configuration version " + versionString);
 -          break;
 -        }
 -      }
 -      return versionString;
 -    }
 -    return null;
 -  }
 -
 -  private String getManifestVersion() throws MalformedURLException, IOException {
 -    String bkuWebStartJar = BKULauncher.class.getProtectionDomain().getCodeSource().getLocation().toString();
 -    URL manifestURL = new URL("jar:" + bkuWebStartJar + "!/META-INF/MANIFEST.MF");
 -    String version = null;
 -    if (manifestURL != null) {
 -      Manifest manifest = new Manifest(manifestURL.openStream());
 -      if (log.isTraceEnabled()) {
 -        log.trace("read version information from " + manifestURL);
 -      }
 -      Attributes atts = manifest.getMainAttributes();
 -      if (atts != null) {
 -        version = atts.getValue("Implementation-Build");
 -      }
 -    }
 -    if (version == null) {
 -      version = "UNKNOWN";
 -    }
 -    log.debug("config version: " + version);
 -    return version;
 -  }
 -
 -  /**
 -   * change the
 -   * @param oldVersion
 -   * @param newVersion
 -   * @return
 -   */
 -  private boolean updateRequired(String oldVersion, String newVersion) {
 -    if (oldVersion != null) {
 -      log.debug("comparing " + oldVersion + " to " + MIN_CONFIG_VERSION);
 -      
 -      int majorEnd = oldVersion.indexOf('-');
 -      String oldMajor = (majorEnd < 0) ? oldVersion : oldVersion.substring(0, majorEnd);
 -
 -      int compare = oldMajor.compareTo(MIN_CONFIG_VERSION);
 -      if (compare < 0 ||
 -              // SNAPSHOT versions are pre-releases (update if release required)
 -              (compare == 0 && oldVersion.startsWith("-SNAPSHOT", majorEnd))) {
 -        return true;
 -      } else {
 -        return false;
 -      }
 -    }
 -    log.debug("no old version, update required");
 -    return true;
 -  }
 -
 -  private boolean updateRequiredStrict(String oldVersion, String newVersion) {
 -    String[] oldV = oldVersion.split("-");
 -    String[] newV = newVersion.split("-");
 -    log.debug("comparing " + oldV[0] + " to " + newV[0]);
 -    if (oldV[0].compareTo(newV[0]) < 0) {
 -      log.debug("update required");
 -      return true;
 -    } else {
 -      log.debug("comparing " + oldV[oldV.length - 1] + " to " + newV[newV.length - 1]);
 -      if (oldV[oldV.length - 1].compareTo(newV[newV.length - 1]) < 0) {
 -        log.debug("update required");
 -        return true;
 -      } else {
 -        log.debug("no update required");
 -        return false;
 -      }
 -    }
 -  }
 -
 -  private void writeVersionFile(File versionFile, String version) throws IOException {
 -    BufferedWriter versionWriter = new BufferedWriter(new FileWriter(versionFile));
 -    versionWriter.write("# MOCCA Web Start configuration version\n");
 -    versionWriter.write("# DO NOT MODIFY THIS FILE\n\n");
 -    versionWriter.write(version);
 -    versionWriter.close();
 -  }
 -
 -//  private SplashScreen splash = SplashScreen.getSplashScreen();
 -  private void startUpServer() throws Exception {
 -    log.info("init servlet container and MOCCA webapp");
 -    server = new Container();
 -    // XmlConfiguration xcfg = new XmlConfiguration(getClass().getClassLoader()
 -    // .getResourceAsStream("at/gv/egiz/bku/local/app/jetty.xml"));
 -    // xcfg.configure(server);
 -    server.init();
 -    server.start();
 -  }
 -
 -  private void initTrayIcon() {
 -    log.debug("init MOCCA tray icon");
 -    Locale loc = Locale.getDefault();
 -    try {
 -      resourceBundle = ResourceBundle.getBundle(
 -              MESSAGES_RESOURCE, loc);
 -    } catch (MissingResourceException mx) {
 -      resourceBundle = ResourceBundle.getBundle(
 -              MESSAGES_RESOURCE, Locale.ENGLISH);
 -    }
 -    TrayIconDialog.getInstance().init(resourceBundle);
 -    TrayIconDialog.getInstance().setShutdownHook(this);
 -//    TrayIconDialog.getInstance().displayInfo(GREETING_CAPTION, GREETING_MESSAGE);
 -  }
 -
 -  private void initStart() {
 -  }
 -
 -  private void initFinished(boolean installCert) {
 -    try {
 -//      if (splash != null) {
 -//        try {
 -//          splash.close();
 -//        } catch (IllegalStateException ex) {
 -//          log.warn("Failed to close splash screen: " + ex.getMessage());
 -//        }
 -//      }
 -
 -      if (installCert) {
 -        log.debug("trying install MOCCA certificate on system browser");
 -        if (Desktop.isDesktopSupported()) {
 -          Desktop desktop = Desktop.getDesktop();
 -          if (desktop.isSupported(Desktop.Action.BROWSE)) {
 -            try {
 -              desktop.browse(new URI("https://localhost:" +
 -                      Integer.getInteger(Container.HTTPS_PORT_PROPERTY, 3496).intValue()));
 -            } catch (Exception ex) {
 -              log.error("failed to open system browser, install MOCCA certificate manually", ex);
 -            }
 -          } else {
 -            log.error("failed to open system browser, install MOCCA certificate manually");
 -          }
 -        } else {
 -          log.error("failed to open system browser, install MOCCA certificate manually");
 -        }
 -      }
 -
 -      log.info("init completed, joining server");
 -      server.join();
 -    } catch (InterruptedException e) {
 -      log.warn("failed to join MOCCA server: " + e.getMessage(), e);
 -    }
 -  }
 -
 -  private void unzip(File zipfile) throws IOException {
 -    File dir = zipfile.getParentFile();
 -    ZipFile zipFile = new ZipFile(zipfile);
 -    Enumeration<? extends ZipEntry> entries = zipFile.entries();
 -    while (entries.hasMoreElements()) {
 -      ZipEntry entry = entries.nextElement();
 -      File eF = new File(dir, entry.getName());
 -      if (entry.isDirectory()) {
 -        eF.mkdirs();
 -        continue;
 -      }
 -      File f = new File(eF.getParent());
 -      f.mkdirs();
 -      StreamUtil.copyStream(zipFile.getInputStream(entry),
 -              new FileOutputStream(eF));
 -    }
 -    zipFile.close();
 -  }
 -
 -  /**
 -   * @param args
 -   */
 -  public static void main(String[] args) throws InterruptedException {
 -
 -    if (log.isDebugEnabled()) {
 -      //System.setProperty("DEBUG", "true");
 -      System.setProperty("VERBOSE", "true");
 -      System.setProperty("javax.net.debug", "ssl,handshake");
 -    }
 -    
 -//      log.warn("***** DISABLING SECURITY MANAGER *******");
 -      System.setSecurityManager(null);
 -
 -      BKULauncher launcher = new BKULauncher();
 -      launcher.initStart();
 -
 -      boolean installCert = false;
 -
 -      launcher.initTrayIcon();
 -      TrayIconDialog.getInstance().displayInfo(STARTUP_CAPTION, STARTUP_MESSAGE);
 -
 -      try {
 -        File configDir = new File(System.getProperty("user.home") + '/' + CONFIG_DIR);
 -        installCert = launcher.ensureConfig(configDir);
 -      } catch (Exception ex) {
 -        log.fatal("Failed to init MOCCA configuration, exiting", ex);
 -        TrayIconDialog.getInstance().displayError(ERROR_CAPTION, ERROR_CONF_MESSAGE);
 -        Thread.sleep(5000);
 -        System.exit(-1000);
 -      }
 -
 -      try {
 -        launcher.startUpServer();
 -        TrayIconDialog.getInstance().displayInfo(GREETING_CAPTION, GREETING_MESSAGE);
 -        launcher.initFinished(installCert);
 -      } catch (BindException ex) {
 -        log.fatal("Failed to launch MOCCA, " + ex.getMessage(), ex);
 -        TrayIconDialog.getInstance().displayError(ERROR_CAPTION, ERROR_BIND_MESSAGE);
 -        Thread.sleep(5000);
 -        System.exit(-1000);
 -      } catch (MultiException ex) {
 -        log.fatal("Failed to launch MOCCA, " + ex.getMessage(), ex);
 -        if (ex.getThrowable(0) instanceof BindException) {
 -          TrayIconDialog.getInstance().displayError(ERROR_CAPTION, ERROR_BIND_MESSAGE);
 -        } else {
 -          TrayIconDialog.getInstance().displayError(ERROR_CAPTION, ERROR_STARTUP_MESSAGE);
 -        }
 -        Thread.sleep(5000);
 -        System.exit(-1000);
 -      } catch (Exception e) {
 -        log.fatal("Failed to launch MOCCA, " + e.getMessage(), e);
 -        TrayIconDialog.getInstance().displayError(ERROR_CAPTION, ERROR_STARTUP_MESSAGE);
 -        Thread.sleep(5000);
 -        System.exit(-1000);
 -      }
 -    
 -  }
 -
 -  private void backupAndDelete(File dir, URI relativeTo, ZipOutputStream zip) throws IOException {
 -    if (dir.isDirectory()) {
 -      File[] subDirs = dir.listFiles();
 -      for (File subDir : subDirs) {
 -        backupAndDelete(subDir, relativeTo, zip);
 -        subDir.delete();
 -      }
 -    } else {
 -      URI relativePath = relativeTo.relativize(dir.toURI());
 -      ZipEntry entry = new ZipEntry(relativePath.toString());
 -      zip.putNextEntry(entry);
 -      BufferedInputStream entryIS = new BufferedInputStream(new FileInputStream(dir));
 -      StreamUtil.copyStream(entryIS, zip);
 -      entryIS.close();
 -      zip.closeEntry();
 -      dir.delete();
 -    }
 -  }
 -
 -  /**
 -   * Checks whether the config directory already exists and creates it otherwise.
 -   * @param configDir the config directory to be created
 -   * @return true if a new MOCCA cert was created (and needs to be installed in the browser)
 -   */
 -  private boolean ensureConfig(File configDir) throws IOException, GeneralSecurityException, CodingException {
 -    log.debug("config directory: " + configDir);
 -    String manifestVersion = getManifestVersion();
 -    File versionFile = new File(configDir, VERSION_FILE);
 -
 -    if (configDir.exists()) {
 -      if (configDir.isFile()) {
 -        log.error("invalid config directory: " + configDir);
 -        throw new IOException("invalid config directory: " + configDir);
 -      } else {
 -        String fileVersion = getFileVersion(versionFile);
 -        if (updateRequired(fileVersion, manifestVersion)) {
 -          if (fileVersion == null) {
 -            fileVersion = "unknown";
 -          }
 -          log.info("updating configuration from " + fileVersion + " to " + manifestVersion);
 -          File moccaDir = configDir.getParentFile();
 -          File zipFile = new File(moccaDir, "conf-" + fileVersion + ".zip");
 -          ZipOutputStream zipOS = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
 -          backupAndDelete(configDir, moccaDir.toURI(), zipOS);
 -          zipOS.close();
 -          createConfig(configDir, versionFile, manifestVersion);
 -          createCertificates(configDir);
 -          return true;
 -        }
 -      }
 -    } else {
 -      createConfig(configDir, versionFile, manifestVersion);
 -      createCertificates(configDir);
 -      return true;
 -    }
 -    return false;
 -  }
 -
 -  public void shutDown() {
 -    log.info("Shutting down server");
 -    if ((server != null) && (server.isRunning())) {
 -      try {
 -        if (server.isRunning()) {
 -          server.stop();
 -        }
 -      } catch (Exception e) {
 -        log.debug(e.toString());
 -      } finally {
 -        if (server.isRunning()) {
 -          server.destroy();
 -        }
 -      }
 -    }
 -    System.exit(0);
 -  }
 -}
 diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Configurator.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Configurator.java new file mode 100644 index 00000000..ab1746ed --- /dev/null +++ b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Configurator.java @@ -0,0 +1,418 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + *  + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *  + *     http://www.apache.org/licenses/LICENSE-2.0 + *  + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package at.gv.egiz.bku.webstart; + +import at.gv.egiz.bku.utils.StreamUtil; +import iaik.asn1.CodingException; +import iaik.xml.crypto.utils.Utils; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.jdt.core.dom.ThisExpression; + +/** + * + * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> + */ +public class Configurator { + +  /** +   * MOCCA configuration +   * configurations with less than this (major) version will be backuped and updated +   * allowed: MAJOR[.MINOR[.X[-SNAPSHOT]]] +   */ +  public static final String MIN_CONFIG_VERSION = "1.0.9-SNAPSHOT"; +  public static final String CONFIG_DIR = ".mocca/conf/"; +  public static final String CERTS_DIR = ".mocca/certs/"; +  public static final String VERSION_FILE = ".version"; +  public static final String UNKOWN_VERSION = "unknown"; +  public static final String CONF_TEMPLATE_FILE = "conf-tmp.zip"; +  public static final String CONF_TEMPLATE_RESOURCE = "at/gv/egiz/bku/webstart/conf/conf.zip"; +  public static final String CERTIFICATES_PKG = "at/gv/egiz/bku/certs"; + +  /** +   * MOCCA TLS certificate +   */ +  public static final String KEYSTORE_FILE = "keystore.ks"; +  public static final String PASSWD_FILE = ".secret"; + +  private static final Log log = LogFactory.getLog(Configurator.class); +   +  /** currently installed configuration version */ +  private String version; +  private String certsVersion; +  /** whether a new MOCCA TLS cert was created during initialization */ +  private boolean certRenewed = false; + +  /** +   * Checks whether the config directory already exists and creates it otherwise. +   * @param configDir the config directory to be created +   * @throws IOException config/certificate creation failed +   * @throws GeneralSecurityException if MOCCA TLS certificate could not be created +   * @throws CodingException if MOCCA TLS certificate could not be created +   */ +  public void ensureConfiguration() throws IOException, CodingException, GeneralSecurityException { +    File configDir = new File(System.getProperty("user.home") + '/' + CONFIG_DIR); +    if (configDir.exists()) { +      if (configDir.isFile()) { +        log.error("invalid config directory: " + configDir); +        throw new IOException("invalid config directory: " + configDir); +      } else { +        version = readVersion(new File(configDir, VERSION_FILE)); +        if (log.isDebugEnabled()) { +          log.debug("config directory " + configDir + ", version " + version); +        } +        if (updateRequired(version)) { +          File moccaDir = configDir.getParentFile(); +          File zipFile = new File(moccaDir, "conf-" + version + ".zip"); +          ZipOutputStream zipOS = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile))); +          log.info("backup configuration to " + zipFile); +          backupAndDelete(configDir, moccaDir.toURI(), zipOS); +          zipOS.close(); +          initConfig(configDir); +        } +      } +    } else { +      initConfig(configDir); +    } +  } + +  /** +   * To be replaced by TSLs in IAIK-PKI +   * @throws IOException +   */ +  public void ensureCertificates() throws IOException { +    File certsDir = new File(System.getProperty("user.home") + '/' + CERTS_DIR); +    if (certsDir.exists()) { +      if (certsDir.isFile()) { +        log.error("invalid certificate store directory: " + certsDir); +        throw new IOException("invalid config directory: " + certsDir); +      } else { +        certsVersion = readVersion(new File(certsDir, VERSION_FILE)); +        if (log.isDebugEnabled()) { +          log.debug("certificate-store directory " + certsDir + ", version " + certsVersion); +        } +        String newCertsVersion = getCertificatesVersion(); +        if (updateRequiredStrict(certsVersion, newCertsVersion)) { +          File moccaDir = certsDir.getParentFile(); +          File zipFile = new File(moccaDir, "certs-" + certsVersion + ".zip"); +          ZipOutputStream zipOS = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile))); +          log.info("backup certificates to " + zipFile); +          backupAndDelete(certsDir, moccaDir.toURI(), zipOS); +          zipOS.close(); + +          createCerts(certsDir, newCertsVersion); +          certsVersion = newCertsVersion; +        } +      } +    } else { +      String newCertsVersion = getCertificatesVersion(); +      createCerts(certsDir, newCertsVersion); +      certsVersion = newCertsVersion; +    } +  } + +  /** +   *  +   * @return whether a new MOCCA TLS certificate has been created during initialization +   */ +  public boolean isCertRenewed() { +    return certRenewed; +  } + +  /** +   * @return The first valid (not empty, no comment) line of the version file or +   * "unknown" if version file cannot be read or does not contain such a line. +   */ +  protected static String readVersion(File versionFile) { +    if (versionFile.exists() && versionFile.canRead()) { +      BufferedReader versionReader = null; +      try { +        versionReader = new BufferedReader(new FileReader(versionFile)); +        String version; +        while ((version = versionReader.readLine().trim()) != null) { +          if (version.length() > 0 && !version.startsWith("#")) { +            log.debug("configuration version from " + versionFile + ": " + version); +            return version; +          } +        } +      } catch (IOException ex) { +        log.error("failed to read configuration version from " + versionFile, ex); +      } finally { +        try { +          versionReader.close(); +        } catch (IOException ex) { +        } +      } +    } +    log.debug("unknown configuration version"); +    return UNKOWN_VERSION; +  } + +  /** +   * Temporary workaround, replace with TSLs in IAIK-PKI. +   * Retrieves version from BKUCertificates.jar Manifest file.  +   * The (remote) resource URL will be handled by the JNLP loader,  +   * and the resource retrieved from the cache. +   * +   * @return +   * @throws IOException +   */ +  private static String getCertificatesVersion() throws IOException { +    String certsResourceVersion = null; +    URL certsURL = Configurator.class.getClassLoader().getResource(CERTIFICATES_PKG); +    if (certsURL != null) { +      StringBuilder url = new StringBuilder(certsURL.toExternalForm()); +      url = url.replace(url.length() - CERTIFICATES_PKG.length(), url.length(), "META-INF/MANIFEST.MF"); +      log.trace("retrieve certificates resource version from " + url); +      certsURL = new URL(url.toString()); +      Manifest certsManifest = new Manifest(certsURL.openStream()); +      Attributes atts = certsManifest.getMainAttributes(); +      if (atts != null) { +        certsResourceVersion = atts.getValue("Implementation-Version"); +        log.debug("certs resource version: " + certsResourceVersion); +      } +    } else { +      log.error("Failed to retrieve certificates resource " + CERTIFICATES_PKG); +      throw new IOException("Failed to retrieve certificates resource " + CERTIFICATES_PKG); +    } +    return certsResourceVersion; +  } + +  protected static boolean updateRequired(String oldVersion) { +     log.debug("comparing " + oldVersion + " to " + MIN_CONFIG_VERSION); +     if (oldVersion != null && !UNKOWN_VERSION.equals(oldVersion)) { +      +      int majorEnd = oldVersion.indexOf('-'); +      String oldMajor = (majorEnd < 0) ? oldVersion : oldVersion.substring(0, majorEnd); + +      String minMajor = MIN_CONFIG_VERSION; +      boolean releaseRequired = true; +      if (MIN_CONFIG_VERSION.endsWith("-SNAPSHOT")) { +        releaseRequired = false; +        minMajor = minMajor.substring(0, minMajor.length() - 9); +      } + +      int compare = oldMajor.compareTo(minMajor); +      if (compare < 0 || +              // SNAPSHOT versions are pre-releases (update if release required) +              (compare == 0 && releaseRequired && oldVersion.startsWith("-SNAPSHOT", majorEnd))) { +        log.debug("configuration update required"); +        return true; +      } else { +        log.debug("configuration up to date"); +        return false; +      } +    } +    log.debug("no old version, configuration update required"); +    return true; +  } + +  /** +   * if unknown old, update in any case +   * if known old and unknown new, don't update +   * @param oldVersion +   * @param newVersion +   * @return +   */ +  private boolean updateRequiredStrict(String oldVersion, String newVersion) { +    log.debug("comparing " + oldVersion + " to " + newVersion); +    if (oldVersion != null && !UNKOWN_VERSION.equals(oldVersion)) { +      if (newVersion != null && !UNKOWN_VERSION.equals(newVersion)) { +        String[] oldV = oldVersion.split("-"); +        String[] newV = newVersion.split("-"); +        log.trace("comparing " + oldV[0] + " to " + newV[0]); +        if (oldV[0].compareTo(newV[0]) < 0) { +          log.debug("update required"); +          return true; +        } else { +          log.trace("comparing " + oldV[oldV.length - 1] + " to " + newV[newV.length - 1]); +          if (oldV[oldV.length - 1].compareTo(newV[newV.length - 1]) < 0) { +            log.debug("update required"); +            return true; +          } else { +            log.debug("no update required"); +            return false; +          } +        } +      } +      log.debug("unknown new version, do not update"); +      return true; +    } +    log.debug("unknown old version, update required"); +    return true; +  } +   +  protected static void backupAndDelete(File dir, URI relativeTo, ZipOutputStream zip) throws IOException { +    if (dir.isDirectory()) { +      File[] subDirs = dir.listFiles(); +      for (File subDir : subDirs) { +        backupAndDelete(subDir, relativeTo, zip); +        subDir.delete(); +      } +    } else { +      URI relativePath = relativeTo.relativize(dir.toURI()); +      ZipEntry entry = new ZipEntry(relativePath.toString()); +      zip.putNextEntry(entry); +      BufferedInputStream entryIS = new BufferedInputStream(new FileInputStream(dir)); +      StreamUtil.copyStream(entryIS, zip); +      entryIS.close(); +      zip.closeEntry(); +      dir.delete(); +    } +  } + +  /** +   * set up a new MOCCA local configuration +   * (not to be called directly, call ensureConfiguration()) +   * @throws IOException config/certificate creation failed +   * @throws GeneralSecurityException if MOCCA TLS certificate could not be created +   * @throws CodingException if MOCCA TLS certificate could not be created +   */ +  protected void initConfig(File configDir) throws IOException, GeneralSecurityException, CodingException { +    createConfig(configDir, Launcher.version); +    version = Launcher.version; +    createKeyStore(configDir); +    certRenewed = true; +  } + +  private static void createConfig(File configDir, String version) throws IOException { +    if (log.isDebugEnabled()) { +      log.debug("creating configuration version " + Launcher.version + " in " + configDir ); +    } +    configDir.mkdirs(); +    File confTemplateFile = new File(configDir, CONF_TEMPLATE_FILE); +    InputStream is = Configurator.class.getClassLoader().getResourceAsStream(CONF_TEMPLATE_RESOURCE); +    OutputStream os = new BufferedOutputStream(new FileOutputStream(confTemplateFile)); +    StreamUtil.copyStream(is, os); +    os.close(); +    unzip(confTemplateFile, configDir); +    confTemplateFile.delete(); +    writeVersionFile(new File(configDir, VERSION_FILE), version); +  } + +  /** +   * set up a new MOCCA local certStore +   * @throws IOException config/certificate creation failed +   * @throws GeneralSecurityException if MOCCA TLS certificate could not be created +   * @throws CodingException if MOCCA TLS certificate could not be created +   */ +  private static void createCerts(File certsDir, String certsVersion) throws IOException { +    if (log.isDebugEnabled()) { +      log.debug("creating certificate-store " + certsDir + ", version " + certsVersion); +    } +    URL certsURL = Configurator.class.getClassLoader().getResource(CERTIFICATES_PKG); +    if (certsURL != null) { +      StringBuilder url = new StringBuilder(certsURL.toExternalForm()); +      url = url.replace(url.length() - CERTIFICATES_PKG.length(), url.length(), "META-INF/MANIFEST.MF"); +      log.debug("retrieve certificate resource names from " + url); +      certsURL = new URL(url.toString()); +      Manifest certsManifest = new Manifest(certsURL.openStream()); +      certsDir.mkdirs(); +      Iterator<String> entries = certsManifest.getEntries().keySet().iterator(); +      while (entries.hasNext()) { +        String entry = entries.next(); +        if (entry.startsWith(CERTIFICATES_PKG)) { +          String f = entry.substring(CERTIFICATES_PKG.length()); // "/trustStore/..." +          new File(certsDir, f.substring(0, f.lastIndexOf('/'))).mkdirs(); +          BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(certsDir, f))); +          log.debug(f); +          StreamUtil.copyStream(Configurator.class.getClassLoader().getResourceAsStream(entry), bos); +          bos.close(); +        } else { +          log.trace("ignore " + entry); +        } +      } +      writeVersionFile(new File(certsDir, VERSION_FILE), certsVersion); +    } else { +      log.error("Failed to retrieve certificates resource " + CERTIFICATES_PKG); +      throw new IOException("Failed to retrieve certificates resource " + CERTIFICATES_PKG); +    } +  } + +  private static void unzip(File zipfile, File toDir) throws IOException { +    ZipFile zipFile = new ZipFile(zipfile); +    Enumeration<? extends ZipEntry> entries = zipFile.entries(); +    while (entries.hasMoreElements()) { +      ZipEntry entry = entries.nextElement(); +      File eF = new File(toDir, entry.getName()); +      if (entry.isDirectory()) { +        eF.mkdirs(); +        continue; +      } +      File f = new File(eF.getParent()); +      f.mkdirs(); +      StreamUtil.copyStream(zipFile.getInputStream(entry), +              new FileOutputStream(eF)); +    } +    zipFile.close(); +  } + +  private static void writeVersionFile(File versionFile, String version) throws IOException { +    BufferedWriter versionWriter = new BufferedWriter(new FileWriter(versionFile)); +    versionWriter.write("# MOCCA Web Start configuration version\n"); +    versionWriter.write("# DO NOT MODIFY THIS FILE\n\n"); +    versionWriter.write(version); +    versionWriter.close(); +  } + +  private static void createKeyStore(File configDir) throws IOException, GeneralSecurityException, CodingException { +    char[] password = UUID.randomUUID().toString().toCharArray(); +    File passwdFile = new File(configDir, PASSWD_FILE); +    FileWriter passwdWriter = new FileWriter(passwdFile); +    passwdWriter.write(password); +    passwdWriter.close(); +    if (!passwdFile.setReadable(false, false) || !passwdFile.setReadable(true, true)) { +      passwdFile.delete(); +      throw new IOException("failed to make " + passwdFile + " owner readable only, deleting file"); +    } +    TLSServerCA ca = new TLSServerCA(); +    KeyStore ks = ca.generateKeyStore(password); +    File ksFile = new File(configDir, KEYSTORE_FILE); +    FileOutputStream fos = new FileOutputStream(ksFile); +    ks.store(fos, password); +    fos.close(); +  } +} diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Container.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Container.java index 89044486..4df90ab2 100644 --- a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Container.java +++ b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Container.java @@ -1,22 +1,28 @@  package at.gv.egiz.bku.webstart;
  import at.gv.egiz.bku.utils.StreamUtil;
 +import java.awt.AWTPermission;
  import java.io.BufferedOutputStream;
  import java.io.BufferedReader;
  import java.io.File;
  import java.io.FileNotFoundException;
  import java.io.FileOutputStream;
 +import java.io.FilePermission;
  import java.io.FileReader;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
 +import java.lang.reflect.ReflectPermission;
 +import java.net.NetPermission;
 +import java.net.SocketPermission;
 +import java.security.Permissions;
 +import java.security.SecurityPermission;
 +import java.util.PropertyPermission;
 +import javax.smartcardio.CardPermission;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.mortbay.jetty.Connector;
 -import org.mortbay.jetty.Handler;
  import org.mortbay.jetty.Server;
 -import org.mortbay.jetty.handler.DefaultHandler;
 -import org.mortbay.jetty.handler.HandlerCollection;
  import org.mortbay.jetty.nio.SelectChannelConnector;
  import org.mortbay.jetty.security.SslSocketConnector;
  import org.mortbay.jetty.webapp.WebAppContext;
 @@ -28,12 +34,18 @@ public class Container {    public static final String HTTPS_PORT_PROPERTY = "mocca.http.port";
    private static Log log = LogFactory.getLog(Container.class);
 +  static {
 +    if (log.isDebugEnabled()) {
 +      //Jetty log INFO and WARN, include ignored exceptions
 +      //jetty logging may be further restricted by setting level in log4j.properties
 +      System.setProperty("VERBOSE", "true");
 +      //do not set Jetty DEBUG logging, produces loads of output
 +      //System.setProperty("DEBUG", "true");
 +    }
 +  }
    private Server server;
 -  public Container() {
 -  }
 -
    public void init() throws IOException {
  //    System.setProperty("DEBUG", "true");
      server = new Server();
 @@ -55,15 +67,15 @@ public class Container {      sslConnector.setPort(Integer.getInteger(HTTPS_PORT_PROPERTY, 3496).intValue());
      sslConnector.setAcceptors(1);
      sslConnector.setHost("127.0.0.1");
 -    File configDir = new File(System.getProperty("user.home") + "/" + BKULauncher.CONFIG_DIR);
 -    File keystoreFile = new File(configDir, BKULauncher.KEYSTORE_FILE);
 +    File configDir = new File(System.getProperty("user.home") + "/" + Configurator.CONFIG_DIR);
 +    File keystoreFile = new File(configDir, Configurator.KEYSTORE_FILE);
      if (!keystoreFile.canRead()) {
        log.error("MOCCA keystore file not readable: " + keystoreFile.getAbsolutePath());
        throw new FileNotFoundException("MOCCA keystore file not readable: " + keystoreFile.getAbsolutePath());
      }
      log.debug("loading MOCCA keystore from " + keystoreFile.getAbsolutePath());
      sslConnector.setKeystore(keystoreFile.getAbsolutePath());
 -    File passwdFile = new File(configDir, BKULauncher.PASSWD_FILE);
 +    File passwdFile = new File(configDir, Configurator.PASSWD_FILE);
      BufferedReader reader = new BufferedReader(new FileReader(passwdFile));
      String pwd;
      while ((pwd = reader.readLine()) != null) {
 @@ -107,7 +119,6 @@ public class Container {      sslConnector.setExcludeCipherSuites(RFC4492CipherSuites);
 -
      server.setConnectors(new Connector[] { connector, sslConnector });
      WebAppContext webapp = new WebAppContext();
 @@ -116,13 +127,13 @@ public class Container {      webapp.setExtractWAR(true); 
      webapp.setParentLoaderPriority(false);
 -    webapp.setWar(copyWebapp(webapp.getTempDirectory())); //getClass().getClassLoader().getResource("BKULocalWar/").toString());
 -
 +    webapp.setWar(copyWebapp(webapp.getTempDirectory()));
 +    webapp.setPermissions(getPermissions(webapp.getTempDirectory()));
 +    
      server.setHandler(webapp);
      server.setGracefulShutdown(1000*3);
    }
 -
    private String copyWebapp(File webappDir) throws IOException {
      File webapp = new File(webappDir, "BKULocal.war");
      log.debug("copying BKULocal classpath resource to " + webapp);
 @@ -133,6 +144,44 @@ public class Container {      return webapp.getPath();
    }
 +  private Permissions getPermissions(File webappDir) {
 +    Permissions perms = new Permissions();
 +
 +    // jetty-webstart (spring?)
 +    perms.add(new RuntimePermission("getClassLoader"));
 +
 +    // standard permissions
 +    perms.add(new PropertyPermission("*", "read"));
 +    perms.add(new RuntimePermission("accessDeclaredMembers"));
 +    perms.add(new RuntimePermission("accessClassInPackage.*"));
 +    perms.add(new RuntimePermission("defineClassInPackage.*"));
 +    perms.add(new RuntimePermission("setFactory"));
 +    perms.add(new RuntimePermission("getProtectionDomain"));
 +    perms.add(new RuntimePermission("modifyThread"));
 +    perms.add(new RuntimePermission("modifyThreadGroup"));
 +    perms.add(new RuntimePermission("setFactory"));
 +    perms.add(new ReflectPermission("suppressAccessChecks"));
 +
 +    // MOCCA specific
 +    perms.add(new SocketPermission("*", "connect,resolve"));
 +    perms.add(new NetPermission("specifyStreamHandler"));
 +    perms.add(new SecurityPermission("insertProvider.*"));
 +    perms.add(new SecurityPermission("putProviderProperty.*"));
 +    perms.add(new SecurityPermission("removeProvider.*"));
 +    perms.add(new CardPermission("*", "*"));
 +    perms.add(new AWTPermission("*"));
 +
 +    perms.add(new FilePermission(webappDir.getAbsolutePath() + "/-", "read"));
 +    perms.add(new FilePermission(new File(System.getProperty("java.home") + "/lib/xalan.properties").getAbsolutePath(), "read"));
 +    perms.add(new FilePermission(new File(System.getProperty("java.home") + "/lib/xerces.properties").getAbsolutePath(), "read"));
 +    perms.add(new FilePermission(new File(System.getProperty("user.home")).getAbsolutePath(), "read, write"));
 +    perms.add(new FilePermission(new File(System.getProperty("user.home") + "/-").getAbsolutePath(), "read, write"));
 +    perms.add(new FilePermission(new File(System.getProperty("user.home") + "/.mocca/logs/*").getAbsolutePath(), "read, write,delete"));
 +
 +
 +    return perms;
 +  }
 +
    public void start() throws Exception {
      server.start();
    }
 diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Launcher.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Launcher.java new file mode 100644 index 00000000..f7be7b65 --- /dev/null +++ b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/Launcher.java @@ -0,0 +1,230 @@ +package at.gv.egiz.bku.webstart;
 +
 +import iaik.asn1.CodingException;
 +import java.io.IOException;
 +import java.net.URISyntaxException;
 +import java.util.Locale;
 +import java.util.MissingResourceException;
 +import java.util.ResourceBundle;
 +
 +import javax.jnlp.UnavailableServiceException;
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.gv.egiz.bku.webstart.ui.BKUControllerInterface;
 +import at.gv.egiz.bku.webstart.ui.TrayIconDialog;
 +import com.sun.javaws.security.JavaWebStartSecurity;
 +import java.awt.Desktop;
 +import java.awt.SplashScreen;
 +import java.net.BindException;
 +import java.net.URI;
 +import java.net.URL;
 +import java.security.GeneralSecurityException;
 +import java.util.jar.Attributes;
 +import java.util.jar.Manifest;
 +import javax.jnlp.BasicService;
 +import javax.jnlp.ServiceManager;
 +import org.mortbay.util.MultiException;
 +
 +public class Launcher implements BKUControllerInterface {
 +
 +  public static final String WEBAPP_RESOURCE = "BKULocal.war";
 +  public static final String CERTIFICATES_RESOURCE = "BKUCertificates.jar";
 +  public static final String WEBAPP_FILE = "BKULocal.war";
 +  public static final String MESSAGES_RESOURCE = "at/gv/egiz/bku/webstart/ui/UIMessages";
 +  /** resource bundle messages */
 +  public static final String GREETING_CAPTION = "Greetings.Caption";
 +  public static final String GREETING_MESSAGE = "Greetings.Message";
 +  public static final String CONFIG_CAPTION = "Config.Caption";
 +  public static final String CONFIG_MESSAGE = "Config.Message";
 +  public static final String STARTUP_CAPTION = "Startup.Caption";
 +  public static final String STARTUP_MESSAGE = "Startup.Message";
 +  public static final String ERROR_CAPTION = "Error.Caption";
 +  public static final String ERROR_STARTUP_MESSAGE = "Error.Startup.Message";
 +  public static final String ERROR_CONF_MESSAGE = "Error.Conf.Message";
 +  public static final String ERROR_BIND_MESSAGE = "Error.Bind.Message";
 +  public static final URI HTTPS_SECURITY_LAYER_URI;
 +  private static Log log = LogFactory.getLog(Launcher.class);
 +
 +  static {
 +    URI tmp = null;
 +    try {
 +      tmp = new URI("https://localhost:" + Integer.getInteger(Container.HTTPS_PORT_PROPERTY, 3496).intValue());
 +    } catch (URISyntaxException ex) {
 +      log.error(ex);
 +    } finally {
 +      HTTPS_SECURITY_LAYER_URI = tmp;
 +    }
 +  }
 +
 +  public static final String version;
 +  static {
 +    String tmp = Configurator.UNKOWN_VERSION;
 +    try {
 +      String bkuWebStartJar = Launcher.class.getProtectionDomain().getCodeSource().getLocation().toString();
 +      URL manifestURL = new URL("jar:" + bkuWebStartJar + "!/META-INF/MANIFEST.MF");
 +      if (log.isTraceEnabled()) {
 +        log.trace("read version information from " + manifestURL);
 +      }
 +      Manifest manifest = new Manifest(manifestURL.openStream());
 +      Attributes atts = manifest.getMainAttributes();
 +      if (atts != null) {
 +        tmp = atts.getValue("Implementation-Build");
 +      }
 +    } catch (IOException ex) {
 +      log.error("failed to read version", ex);
 +    } finally {
 +      version = tmp;
 +      log.info("BKU Web Start " + version);
 +    }
 +  }
 +
 +  private Configurator config;
 +  private Container server;
 +  private BasicService basicService;
 +
 +  private void initStart() {
 +    try {
 +      basicService = (BasicService) ServiceManager.lookup("javax.jnlp.BasicService");
 +      if (basicService.isOffline()) {
 +        log.info("launching MOCCA Web Start offline");
 +      } else {
 +        log.info("launching MOCCA Web Start online");
 +      }
 +    } catch (UnavailableServiceException ex) {
 +      log.info("Failed to obtain JNLP service: " + ex.getMessage());
 +    }
 +  }
 +
 +  private void initTrayIcon() {
 +    log.debug("init MOCCA tray icon");
 +    Locale loc = Locale.getDefault();
 +    ResourceBundle resourceBundle;
 +    try {
 +      resourceBundle = ResourceBundle.getBundle(
 +              MESSAGES_RESOURCE, loc);
 +    } catch (MissingResourceException mx) {
 +      resourceBundle = ResourceBundle.getBundle(
 +              MESSAGES_RESOURCE, Locale.ENGLISH);
 +    }
 +    TrayIconDialog.getInstance().init(resourceBundle);
 +    TrayIconDialog.getInstance().setShutdownHook(this);
 +//    TrayIconDialog.getInstance().displayInfo(GREETING_CAPTION, GREETING_MESSAGE);
 +  }
 +
 +  private void initConfig() throws IOException, CodingException, GeneralSecurityException {
 +    config = new Configurator();
 +    config.ensureConfiguration();
 +    config.ensureCertificates();
 +  }
 +
 +  private void startServer() throws Exception {
 +    log.info("init servlet container and MOCCA webapp");
 +    server = new Container();
 +    server.init();
 +    server.start();
 +  }
 +
 +  private void initFinished() {
 +    try {
 +      // standalone (non-webstart) version has splashscreen
 +      if (SplashScreen.getSplashScreen() != null) {
 +        try {
 +          SplashScreen.getSplashScreen().close();
 +        } catch (IllegalStateException ex) {
 +          log.warn("Failed to close splash screen: " + ex.getMessage());
 +        }
 +      }
 +      if (config.isCertRenewed()) {
 +        // don't use basicService.showDocument(), which causes a java ssl warning dialog
 +        if (Desktop.isDesktopSupported()) {
 +          Desktop desktop = Desktop.getDesktop();
 +          if (desktop.isSupported(Desktop.Action.BROWSE)) {
 +            try {
 +              desktop.browse(HTTPS_SECURITY_LAYER_URI);
 +            } catch (Exception ex) {
 +              log.error("failed to open system browser, install TLS certificate manually: " + HTTPS_SECURITY_LAYER_URI, ex);
 +            }
 +          } else {
 +            log.error("failed to open system browser, install TLS certificate manually: " + HTTPS_SECURITY_LAYER_URI);
 +          }
 +        } else {
 +          log.error("failed to open system browser, install TLS certificate manually: " + HTTPS_SECURITY_LAYER_URI);
 +        }
 +      }
 +      log.info("BKU successfully started");
 +      server.join();
 +    } catch (InterruptedException e) {
 +      log.warn("failed to join server: " + e.getMessage(), e);
 +    }
 +  }
 +
 +  @Override
 +  public void shutDown() {
 +    log.info("Shutting down server");
 +    if ((server != null) && (server.isRunning())) {
 +      try {
 +        if (server.isRunning()) {
 +          server.stop();
 +        }
 +      } catch (Exception e) {
 +        log.debug(e.toString());
 +      } finally {
 +        if (server.isRunning()) {
 +          server.destroy();
 +        }
 +      }
 +    }
 +    System.exit(0);
 +  }
 +
 +  public static void main(String[] args) throws InterruptedException, IOException {
 +
 +    if (log.isTraceEnabled()) {
 +      SecurityManager sm = System.getSecurityManager();
 +      if (sm instanceof JavaWebStartSecurity) {
 +        System.setSecurityManager(new LogSecurityManager((JavaWebStartSecurity) sm));
 +      }
 +    }
 +
 +    Launcher launcher = new Launcher();
 +    launcher.initStart();
 +    launcher.initTrayIcon(); //keep reference? BKULauncher not garbage collected after main()
 +    
 +    try {
 +      TrayIconDialog.getInstance().displayInfo(CONFIG_CAPTION, CONFIG_MESSAGE);
 +      launcher.initConfig();
 +    } catch (Exception ex) {
 +      log.fatal("Failed to initialize configuration", ex);
 +      TrayIconDialog.getInstance().displayError(ERROR_CAPTION, ERROR_CONF_MESSAGE);
 +      Thread.sleep(5000);
 +      System.exit(-1000);
 +    }
 +
 +    try {
 +      TrayIconDialog.getInstance().displayInfo(STARTUP_CAPTION, STARTUP_MESSAGE);
 +      launcher.startServer();
 +      TrayIconDialog.getInstance().displayInfo(GREETING_CAPTION, GREETING_MESSAGE);
 +      launcher.initFinished();
 +    } catch (BindException ex) {
 +      log.fatal("Failed to launch server, " + ex.getMessage(), ex);
 +      TrayIconDialog.getInstance().displayError(ERROR_CAPTION, ERROR_BIND_MESSAGE);
 +      Thread.sleep(5000);
 +      System.exit(-1000);
 +    } catch (MultiException ex) {
 +      log.fatal("Failed to launch server, " + ex.getMessage(), ex);
 +      if (ex.getThrowable(0) instanceof BindException) {
 +        TrayIconDialog.getInstance().displayError(ERROR_CAPTION, ERROR_BIND_MESSAGE);
 +      } else {
 +        TrayIconDialog.getInstance().displayError(ERROR_CAPTION, ERROR_STARTUP_MESSAGE);
 +      }
 +      Thread.sleep(5000);
 +      System.exit(-1000);
 +    } catch (Exception e) {
 +      log.fatal("Failed to launch server, " + e.getMessage(), e);
 +      TrayIconDialog.getInstance().displayError(ERROR_CAPTION, ERROR_STARTUP_MESSAGE);
 +      Thread.sleep(5000);
 +      System.exit(-1000);
 +    }
 +  }
 +}
 diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/LogSecurityManager.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/LogSecurityManager.java new file mode 100644 index 00000000..99fd403b --- /dev/null +++ b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/LogSecurityManager.java @@ -0,0 +1,440 @@ +/* + * Copyright 2008 Federal Chancellery Austria and + * Graz University of Technology + *  + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *  + *     http://www.apache.org/licenses/LICENSE-2.0 + *  + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package at.gv.egiz.bku.webstart; + +import com.sun.javaws.security.JavaWebStartSecurity; +import java.io.FileDescriptor; +import java.net.InetAddress; +import java.security.Permission; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * JVM argument -Djava.security.debug=access,failure + * (passed as attribute to java element in jnlp) is ignored. + *  + * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> + */ +public class LogSecurityManager extends SecurityManager { + +  protected static final Log log = LogFactory.getLog(LogSecurityManager.class); +  JavaWebStartSecurity sm; + +  public LogSecurityManager(JavaWebStartSecurity sm) { +    this.sm = sm; +//    AppPolicy policy = AppPolicy.getInstance(); +//    SecurityManager sm = System.getSecurityManager(); +  } + +  @Override +  public void checkAccept(String host, int port) { +    try { +      sm.checkAccept(host, port); +    } catch (SecurityException ex) { +      log.warn("checkAccept(" + host + ", " + port + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkAccess(Thread g) { +    try { +      sm.checkAccess(g); +    } catch (SecurityException ex) { +      log.warn("checkAccess(" + g + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkAccess(ThreadGroup g) { +    try { +      sm.checkAccess(g); +    } catch (SecurityException ex) { +      log.warn("checkAccess(" + g + "): " + ex.getMessage(), ex); +      throw ex; +    } + +  } + +  @Override +  public void checkAwtEventQueueAccess() { +    try { +      sm.checkAwtEventQueueAccess(); +    } catch (SecurityException ex) { +      log.warn("checkAwtEventQAccess():" + ex.getMessage(), ex); +      throw ex; +    } + +  } + +  @Override +  public void checkConnect(String host, int port) { +    try { +      sm.checkConnect(host, port); +    } catch (SecurityException ex) { +      log.warn("checkConnect(" + host + ", " + port + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkConnect(String host, int port, Object context) { +    try { +      sm.checkConnect(host, port, context); +    } catch (SecurityException ex) { +      log.warn("checkConnect(" + host + ", " + port + ", " + context + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkCreateClassLoader() { +    try { +      sm.checkCreateClassLoader(); +    } catch (SecurityException ex) { +      log.warn("checkCreateClassLoader(): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkDelete(String file) { +    try { +      sm.checkDelete(file); +    } catch (SecurityException ex) { +      log.warn("checkDelete(" + file + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkExec(String cmd) { +    try { +      sm.checkExec(cmd); +    } catch (SecurityException ex) { +      log.warn("checkExec(" + cmd + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkExit(int status) { +    try { +      sm.checkExit(status); +    } catch (SecurityException ex) { +      log.warn("checkExit(" + status + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkLink(String lib) { +    try { +      sm.checkLink(lib); +    } catch (SecurityException ex) { +      log.warn("checkLink(" + lib + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkListen(int port) { +    try { +      sm.checkListen(port); +    } catch (SecurityException ex) { +      log.warn("checkListen(" + port + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkMemberAccess(Class<?> clazz, int which) { +    try { +      sm.checkMemberAccess(clazz, which); +    } catch (SecurityException ex) { +      log.warn("checkMemberAccess(" + clazz + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkMulticast(InetAddress maddr) { +    try { +      sm.checkMulticast(maddr); +    } catch (SecurityException ex) { +      log.warn("checkMulticast(" + maddr + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkMulticast(InetAddress maddr, byte ttl) { +    try { +      sm.checkMulticast(maddr,ttl); +    } catch (SecurityException ex) { +      log.warn("checkMulticast(" + maddr + "," + ttl + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkPackageAccess(String pkg) { +    try { +      sm.checkPackageAccess(pkg); +    } catch (SecurityException ex) { +      log.warn("checkPackageAccess(" + pkg + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkPackageDefinition(String pkg) { +    try { +      sm.checkPackageDefinition(pkg); +    } catch (SecurityException ex) { +      log.warn("checkPackageDefinition(" + pkg + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkPermission(Permission perm) { +    try { +      sm.checkPermission(perm); +    } catch (SecurityException ex) { +      log.warn("checkPermission(" + perm.toString() + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkPermission(Permission perm, Object context) { +    try { +      sm.checkPermission(perm, context); +    } catch (SecurityException ex) { +      log.warn("checkPermission(" + perm.toString() + ", ctx): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkPrintJobAccess() { +    try { +      sm.checkPrintJobAccess(); +    } catch (SecurityException ex) { +      log.info("checkPrintJobAccess(): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  /** +   * allowed +   */ +  @Override +  public void checkPropertiesAccess() { +    try { +      sm.checkPropertiesAccess(); +    } catch (SecurityException ex) { +      log.info("checkPropertiesAccess(): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  /** +   * access to all properties allowed +   * @param key +   */ +  @Override +  public void checkPropertyAccess(String key) { +    try { +      sm.checkPropertyAccess(key); +    } catch (SecurityException ex) { +      log.info("checkPropertyAccess(" + key + "): " + ex.getMessage()); +      throw ex; +    } +  } + +  @Override +  public void checkRead(FileDescriptor fd) { +    try { +      sm.checkRead(fd); +    } catch (SecurityException ex) { +      log.warn("checkRead(" + fd + ") " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkRead(String file) { +    try { +      sm.checkRead(file); +    } catch (SecurityException ex) { +      log.warn("checkRead(" + file + ") " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkRead(String file, Object context) { +    try { +      sm.checkRead(file, context); +    } catch (SecurityException ex) { +      log.warn("checkRead(" + file + ") " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkSecurityAccess(String target) { +    try { +      sm.checkSecurityAccess(target); +    } catch (SecurityException ex) { +      log.info("checkSecurityAccess(" + target + "): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public void checkSetFactory() { +    log.info("checkSetFactory() "); +    try { +      sm.checkSetFactory(); +    } catch (SecurityException ex) { +      log.warn("checkSetFactroy(): " + ex.getMessage(), ex); +      throw ex; +    } + +  } + +  @Override +  public void checkSystemClipboardAccess() { +    try { +      sm.checkSystemClipboardAccess(); +    } catch (SecurityException ex) { +      log.info("checkSystemClipboardAccess(): " + ex.getMessage(), ex); +      throw ex; +    } +  } + +  @Override +  public boolean checkTopLevelWindow(Object window) { +    log.info("checkTopLevelWindow(Object window)"); +    try { +      return sm.checkTopLevelWindow(window); +    } catch (SecurityException ex) { +      log.warn("checkTopLevelWindow(" + window + "): " + ex.getMessage(), ex); +      throw ex; +    } + +  } + +  @Override +  public void checkWrite(FileDescriptor fd) { +    try { +      sm.checkWrite(fd); +    } catch (SecurityException ex) { +      log.info("checkWrite(" + fd + "): " + ex.getMessage(), ex); +    } +  } + +  @Override +  public void checkWrite(String file) { +    try { +      sm.checkWrite(file); +    } catch (SecurityException ex) { +      log.info("checkWrite(" + file + "): " + ex.getMessage(), ex); +    } +  } + +//  @Override +//  protected int classDepth(String name) { +//    log.info("classDepth(String name)"); return this.classDepth(name); +//  } +// +//  @Override +//  protected int classLoaderDepth() { +//    log.info("classLoaderDepth"); return sm.classLoaderDepth(); +//  } +// +//  @Override +//  protected Object clone() throws CloneNotSupportedException { +//    log.info("clone"); return sm.clone(); +//  } +// +//  @Override +//  protected ClassLoader currentClassLoader() { +//    log.info("currentClassLoader"); return sm.currentClassLoader(); +//  } +// +//  @Override +//  protected Class<?> currentLoadedClass() { +//    log.info("currentLoadedClass"); return sm.currentLoadedClass(); +//  } +  @Override +  public boolean equals(Object obj) { +    log.info("equals"); +    return sm.equals(obj); +  } + +//  @Override +//  protected void finalize() throws Throwable { +//    log.info("finalize"); sm.finalize(); +//  } +//  @Override +//  protected Class[] getClassContext() { +//    log.info("getClassContext"); return sm.getClassContext(); +//  } +  @Override +  public boolean getInCheck() { +    log.info("getInCheck"); +    return sm.getInCheck(); +  } + +  @Override +  public Object getSecurityContext() { +    log.info("getSecurityContext"); +    return sm.getSecurityContext(); +  } + +  @Override +  public ThreadGroup getThreadGroup() { +    log.info("getThreadGroup"); +    return sm.getThreadGroup(); +  } + +  @Override +  public int hashCode() { +    log.info("hashCode"); +    return sm.hashCode(); +  } + +//  @Override +//  protected boolean inClass(String name) { +//    log.info("inClass"); return sm.inClass(name); +//  } +// +//  @Override +//  protected boolean inClassLoader() { +//    log.info(""); return sm.inClassLoader(); +//  } +  @Override +  public String toString() { +    log.info("toString"); +    return sm.toString(); +  } +} diff --git a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/ui/TrayIconDialog.java b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/ui/TrayIconDialog.java index 9990b2a0..fb7c40dd 100644 --- a/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/ui/TrayIconDialog.java +++ b/BKUWebStart/src/main/java/at/gv/egiz/bku/webstart/ui/TrayIconDialog.java @@ -36,7 +36,7 @@ import org.apache.commons.logging.Log;  import org.apache.commons.logging.LogFactory;  public class TrayIconDialog implements TrayIconDialogInterface { -  public static final String TRAYICON_RESOURCE = "at/gv/egiz/bku/webstart/ui/trayicon.png"; +  public static final String TRAYICON_RESOURCE = "at/gv/egiz/bku/webstart/ui/trayicon_32.png";    public static final String TRAYMENU_SHUTDOWN = "TrayMenu.Shutdown";    public static final String TRAYMENU_TOOLTIP = "TrayMenu.Tooltip"; | 
