Firefox warning for Java plugin

Web Start of unsigned Java apps: .NET to the rescue

Have you already signed your Java applets with a trusted authority certificate? You know you will have to.

Why sign?

This is supposed to provide “numerous security benefits to users”, according to Oracle. Indeed, if someone used to just visit a “get-rich-quick” site, and to unknowingly start a hidden malicious Java applet, now they will have to confirm that that they knowingly agree to start an applet provided by officially registered “get-rich-quick Pty Limited”.

As for you and me, as publishers of Java applets, how will it protect our good names? Well, the bad guys will not be able intercept our software and add their viruses to it – unless they want to use their own certificate to sign it with. This is the code repurposing which Oracle aims to prevent. One can argue that the same could be achieved by simply requiring the applets to be delivered only via secured protocol. And it would be cheaper too, for us. Some people even are questioning if all this exercise with certificates can achieve much at all…

Oracle used to tell us that “For applets and JNLP applications the best approach is often to leave the jar files unsigned. The application then runs in a sandbox and will not be able to execute any potentially dangerous code” in its Secure Coding Guidelines. Well, no more…

But for now, while you are busy collecting documents for the trusted authority to sell you the code signing certificate, why not have some fun, and see if we can deploy a Java application without help of Java Web Start. No, it won’t work for applets – which are interacting with browser DOM model. But if the purpose is to deliver a Java desktop application via Web, and to make sure it is automatically updated (even pass parameters to it – though we will not go into such details in this post), you can deliver it via… a .NET wrapper. Microsoft ClickOnce technology allows a .NET application to be deployed without security limitations, using a self-signed security certificate – and we will be able to start our Java application, deployed as part of it, bypassing Java deployment mechanisms. Of cause, only Windows users will be able to run it.

Creating .NET wrapper

Source Folders of sample Java applicationSo let’s start. We will use a small Java Swing application, consisting of one main class; it also uses a few libraries, to demonstrate application packaging. Here is how the project looks in NetBeans:

Snapshot of sample Swing applicationWhen started, it should show a small screen, where you can explorer some Swing controls in different Swing Look and Feel.

To create the .NET wrapper, we will need Microsoft Visual Studio (a C# Express edition will do). We will create a new project, called SampleLauncher, of type “WPF Application”.

When project is created, a WPF Window called MainWindow will be open in the editor. This is the only component we need: it will show when the launcher is started from the Web page, while we start the Java application in the background. Since we just need to show some message there, we replace the XAML code in the editor with the following:

<Window x:Class="SampleLauncher.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Application Launcher" Width="500" WindowStartupLocation="CenterScreen" SizeToContent="Height">
    <Grid>
        <Label Name="msgLabel" Content="Verifying application environment..." HorizontalAlignment="Stretch" />
    </Grid>
</Window>

Now we need to add our Java application to the project. Save the project to a new disk folder, using “Save All” command (uncheck “Create Directory for solution” option). Show All Files in Visual StudioOutside of VS IDE, copy the Java distribution directory, which contains the jar files, to the .NET project, next to source files. You can delete README.TXT file. Return to IDE, select the project, and select “Show All Files” option:

Changing file options in VSYou should see the folder you added. Right-click it, and select “Include in Project” command. Expand the folder, and choosing each of jar files, change its options so that the file will be copied to the .NET application. When the application starts, the jar files will be present in the program folder.

Next step will be to make WPF application to start our Java program. We will add these steps to the program logic: checking that java command is available, verifying the Java version, and executing the program. For this, expand the MainWindow.xaml node, and double-click MainWindow.xaml.cs to open it in the editor. Replace the file contents with the following code:

using System;
using System.Windows;
using System.ComponentModel;
using System.Diagnostics;

namespace SampleLauncher
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            BackgroundWorker javaLaunchWorker = new BackgroundWorker();
            javaLaunchWorker.DoWork += new DoWorkEventHandler(javaLaunchWorker_DoWork);
            javaLaunchWorker.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(javaLaunchWorker_RunWorkerCompleted);
            javaLaunchWorker.RunWorkerAsync();
        }

        private void javaLaunchWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            // 1) check Java version
            Process versionProc = new Process();
            // Redirect the output stream of the child process.
            versionProc.StartInfo.UseShellExecute = false;
            versionProc.StartInfo.RedirectStandardOutput = true;
            versionProc.StartInfo.RedirectStandardError = true;
            versionProc.StartInfo.FileName = "javaw";
            versionProc.StartInfo.Arguments = "-version";
            versionProc.Start();
            string output = versionProc.StandardOutput.ReadToEnd();
            string error = versionProc.StandardError.ReadToEnd();
            versionProc.WaitForExit();
            // let's see what was the result
            string sVersion = extractVersion(output);
            if (sVersion == null)
                sVersion = extractVersion(error);
            // result will only be a string - if there is an error to report
            if (sVersion == null)
            {
                e.Result = "Failed to find correct Java version: " + error;
                return;
            }
            if (!(sVersion.StartsWith("1.7") || sVersion.StartsWith("1.8")))
            {
                e.Result = "Only Java version 7 and 8 are supported, not " + sVersion;
                return;
            }

            // 2) now we know that java is installed and has correct version. Start the program
            Process p = new Process();
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.FileName = "javaw";
            p.StartInfo.Arguments = "-jar dist/SampleApp.jar";
            p.Start();

            bool ended = p.WaitForExit(5000);
            if (ended)
            {
                error = p.StandardError.ReadToEnd();
                if (error.Length > 0)
                    e.Result = error;
            }
        }

        void javaLaunchWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
                msgLabel.Content = e.Error.Message; // exceptions in logic
            else if (e.Result != null)
                msgLabel.Content = e.Result;    // our error message
            else
                this.Close(); // will finish WPF application
        }

        /// <summary>
        /// Extracts Java version from "java -version" output.
        /// </summary>
        /// <param name="text">not null</param>
        /// <returns>null if not found</returns>
        string extractVersion(String text)
        {
            int from = text.IndexOf('"');
            if (from < 0)
                return null;
            string next = text.Substring(from + 1);
            int to = next.IndexOf('"');
            if (to < 0)
                return null;
            return next.Substring(0, to);
        }
    }
}

WPF screen of Java lancherOf cause is not a production code – just our funny little exercise. But if you run the application from the IDE, you should see this small screen popping up for a few seconds, after which the Java application should start, and .NET application stop.

Deploying via Web Start

We will deploy our WPF application in two steps: we prepare all binary files on a local file system, and then deploy them to the web server. And the steps will be made a simple as possible, for this demo.

WPF security options for ClickOnce deploymentTo start, right-click the project item in the VS IDE, and select “Properties“. First of all, we will change application security settings, by choosing the options as shown at this screen: choosing Full Trust application.

WPF ClickOnce publish optionsNext, we will change the deployment options, on Publish tab. Publishing Folder Location will be a local file system directory of your choice. But Installation Folder URL should be the URL where the published application should be found on your web site. And we will choose the offline option.

WPF ClickOnce Application Updates optionsOn the same page, we will click Updates... button, and specify that application should check for updates before launching:

At last, back on Publish page, we can run create the files we need to deploy, by clicking the Publish Now button. (It may try to open the URL in the browser – do not worry about it).

The last step is to transfer the files from local file system directory to the web server, and to provide the web UI for starting the application.

Server folder structureYou need to transfer entire contents of the local directory to the server location which maps to the deployment URL you specified in the deployment options. The server directory will have two files, and several sub-directories. Sub-directory name includes the version of WPF application, automatically incremented each time you prepare deployment files.

Unless your web site runs on Microsoft IIS web server, you also need to make sure that your web server maps file extension application to mime-type of application/x-ms-application. Now, all you need to do to start the PWF application – and your Java Swing application – from browser, is to provide a link on some page, pointing to the .application file:

<a href="http://bytesyntony.com/attachments/SampleLauncher/SampleLauncher.application">Start it</a>

You can try the demo we prepared on our site

And so what?

So what was the purpose of this exercise? No, we do not suggest you actually use it. It just a demonstration of security restrictions, placed by different technologies on web delivery of binary content.

Did we compromise the new Java security model – a correct model, but quite expensive for developers? No, we just switched to a different model, one which allows users to run a code delivered via web, and signed with a self-signed security certificate.

Facebooktwittergoogle_plusredditpinterestlinkedinmailFacebooktwittergoogle_plusredditpinterestlinkedinmail

Leave a Reply

Your email address will not be published. Required fields are marked *