I have some Java code which depends on a system property super.secret.password. I need to set that property when i run my app. The app will be started by a shell script, and the password will be kept in a file with minimal read permissions.
I really don't want to write:
java -Dsuper.secret.password=letmein gov.fortknox.MyApp
Because then anyone who can get on to the machine and run ps or top can see what the password is.
So, is there a good way to set system properties without exposing them on the command line?
The only generic solution we've come up with is to write a small C program which reads system properties from a file, then starts the JVM using the JNI invocation API. Needless to say, we are not keen to do this.
If there isn't a way to set them without using the command line, is there a way to hide the command line from prying eyes? We're using Red Hat Enterprise Linux Server 5.5.
For what it's worth, the app in question is actually JBoss EAP 4.3.0, and we're using the system properties to fill in substitution constructs (${like.this}) in its XML configuration files. There are JBoss-specific solutions - either use the SystemPropertiesService (by default, configured through the properties-service.xml file in the deploy directory) or pass the -P option to run.sh. However, i am interested in the more general case, where this could be any Java program.
You could just read the file somewhere near startup and call System.setProperty(). For a web application use a ServletContextListener so it happens early, see this answer for a quick example.
Update: this is perhaps not early enough for your use case with JBoss loading its configuration files.
If your concern is exposing the value for super.secret.password in clear text but you are not worried about someone invoking your program with the correct value for the password because of you've covered that issue using permissions or some other means, then I think you could simply encrypt the password in your start-up script and have a wrapper class decrypt it.
java -Dsuper.secret.password=BbWvOuliHZVHVwsXudsj14d1iXzo655R gov.fortknox.DecryptWrapper
If the credentials are for a data source, I should also point out other solutions specific to JBoss: SecureIdentityLoginModule which essentially does the above, and PBEUtils which offers a keystore solution when used with SecureIdentityLoginModule. See EncryptingDataSourcePasswords.
And finally, the suggestion by Peter Lawery to use a file is valid too.
'cryptomainia' was written to solve this exact issue. It decrypts main() arguments. https://github.com/birchb1024/cryptomainia
You can read it from some file in a static initializer of your class that contains the main method:
static {
try {
FileReader fr = new FileReader(FILE_NAME);
// read the property
System.setProperty(property.getName(), property.getValue());
} catch (final FileNotFoundException ex) {
logger.log(Level.SEVERE, ex.getMessage(), ex);
} catch (final IOException ex) {
logger.log(Level.SEVERE, ex.getMessage(), ex);
}
}
...
public static void main(...){
...
}
You can use JAVA_TOOL_OPTIONS environment variable and set the property there. But it will be visible still in your script file.
if an attacker has physical access to your machine, then there is no real reason why they can't own the machine - a simple rot13 to avert the casual eye is plenty.
If an attacker has some privileges (such as running top for example), but not physical access, then you can execute the program under a specialized user account (e.g., web-server-user), which has very little privilege, but has exclusive read access to a file containing the password. you then start up the app using that user account, and pass in the file path.
Doing so relies on the access privilege restrictions in the OS, which is likely to be implemented much better than what you can roll yourself.
Related
I wrote a simple socket in java, with netbeans, that listens for connections and that can perform other simple actions.
The problem is that, i have to force users of my app, to use a specific browser (i.e. firefox). How i can achive this?
It's a good idea attach it (in a portable version) to my .jar? If yes, how i can do this?
Exist some other way to do it?
I'm not very expert in Java, so any idea or any help is appreciated :)
Thanks.
Assuming you can (legally and otherwise) bundle Firefox to your application (and I still recommend otherwise), here's a minimal example of how to use a process in java, to run Firefox parametrized with a given URL.
// this is Linux-ish - adapt accordingly
String myBundledFirefox = "/usr/bin/firefox";
String myAppURL = "http://stackoverflow.com";
ProcessBuilder pb = new ProcessBuilder(myBundledFirefox, myAppURL);
pb.start();
This may (or may not) run Firefox in your machine and open the SO page, given a relatively broad list of circumstances.
Take a look at the API, to set your expectations straight about this.
In particular, the start method lists a number of exceptional conditions, the most relevant of which listed here (quoting the docs):
SecurityException - if a security manager exists and its
checkExec method doesn't allow creation of the subprocess, or the standard input to the subprocess was redirected from a file and the security manager's checkRead method denies read access to the file, or the standard output or standard error of the subprocess was redirected to a file and the security manager's checkWrite method denies write access to the file
IOException - if an I/O error occurs
Enforcing a special browser is a bad habit.
I would suggest to rewrite some portions of your code to make it X-browser compatible.
If you have done this, you could use java-FX and create a webkit based browser instance, without using any system dependencies.
Is there a way to change working dir for JVM when running Java Webstart?
When i use system.setProperties("user.dir", newDir) it sets it(system.getProperties() shows it does) but ignores it.
Is this a limitation in Java Webstart to always use the working dir where i started the jnlp file?
I am using all permissions in the jnlp file.
Please help!
EDIT: Whatever i do now, my webstart always uses user.dir to save files. Frustrating!
I've had this question in the past myself, but I've always found that, in the end, I didn't need it. Why do I say this?
Because your java web start app is not like an executable run from Program Files. It doesn't even exist on your computer like most programs (it is broken up into a bunch of different files and reassembled by the JVM). Therefore, you cannot say that the program has its own directory to do what it needs.
But it doesn't need to. Here's why:
Java has the Preferences API to help when you need to store data. The under-workings of the Preferences API is as mysterious as JWS, thus they are really a perfect fit. Either way, if you need to write things to a file, you should check this API to see if it can meet your needs.
If you need to write files for the user, then prompting them and allowing them to choose the location obviously means you won't use your current working directory to read/write files.
If you need to serialize objects, you should just create a program directory using the user.home resource as #AndrewThompson suggested. This will be "your" directory and is as good (in fact, better) than a directory in Program Files (if you're running on Windows, as an example).
In conclusion, in all cases (that I've come across), there's no need to change your current working directory. If you need your own folder, create one in user.home (because you won't run into file permissions issues there).
..all my settings file i use is created in the user.dir.
There is the mistake. Put them in a sub-directory of user.home & the problem is solved.
In the hypothesis you really really need to divert user.dir property for Java WebStart execution, here is the only option I have found: set this system environment variable (so system wide):
_JAVA_OPTIONS="-Duser.dir=C:\Temp"
But care about it, this option is read and applied to any JVM executions.
Why was it required in my context ? Because Java WebStart ClassLoader was looking for any single resource (class, properties...) in user profile before getting it from jar files in cache. As the user profile has been moved to a network storage, application start up became terribly slow. I am still investigating Java sources to understand (and avoid) this behavior. So my applications work perfectly without setting user.dir but that was the only work-around for the performance issue we got at the moment.
The recommended way to pass runtime parameters or user specific setting is through the jnlp argument
<application-desc main-class=".....">
<argument>user.home</argument>
..............
I am in the process of writing a cross platform Swing based application in which I want to utilize a file association which has been registered with the OS.
So iv got to the point where I can click on a file and my app loads, but what I need to know is how I can get my application to know where the file is that launched it and then query the contents.
Is there something further I have to do with the file association registration? Or can Java do this for me?
I'm not positive, but I'd expect that the name of the file you're processing by file click will end up in the arguments to your main() method. Have you tried/checked that?
If this is on Windows (you didn't specify):
In the registry wherever you specified your application path for the file type registered to it, add to "%1". This is a special parameter Windows will fill in with the path of the file that was clicked. So your registry entry would look something like c:\path\to\app.exe "%1"
One way to do this is to have the file association run your Java app via a script or batch file, and have the batch file pass the pathname of the file as a command line argument, environment variable or Java property.
Extensions can be linked to applications, you can setup the registry keys during installation. Which keys you need is documented here:
http://support.microsoft.com/?scid=kb%3Ben-us%3B185453&x=6&y=11
From java you can't access the windows registry in a direct way.
Using Runtime you could do something like that
http://www.rgagnon.com/javadetails/java-0480.html
There're two commands on Windows that can help, assoc and ftype, so that you needn't do the dirty laundry to manipulate registry. Invoke the commands using, say, java.lang.Process. http://www.rgagnon.com/javadetails/java-0592.html
I want to change the logging level depending if I'm debbugging or not, but I can't find a code snippet to check if the application is running in debug mode.
I'm using eclipse to debug the application, so if the solution only works within Eclipse it will be fine.
Found the answer on how-to-find-out-if-debug-mode-is-enabled
boolean isDebug = java.lang.management.ManagementFactory.getRuntimeMXBean().
getInputArguments().toString().contains("-agentlib:jdwp");
This will check if the Java Debug Wire Protocol agent is used.
You could modify the Debug Configuration. For example add a special VM argument only in the Debug Configuration. You can use System.getProperties() to read the supplied arguments.
Even better, modify the configurations (Run and Debug) to load a different logging configuration file. It isn't good if you need to write code to determine the logging level. This should only be a matter of configuration.
There is not an officially sanctioned way to reliably determine if any given JVM is in debug mode from inside the JVM itself, and relying on artifacts will just break your code some time in the future.
You will therefore need to introduce a methology yourself. Suggestions:
A system property.
An environment variable (shell variable like $HOME or %HOME%)
Ask the JVM about the physical location of a given resource - http://www.exampledepot.com/egs/java.lang/ClassOrigin.html - and based on it, make your decision (does the path contain the word "debug"? is it inside a jar or an unpacked class file? etc).
JNDI
The existance or content of a particular resource.
Have you tried add a vm argument in the eclipse run config?
Pass this as a VM Argument
-Ddebug=true
then you can do Boolean.getBoolean("debug") to check this.
If you are setting the debug level from your own program, may be a line like:
public static final boolean DEBUG_MODE = System.getProperty("java.vm.info", "").contains("sharing");
would do the trick.
Just tested it in eclipse3.5:
package test;
public class Test
{
/**
* #param args
*/
public static void main(String[] args)
{
System.out.println(System.getProperty("java.vm.info", ""));
}
}
will display:
mixed mode, sharing
if launched without debug
mixed mode
if executed with debug launcher
Joachim Sauer comments:
This is highly system depending.
I assume the "sharing" indicates that cross-VM class-sharing is active.
This is a very new feature and is only available on some platforms.
Furthermore there can be many possible reasons to en- or disable it, so I wouldn't use this for debug-mode detection.
(Note: I tested it with the latest jdk1.6b14. I leave this as a CW answer.)
Have a look here:
http://wiki.eclipse.org/FAQ_How_do_I_use_the_platform_debug_tracing_facility%3F
Moreover, I think you can't know if your app is run in debug mode. The only thing you can do is to pass an argument to your JVM when you debug.
Manu
If using socket (e.g. 9999) you can call netstat to check if connection was established:
Process p = new ProcessBuilder("netstat", "-n").start();
String stdout = IOUtils.toString(p.getInputStream(), Charset.defaultCharset());
Then scan in stdout for 127.0.0.1:9999.*ESTABLISHED
Third party vendors using our software as a component view Windows Logo Certification as an important selection criteria. 90% of the requirements are easy to adhere to given the flexibility in deploying Java programs. Some immediate difficulties present themselves:
Tagging jar files with resource strings for versioning information.
Moving From properties files to .INI files
Short Path Name / Long Path Name / UNC isn't well support by the libraries
Look and feel requirements
These will require some serious recoding to address. I may be interpreting the specifications too closely. I found one decent example of an application that obtained Windows 2000 certification. The look and feel in this instance only refers to any visible installer that we present. Even the specifications themselves imply things in the descriptions that are not really covered in the title of the requirement.
1.5 The application should not read from or write to Win.ini, System.ini, Autoexec.bat or Config.sys
excerpt:
If your application uses information that you do not want to put in the registry, create a private initialization file and place it in the directory with the application's executable files. You can easily manage the installation of a private .ini file, as well as add or remove information from existing .ini files, by using Windows Installer to install your application.
Any feedback would be appreciated.
For the look and feel, call this at the beggining of your main() function:
log.info("Setting java look and feel");
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
log.warn("Could not set system look and feel", e);
}
// Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
Please note that the example of an INI file should not be taken as a mandate. What you call the "title" is really the requirement itself. The reason for this is that the specifications are intended (amongst others) to prevent application installations from interfering with each other. Moving to private configurations (whether in the file system or in the registry) supports this.
In fact, the current suggestion is no longer INI files, but the registry for small parts of the configuration, and XML files in %APPDATA% if you've got a lot.