My company produces Java Applications for Servers and delivers JNLP files to start local Applications. Since OSX 10.8.4 it is required to sign JNLP files with a Developer ID to keep Gatekeeper happy (it's actually in the release notes at the very bottom).
The question is: how to accomplish this? AFAIK you can sign Apps (we have some Java Apps signed with Developer IDs) - but JNLP - Files are just that: files.
Next: how to do this with generated JNLP files. We have to modify them as they come from a server - e.g. properties, base URL and so forth.
AFAIK Java has a certain mechanism to say JNLP files are signed via their respective JAR file (the one that holds the main class) - but: Jar files are signed with a different certificate they will not satisfy Gatekeeper as well.
I did find one reference on how to sign tools and stuff, but it does not apply the scenario of dynamic files.
What I do not want as answers: Right-Click and Open to override the Gatekeeper or change the System- or Java settings. This is not an option.
[UPDATE]
Since OSX 10.9.5 you also have to sign using OSX 10.9+ and have valid version 2 signatures. How will this be done?
I think I found a solution. The only one I can currently think up. We basically need to wrap the JNLP with a custom app launcher, sign the app, make sure we can modify the JNLP on the fly on a server and then have it run.
As you may be aware, there is an app bundler project which can wrap up any JAR files into an OSX executable. This can be signed, delivered and will not fail Gatekeeper. I made a custom fork (which is up for a pull int o the main fork) that can take an JNLP file, wrap it up and you have a custom application doing just all the stuff a JNLP should do.
A Requirement is, however, that you do have a valid "Developer ID Application" certificate
Head over to bitbucket.org and download the current version
Run the ant task and build the appbundler package.
Have a look at the documentation for an example build script that will create the app container.
The example does not include the JNLP into the application right now.
The applications signature is created in a way so that the JNLP file can be modified later.
The application is being put into a zip file. This is important for downloading an application since they are only directories
Create your server code. Load the ZIP file, put the JNLP File into the directory <yourapp>.app/Contents/Java/
Deliver the zip file.
Now, if everything went fine, the zip file should automatically be unpacked in the Download folder and you should see your application icon. If you really made no mistake, you can execute the application as if it was a normal one.
I hope this will help a lot of developers fixing the broken JNLP behavior with OSX.
[UPDATE for modifiable JNLPs]
Since OSX 10.9.5 it is required to have valid version 2 signatures on your app. This means that it the trick that was previously used by the app bundler (set a resource list file) does not work anymore. Everything and anything has to be signed now and it is virtually impossible to change the signed app afterwards.
I did however find a way: Use the app bundler. Set the JNLP to a file inside the Contents/_CodeSignature directory. Do not yet copy your modifiable JNLP in there but do this e.g. using Java later on when patching the zip (you'll need some code here anyway).
Please note: this should really only be needed if you have to put another JNLP file dynamically into the app container (thats is what the questions was about)
UPDATE (08-2017)
Oracle will be releasing Java 9 by the end of September. The appbundler does not handle the java9 vm correctly. They changed a whole lot of the API and the way that javaws works. For I need to say: stick with java8 if you want to use wrapped JNLP apps.
We've been able to determine that you can sign a jnlp file with codesign, using the "Developer ID Application" Certificate, like this:
codesign -f -s "Developer ID Application: " foo.jnlp
The result from this operation seems to pass Gatekeeper on the local machine. However, it seems like the signature gets stored as extended HFS attributes, and as a result, it is not transmitted if a user fetches the file from a HTTP transaction.
It might work if you took the .jnlp file, and packaged it in some kind of container, like a .dmg or maybe a .tar.gz, however, that's both a lot of work, and it provides a fairly challenging user experience.
From an email thread with Apple tech support, it seems the official word is to use the xip tool to work around the reliance on HFS extended attributes with codesign:
Instead of codesign, use xip (pronounced "chip")
to create a signed archive of your JNLP file. Provide your Developer
ID Installer identity as the argument to the --sign option, not your
Developer ID Application identity.
A xip archive is essentially a signed zip archive so it can be served
over the Internet in the same way as a zip archive. It will be
unarchived automatically on the client Mac.
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/xip.1.html
From my experimentation the xip tool always generates an archive with the jnlp contained in a folder when unxip'd.
Just to summarise the discussion; currently there is no existing solution on how to come around this.
This means that end users cannot launch an application via JNLP easily. Basically one needs to tell the user to Right-Click and Open to override the Gatekeeper.
The other solution would be to make an signed Mac application and have users install that via disk image.
Would it work to bundle a simple executable shell script called something like "myapp" in a signed .dmg which looks like this:
javaws http://path/to/my/app.jnlp
that way you can change the .jnlp however you like without changing your .dmg. I don't have an Apple Developer ID, so I can't try it myself right now.
Related
I have an application that has an applet that does two simple things:
Download an executable jar file from our server (if the user doesn't already have it) to an specific folder in the user's PC
Execute the jar file with the corresponding parameters
This jar file monitors an Office file for changes and send it back to our server.
The problem is the war Chrome is creating with Java with this NPAPI thing. So I have until September to think of an alternate technology or stop the Chrome support.
Do you think of some other way to achieve the same result? Just download and execute. Doesn't seem that hard =(. Can HTML 5 do that?
EDIT
I was looking into Java Web Start and became a little happy. It appears that it can do what I want: executing a up to date jar file passing parameters. But I never worked with JWS, so I have some doubts:
Is it possible to pass parameters to it? I read about some JSP files that you can configure to do that, but I'm still unsure.
Theoretically, it should start automatically from a browser link, am I right? I tried this site:
https://docs.oracle.com/javase/tutorial/deployment/webstart/running.html
and it didn't work that way. I had to mark "always open files of that type" on Google Chrome. Is there a way for automatize it?
Thanks again!!
From what I know there are at least two things that allow you to stick with Java.
Webstart
Install4
Webstart is provided by Oracle and allows you to download Java program from the web and execute them. Update mechanisms exist, so you can always provide a current version.
Install4J (or any other installer for Java applications that offers an update mechanism) provides an installer which enables your customer to install an application which afterwards will be kept up to date by the integrated update mechanism. But Install4J comes at a price, there might be freeware / open source alternatives. Install4J and its alternatives are often discussed here on SO, you might want to check here.
I think the FileAPI of HTML5 is limited and can not access arbitrary files because a sandbox prevents this. You might check SO again for details about that.
I'm using the following link to access JNLP API's:
Using Filechooser
The project: JWSFileChooserDemo
Basically I want an Open and Save dialog box to get "text" file from user, saving it on server, reading it, processing etc and then showing the same .java file on Website.
For the above 2 lines I've tried:
1. "Integration of Applet with Web Application", this integration works correctly but integration of "Applet .jar file in Web Application" restricts the reading of file.
2. Then I used Servlets to do the same job, but file reading doesn't works therefor me.
3. Now, I'm using JNLP, Java Web Start for the same.
But according to what I've read on the website, the applet should be signed for these file operations. Under NetbeansIDE there is an option to enable WEB START and self-signing an applet. But this doesn't work for me.
I created the same program as mentioned in the link(using javax.jnlp), but after clicking on Open, it is looping towards else statement which shows "User cancelled save request.".
I think, the above error is due applet is not signed properly as when I run the JNLP file given on the link..it asks for following confirmation i.e.
So, should I sign an applet using Project properties->WebStart->Enable WebStart->signing->self-signing by generated key or by signing it using keytools which generated certificate i.e .crt file. Is there any other way to do this?
Is there any other way to do this?
It is possible to use the JNLP API services in an unsigned application. Having said that, Oracle has decided that in a future JRE, unsigned code will not be loaded at all (using the default security preferences).
Note that those two linked pages refer to two different ways to load files.
'Using Filechooser' uses the JFileChooser provided with Swing. An applet/JWS app. that uses a file chooser needs to declare all-permissions in the launch file.
The JWSFileChooserDemo demo. OTOH, uses the JNLP API file services, and would produce a prompt at run-time similar to the one shown. At the moment these do not need to be signed.
As far as 'self signed' goes, Oracle has also put warnings against using that. The publisher of a self-signed app. at the moment, will show as UNKNOWN with extra warnings about accepting code from unknown sources. In the future, the JRE will also automatically reject self-signed code.
For the longer term, the only real option is to supply a digitally signed app. Signed using a verified certificate from a Certification Authority.
I coded a Java program to read and modify a file on the computer. The program is based only on 1 class.
At the moment who want to use it has to run it from terminal, I'm looking on how to insert it on a webpage and make it run on the visitor's computer. It would be fine to have a file chooser (the user will want this modification).
I searched on internet and found Java applets, but I read that they aren't downloaded and executed locally so the program won't work.
How to provide a Java class file from a webpage, for use on the computer of the end-user?
If you really want to download a Java program and run it locally, you should check out Java Web Start.
Briefly, it allows the user to download and run a Java program locally on their machine. It does clever stuff like identify if an updated version is available for download, and will run the cached version if that's the current version.
Here's a tutorial.
..it would be fine to have a file chooser ..
In that case, there are basically the two options as I've outlined in comments throughout this question & the answers. I'll collect them together here:
Digitally sign the applet, get the user to accept the digitally signed code when prompted (before the applet is loaded), then offer a JFileChooser to browse to the file.
If the user has a plugin 2 JRE (chase the links in the JWS info. page for more details), it is possible to deliver the applet to the user unprompted, then leverage the JNLP API to produce a file chooser. The user will be prompted before the dialog appears, this time with a more specific warning.
JWS
For an example, see my applet based GIF animation tool which uses the JNLP API when the user goes to load image frames or save the animated GIF.
That applet is not open source (mostly because of my laziness in not wanting to revisit & tidy the code) but there is a much better example of using the JNLP file services that comes complete with source.
Digital signatures
I don't have any great links about the process of digitally signing code, but note that the 'example of using the JNLP file services' listed above provides one set of signed Jars for 2 different security environments. It also (hopefully obviously) demonstrates how to digitally sign code using Ant (it all happens by invoking the default task in the build.xml).
Applets can modify files locally, if they are signed and the user allows them to.
Read up on signed applets.
I read that they aren't downloaded and excuted locally
Whereever you read that, it is 100% incorrect. Applets are downloaded into the browser and executed at the client host.
I have created a Java software with a graphical interface using SWING. I have packaged it in a runneable JAR file by using he "export" function of ECLIPSE and it runs fine on my computer.
However, the function of reading files of my software does not work on some other computers.
I guess that it must be a security permission problem.
So my question is: how to give the permissions to my Jar file or how the user can give the permissions so that my software is allowed to read file?
I'm looking for something as simple as possible as i'm not going to sell my software.
EDIT: My application is a desktop application (not an applet).
Thanks,
Digitally sign the Jar.
Create an XML based (JNLP) launch file for it.
Launch it from a link using Java Web Start. JWS can install desktop shortcuts & menu items for it, if requested in the launch file and supported on the target OS.
I'm looking for something as simple as possible..
Installing applications in a way that is reliable & simple for the end user, is not easy for the developer.
We have to make a Java application demo available on Internet using JWS. It goes pretty well; all that's missing is making working directory files available for the application.
We know about the getResource() way... The problem is that we have different plugins for the same application and each one require different files (and often different versions of the same files) in their working directory to work properly. So we just change the working directory when we want the application to have a different behavior.
Currently, the demo is packaged in a signed jar file and it loads correctly until it requires a file from the working directory. Obviously, the Internet users of this demo don't have the files ready. We need a way to make these files available to the WebStart application (read/write access) in its working directory.
We've thought of some things, like having the application download the files itself when it starts, or package them in the jar and extract them on startup.
Looking for advices and/or new ideas. I'll continue working on this... I'll update if I ever find something reliable.
Thank you very much!
I said I would share what I found in my research for something that would fit my needs. Here's what I have so far.
I have found that the concept of current working directory (CWD) does not really make sense in the context of a Java Web Start (JWS) application. This had for effect that I stopped trying to find the CWD of a JWS and started looking for other options.
I have found that (no, I didn't know that) you can refer (using getResource()) to a file in the root directory of a JAR file by simply adding a '/' in front of its name. ("/log4j.properties", for example.) The impact of this is that I can now take any file which is only referred to in a read-only manner in the root of that JAR file (which is really only a ZIP file). You can refer to any file in the root of the JAR file using AnyClass.class.getResourceAsStream. That rules out the problem with read-only files required to run the application, at the cost of a switch in the code telling whether the application is run from a valid CWD or from a JWS context. (You can very simply set a property in the JNLP file of the JWS application and check if that property is set or not to know where to look for the file.)
For write-only files (log files in my case), I used the property , adding a directory with the name of the application: <user.home>/.appname and added log files to it.
Read/write files (which I don't have in my case) would probably simply go at the same place than write-only files. The software could deal with uploading them somewhere if needed, once modified, I guess.
That's the way I deal with the problem for now.
Note there is a service you can explicitly ask for, to get file access to the computer (unless you go all the way and ask for full access (which requires signed jar files)).
Then you need to determine where these files need to go - basically you have no idea what is where and whether you may actually write anywhere. You can create tmp-files but those go away.
Would a file system abstraction talking to the JNLP-server do so you store the users data on the server?