My program saves encrypted product key data to the computer with the java.util.Preferences class (system preferences, not user). The problem is, on both Windows and Linux (haven't tested on OSX, but it's probably the same), if I don't run the program with sudo or with Administrator privileges, it emits an exception or warning whenever it tries to read or save the data.
Obviously requiring the user to run the program with Admin privileges would be impractical. Optimally, I'd like the operating system to ask the user for permission.
This is quite silly, and removes half the purpose of Preferences. How can this be fixed?
Here's a summary what I need: I need my program to ask for permission from the operating system to save system settings.
Here is the error information
Here's the error when the when I try to read a node (because the node doesn't exist):
Mar 18, 2011 9:41:15 AM java.util.prefs.WindowsPreferences <init>
WARNING: Could not create windows registry node Software\JavaSoft\Prefs\myapp at root 0x80000002. Windows RegCreateKeyEx(...) returned error code 5.
Mar 18, 2011 9:41:15 AM java.util.prefs.WindowsPreferences WindowsRegOpenKey1
WARNING: Trying to recreate Windows registry node Software\JavaSoft\Prefs\myapp at root 0x80000002.
Mar 18, 2011 9:41:15 AM java.util.prefs.WindowsPreferences openKey
WARNING: Could not open windows registry node Software\JavaSoft\Prefs\myapp at root 0x80000002. Windows RegOpenKey(...) returned error code 2.
Mar 18, 2011 9:41:15 AM java.util.prefs.WindowsPreferences WindowsRegOpenKey1
WARNING: Trying to recreate Windows registry node Software\JavaSoft\Prefs\myapp\subpackage at root 0x80000002.
Mar 18, 2011 9:41:15 AM java.util.prefs.WindowsPreferences openKey
WARNING: Could not open windows registry node Software\JavaSoft\Prefs\myapp\subpackage at root 0x80000002. Windows RegOpenKey(...) returned error code 2.
And this is what happens when I try to write to a node:
Mar 18, 2011 9:43:11 AM java.util.prefs.WindowsPreferences WindowsRegOpenKey1
WARNING: Trying to recreate Windows registry node Software\JavaSoft\Prefs\myapp\subpackage at root 0x80000002.
Mar 18, 2011 9:43:11 AM java.util.prefs.WindowsPreferences openKey
WARNING: Could not open windows registry node Software\JavaSoft\Prefs\myapp\subpackage at root 0x80000002. Windows RegOpenKey(...) returned error code 2.
Unfortunately most of the answers you got here are wrong ... at least slightly. In the sense that the symptom is being treated, not the cause.
Let's recap. Java Preferences has two "trees": the user tree and the system tree. You can write your own backend to Java Preferences (called a backing store) but few developers do, so you end up with the JDK's default backing store. On a Windows platform this means the Win Registry, more specifically:
The user tree is written into HKEY_CURRENT_USER\Software\JavaSoft\Prefs (the OS user always has write access here)
The system tree is written into HKEY_LOCAL_MACHINE\Software\JavaSoft\Prefs (only an OS user with admin privs has write access here)
In summary: As long as your code doesn't attempt to use the system tree, you should be fine and shouldn't need to mess with assigning privileges at the OS level. The system tree is meant for "all users on the host" and the user tree is meant for the specific logged-in user. In your case I'm confident you can suffice with the user tree, so that is really your solution. Don't go messing with privileges, running as Administrator, and what not.
.... but there's more. Suppose your code deliberately doesn't touch the Java Preferences system tree, as instructed. You'll then still see this warning on Windows:
WARNING [java.util.prefs]: Could not open/create prefs root node Software\JavaSoft\Prefs at root 0x80000002. Windows RegCreateKeyEx(...) returned error code 5.
So what is going on? Did I give you the wrong advice ? Not really. Stay with me.
Diving into the JDK source code you'll see that 0x80000002 means HKLM, i.e. the place in the Win Registry that shouldn't be touched. Your code never references the system tree and yet you still see this warning !?? (At this point you must be ripping all your hair out ... as I did)
Well, this is one of the rare occasions where there really is a JDK bug. You can read more about it in this answer by me which I encourage you to read if you are interested in why subtle bugs can go undetected in the JDK for years. The bug has existed ever since JDK 1.4 but has only recently been fixed and not yet backported to JDK 8 (update: the fix has now been backported to version 8u192 onwards of the JDK)
Best advice
Make sure your code only references the user tree, not the system tree. It is only fair that the OS requires all kinds of privs for you to write to a system-wide location. If you really need to write into such a location then there really is no other solution than assigning privs, executing as Administrator or what not.
Ignore the warning. It'll go away once you are on Java 8 update 192 or later. The warning can be safely ignored.
Alternatively you can try to programmatically silence the warning. It comes from the JDK's Platform Logger, so something like this should work, albeit I haven't tried it myself:
sun.util.logging.PlatformLogger platformLogger = PlatformLogger.getLogger("java.util.prefs");
platformLogger.setLevel(PlatformLogger.Level.OFF);
This link is work for me:
Resolving the problem
The work around is to login as the administrator and create the key HKEY_LOCAL_MACHINE\Software\JavaSoft\Prefs
It is possible to change the access rights of the registry entries. If you allow full access rights to
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs to everybody, everybody will see the same set of preferences and everybody will be able to change them globally. I am aware that this is not a solution for software that is installed by customers, but it might be of use for somebody.
Modifying the answer based on feedback.
This solution is probably overkill but ...
I suggest you change your store to write to a file instead of the registry (example)
A lot of java-based products ship with their own JVM. They do it so that they can run with a custom policy file (which would be needed in your case to write to a common location) and save on support issues (like outdated/untested JVM's being used)
Especially with Windows 7, the JVM has not by default the permission to write into the Windows registry where the backing store for java.util.prefs.preferences is located under MS-Windows.
When executing either the ReverseXSL transformer, or even the Regex tester program, one can get errors like: Could not open/create prefs root node Software\JavaSoft\Prefs at root 0x80000002. Windows RegCreateKeyEx
This does prevent registering a license. It does not prevent the software to perform transformations in the free software mode.
Fixing the issue is simply a matter of granting the necessary permissions to the registry root key at stake.
Run regedit.exe as administrator (regedit.exe is located in the c:\Windows operating system root directory).
Go to key HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs. Right click to set permissions. Check a mark in the Full Control check box for the user(s) that need executing the reverseXSL software.
Just Run the application as administrator, or if using eclipse, run eclipse as administrator.
This has finally been patched, in January 2019, in Java SE Development Kit 8u202.
This is the Patch Set Update (PSU), as opposed to the Critical Patch Update (CPU), 8u201. The difference is explained here. (The page uses Java 7 as an example, but it gets the point across.)
The download can be found lower down on the "Java SE Development Kit 8" page. (https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
The Answer by peterh already elaborated on the background, but I was searching for a fix and found it!
Since you can't touch the PlatformLogger itself, you have to void its message:
// get rid of the bugged Preferences warning
PrintStream err = System.err;
System.setErr(new PrintStream(new OutputStream() {
public void write(int b) {}
}));
Preferences PREFS = Preferences.userNodeForPackage(Settings.class);
System.setErr(err);
This way the annoying Warning is gone without leaving any traces. Note that you only need to do this at the point where you are referencing the Preferences API for the first time in your program.
The fix is to run JMeter as Administrator, it will create the registry key for you, then you can restart JMeter as a normal user and you won't have the warning anymore.JMeter official site - changes
The solution for me was not obvious - it was to update my cryptography security jars from Oracle as it seems to be a key length restriction (I didn't believe it was related, until I tried it).
Download from Oracle website
The download contains instructions and explains:
Due to import control restrictions of some countries, the version of
the JCE policy files that are bundled in the Java Runtime Environment,
or JRE(TM), 8 environment allow "strong" but limited cryptography to be
used. This download bundle (the one including this README file)
provides "unlimited strength" policy files which contain no
restrictions on cryptographic strengths.
This apparently applies to Registry keys too
Go to your registry and create JavaSoft\Prefs\myapp under HKEY_LOCAL_MACHINE-->SOFTWARE
Create key name as Prefs and in that create a sub key as myapp, this will resolve the issue.
Related
I have a Java 10 application on Windows Server 2016 which is continually writing to a file using java.util.logging. In Windows File Explorer, the "Last modified" and "Size" columns do not update. Pressing [F5] does not update the details. DOS DIR gives the same incorrect answer. Right Click > Properties > Details gives an even different (and older) answer.
Only running DOS TYPE or opening/closing (without save) in Notepad on the file, seems to cause File Explorer and DOS DIR to update.
I assume the Java code is correct with respect to flush() as the same classes on Java 8 on Windows Server 2008 causes File Explorer to update. Also when running TYPE and Notepad I also see the timestamped records matching the system clock, but well after "Last Modified".
So I assume that there is something up with Windows Server 2016. Any ideas what to check?
So I assume that there is something up with Windows Server 2016. Any ideas what to check?
By default Windows is setup to work this way. From File timestamp not updating on 2008 but does on 2003:
On 2003, opening the log file folder in explorer, you can see the timestamp and files size change before your eyes each time the log is updated.
On 2008, most of the time, there is no change unless you interact in some other way...
[snip]
Yes, some of these attributes have been disabled in 2008.
If you want for example want to see/use “Last Accessed” time you need to enable the tracking of this attribute.
You can enable this by setting HKLM\System\CurrentControlSet\Control\FileSystem\NtfsDisableLastAccessUpdate to 0 (this value is REG_DWORD).
Please beware that his could impact disk IO performance on busy file servers !
So the behavior was change to improve performance.
From the Performance Tuning Web Servers:
The system-global switch NtfsDisableLastAccessUpdate (REG_DWORD) 1 is located under HKLM\System\CurrentControlSet\Control\FileSystem and is set by default to 1. This switch reduces disk I/O load and latencies by disabling date and time stamp updating for the last file or directory access. Clean installations of Windows Server 2016, Windows Server 2012 R2, Windows Server 2012, Windows Server 2008 R2, and Windows Server 2008 enable this setting by default, and you do not need to adjust it. Earlier versions of Windows did not set this key. If your server is running an earlier version of Windows, or it was upgraded to Windows Server 2016, Windows Server 2012 R2, Windows Server 2012, Windows Server 2008 R2, or Windows Server 2008, you should enable this setting.
It appears that this setting can still be used in Windows Server 2016.
I assume the Java code is correct with respect to flush() as the same classes on Java 8 on Windows Server 2008 causes File Explorer to update. Also when running TYPE and Notepad I also see the timestamped records matching the system clock, but well after "Last Modified".
Flush is not the same as sync. The FileHandler just performs a flush after each record is published. Windows is not setup to force a writing of the metadata to the file system. From File “Date modified” property are not updating while modifying a file without closing it.:
On 2008, "Last Modified" field on log files is not updated unless another
program attempts to open the file or the utility is stopped, even if F5 is pressed to
refresh the view.
Explorer gets is information from NTFS, by using a cmd prompt and "dir" we found that the NTFS metadata for the files is not updated until the handle to a file is closed.
Refreshing the information of a FOLDER is just going to go to the (memory resident) metadata cached by NTFS, but querying the file explicitly will force disk I/O to get the properties - this was a design change introduced in Vista to reduce unnecessary disk I/O to improve performance
There are some exceptions to this rule:
in some, but not all, cases a simple "dir filename" is enough to refresh the metadata
"special" folders may be treated differently, such as user profiles where we do not expect a large number of files and want to be able to rely on the file data presented
kernel filter drivers may change the behaviour as by design they "add, remove or
change functionality of other drivers"
As the workaround is for any process to open and close a handle to the log files, a tool was written to do exactly that, plus get the file information, using the following APIs:
CreateFile
GetFileInformationByHandle
CloseHandle
You might be able to attempt to open a FileInputStream using the file name that the FileHandler created.
Only running DOS TYPE or opening/closing (without save) in Notepad on the file, seems to cause File Explorer and DOS DIR to update.
The only universal method I've found for updating the metadata from an outside process is to select a file using the file explorer interactively:
explorer /select, c:\test\file.txt
Most likely this is very similar to what is happening in notepad.
I like your use of TYPE command. You can use that with the nul to ignore the output.
type filename.log > NUL
It is possible that running dir with metadata switches might force the update of metadata:
dir /A /R /Q filename.log > nul
I have a Java application that reads from the Preferences by using:
Preferences prefs = Preferences.userNodeForPackage(MyClass.class);
prefs.get((String)key, "");
On a fresh Windows 8 machine this fails with:
WARNING: Could not open/create prefs root node Software\JavaSoft\Prefs
at root 0x80000002. Windows RegCreateKeyEx(...) returned error code 5.
Error code 5 is access denied.
I can't find anything I'm doing wrong. Google and SO searches give old results relating only to Windows Vista/7 where one was wrongly using systemRoot (How can I write System preferences with Java? Can I invoke UAC?).
The error can be "cured" by creating HKLM/Software/JavaSoft/Prefs and setting permissions to HKLM/Software/JavaSoft as mentioned here Java: java.util.Preferences Failing. But this is not something I can require my users to do when they install the program.
So I'm looking for a better solution. My last ditch effort is to simply write to file but I'd like to avoid that. This also seems related I'm trying to use Java Prefences from XML WITHOUT using Windows registry, but I see a Registry-related message but it was down voted without an answer.
At current I suspect a Win8 JVM bug...
Questions
Does any one know of a solution that doesn't involve writing files?
Why does the same code work perfectly fine in Windows 7 but fails miserably in Windows 8?
I recently started noticing a same warning and thought it means that registry cannot be written. But upon closer inspection I noticed that all preferences where successfully updated in HKEY_CURRENT_USER anyways. So I got curious why I'm seeing this warning.
It turned out that the culprit is this static member variable: WindowsPreferences.systemRoot
Looks like Java tries to initialize WindowsPreferences.systemRoot just in case it is used later on by the program, and that initialization obviously fails if the program is not ran as administrator.
Since you're using Preferences.userNodeForPackage(), you will never need the systemRoot, therefore you can safely ignore that warning.
Of course, this is a horrible practice that Java tries to initialize systemRoot when it's not requested.
Update: I tested this problem in various Java versions and concluded that this bug was introduced in Java 1.7.0_21. It worked fine in Java 1.7.0_17 simply because the installer of that version would create the "Pref" folder in registry! Of course even in that version if you were to delete "Pref" from registry then it would stop working, so it was a silly solution on the part of Oracle to begin with. I will fill a bug report.
Update 2: The warning message is not a bug. It seem to be the intended behavior: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6809488
I need to create a persistent storage in my Java app so all users can access it. So I was studying about java.util.prefs.Preferences and using systemRoot() works fine to me on Windows, saving data at Register.
But I'm really facing some problems on Linux (Ubuntu). I want to use a directory that other of our apps already uses: /usr/share/.
So, I'm trying to redirect systemRoot default directory to /usr/share at runtime. Here's my code:
System.setProperty("java -Djava.util.prefs.systemRoot", "/usr/share/myfolder");
Preferences pref = Preferences.systemRoot().node("/usr/share/myfolder");
According to this site, I have to create .systemPrefs folder before execute this command line and its implicit that systemRoot() will use it.
When I execute my program, I get the following WARNING:
java.util.prefs.FileSystemPreferences syncWorld
WARNING Couldn't flush system prefs: java.util.prefs.BackingStoreException: /etc/.java/.systemPrefs/usr create failed.
So I'm assuming that System.setProperty isn't working. Any suggestion?
Thanks in advance!
This is a really pesky issue Java running on *nix based servers.
I was able to solve it by using the following vm args:
-Djava.util.prefs.userRoot=/opt/apache-tomcat-7.0.50/uprefs -Djava.util.prefs.systemRoot=/opt/apache-tomcat-7.0.50/sprefs
One important note though on the systemRoot path is to create a sub-folder within it named .systemPrefs or it will not work.
Also, don't forget to chown -R these directories to the user running the java application (in my case it was tomcat).
Bimalesh suggested that instead of
System.setProperty("java -Djava.util.prefs.systemRoot", "/usr/share/myfolder"), that you say
System.setProperty("-Djava.util.prefs.systemRoot", "/usr/share/myfolder").
But the name of the property that you are trying to set is java.util.prefs.systemRoot, and not -Djava.util.prefs.systemRoot, so you should do
System.setProperty("java.util.prefs.systemRoot", "/usr/share/myfolder");
If that doesn't work, try adding the "-D" switch to the command line that starts your program. That is where
java -D... should go. The command would start with
java -Djava.util.prefs.systemRoot=/usr/share/myfolder
In a Linux system, the System root preference node will be under /etc. This is due to history, and is a standard that is regulated by the Linux Standard Base. Any non-system preferences can go in other locations, but it is a violation of the design of the operating system to have system preference go elsewhere.
Odds are your define is ineffective in a Linux system because it fails to start at /etc. Apparently something in the Java code defers to the specification of the operating system over your decision to re-base the preference root.
Typically such files are protected against modification by not being world (or even most user) writeable. This means that for users to have access to Preferences, they should go under
Preferences.userRoot()
Which will place them in hidden directories just off their home directory (where they will have modification privileges).
If your want any user to read any other user's preferences (the description sounds like you might) then you will need to have an installer that runs as a sufficiently authorized user (typically root) to make the required directory under /etc and change it's permissions to be world writeable.
Typically files under /etc are not world writable as users changing other's user's setting is then possible, and considered a type of security breach of the user's expected environment. For example, a careless employee (or a disgruntled one) could wipe out all other user's preferences in one stroke.
I'm developing a new java web start capability for an existing site. All is going well except that one of my test launches, on one of machines has become mysteriously contaminated in a way that is so strange, I'm grasping at straws to explain.
Before the details, some general facts. The script works everywhere else. It fails from this one machine, only when logged in as one particular user. It fails if launched directly from the web, or if the local .jnlp file is launched directly from javaws.
The symptom when it fails is javaws reports "error at line 145", which is itself inexplicable since the jnlp file has only about 15 lines. The smoking gun is that if I use javaws -verbose, I see the following text as the text of the file that failed to parse.
<!--
# Copyright (C) 2009, CyberTAN Corporation
# All Rights Reserved.
#
# THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY
...
plus some suspicious looking javascript. I've determined that this text is what
my router presents when someone connected to the guest wireless network tries to
access the web for the first time.
So my working theory is that once during the testing phase, I booted up my netbook,
accidentally was connected to the guest network instead of the regular network,
managed to access the web jnlp file as the first network access, and got this
page in response instead of the expected.
My question is, where (and why) is this text persisting in the system? I've I ran a search
everywhere, including hidden files, and can't find this text residing anywhere. I've also
flushed javaws caches using the -viewer option.
Do you still see the App in the Java Cache Viewer GUI (javaws -viewer)?
Try to delete the cache at C:\Documents and Settings\[account]\Local Settings\Application Data\Sun\Java\Deployment\cache (or similar, assuming you're using Windows)...
Here's some additional info: http://www.ngs.ac.uk/clearwebstartcache
Have you updated the URL to your JNLP? Here's some discussion going in this direction: https://forums.oracle.com/forums/thread.jspa?messageID=9804718
Personally, I wouldn't bother too much about the how and why - WebStart can be weird at times. Just ix the problem on your "one machine" and try to keep your productive JNLP as stable as possible.
I have a SWT Java app that runs on Windows XP / Vista / 7 and Mac OS X. I'm currently saving a config file to:
System.getProperty("user.home") + filename
With the changes in security in Windows Vista and Windows 7 this doesn't seem to be the best place to save it anymore.
This file saves information such as registration key info and it is annoying for my users if the file can't be saved or is deleted.
Is there a better path I should use?
Also, what's the preferred path for per user application data on Mac OS X?
macos path for application data to be kept is "~/Library/Application Support" as per Apple documentation
What changes in security? I understand they prohibited writing in Program Files, I didn't know they forbid to write in user home.
It would be a serious compatibility break, I have a number of applications writing there, either directly a file, or in a folder ("hidden" at the Unix mode, ie. prefixed with a dot).
Now, it seems to be more "friendly" to write in Application Data folder as do a number of other applications (but rarely cross-platform applications which seem to use the previous solution...) but the exact location seems hard to find in Java, and would need a platform detection to do something else on other platforms.
An alternative seems to be to use the Preferences API, ie. java.util.prefs.Preferences.
Sun itself, with its java control panel, had the very same problem (bug 6487334): their control panel, running at different integrity level, could not both read/write to their deployment directories.
They moved it to c:\users\<username>\appdata\local, but had to not rely on System.getProperty("user.home") because to this day, it uses a registry KEY that can be set to incorrect value if windows is "tweaked": bug 6519127
So the question How to get local application data folder in Java?, using HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\* is the right place to start looking for read/write access for your settings.
You can read it with, for instance, SWT Win32 Extension project.
The interest to keep your data within the user's homedir is that they will be part of the user's profile which can be a roaming profile, saved at logoff and restored at logon (used quite often on corporation's workstations)