Friday October 21, 2005
java.io.Console is finally here!
One of the most popular feature requests for J2SETM
in recent times has been the
request to improve console support and provide a way to enter passwords with echo
disabled. Developers know this feature
4050435 as
it has been skulking in the
Top 25 RFEs list for some time.
The good news is that the feature has made it into
Mustang thanks to Xueming Shen.
It went into b57 and should show up be on the
download site later today. The feature adds
java.io.Console which provides methods to read lines and passwords from the
console. It also provides useful methods to write formatted strings to the console too.
Here's a little taster that prompts user to enter a password that is at least
8 characters in length. The password is not echoed to the console as it
is entered.
static final int MIN_PASSWORD_LENGTH = 8;
char[] password;
do {
password = System.console().readPassword(
"Enter password (minimum of %d characters): ", MIN_PASSWORD_LENGTH);
} while (password.length < MIN_PASSWORD_LENGTH);
|
System.console() is used to obtain the unique Console for the Java virtual machine. There may not be a console of course - it depends on the platform, and also on how the Java virtual machine was started. If there isn't a console then the console() method returns null (the above code fragment doesn't check for this).
The readPassword method writes the prompt and reads the password. The prompt is provided as a format string and an argument list. If you've used the formatted printing support that was added in J2SE 5.0 then you'll recognize this.
Another thing about this code fragment is that it leaves you with a password in a character array. As with anything sensitive you don't want to have this in memory for a long time so it's good to zero the array as soon as you can.
So if you develop applications that need to access a character based console then you should find java.io.Console very useful (and very simple to use).
Posted at 10:17AM Oct 21, 2005 by alanb in Archive | Comments[39]
Friday October 14, 2005
jstack
One of the useful troubleshooting utilities in J2SETM 5.0 is jstack. It prints the stack traces of all java threads for a given process or core dump. The -m option will print a mixed-mode stack so that you can see native frames in addition to the java frames. jstack was originally created for troubleshooting problems involving hangs and crashes but developers have found it a useful utility to look at running applications too.
jstack isn't the only way to obtain a thread dump of a running application. Developers have long been accustomed to using Ctrl-\ (or Ctrl-Break if you are on Windows) to get a thread dump of an application that is running interactively. An alternative to the key sequence on Solaris (or Linux) is to send a QUIT signal to the target process. In that case the target processs prints a thread dump to its standard output (which can be pain if you don't know where the log file is).
If you are lucky to be on Solaris 10, then yet another way to obtain a stack trace is using the the pstack utility. This has been updated in Solaris 10 so that it prints java method names for interpreted, compiled and inlined java methods. pstack prints a mixed-mode stack and the output is similar to jstack -m.
Mustang (Java SE 6.0) brings more improvements. For starters the default mode for jstack is to work a bit like a remote Ctrl-\. This means that the output of the thread dump has changed a bit but there is more information on deadlocks and JNI Global References in additional to the thread stacks. If the VM is hung then a thread dump can still be forced using the -F option.
The second improvement is that jstack is included on Windows. It doesn't have all the features yet of the jstack utility on Solaris but it does solve a long standing requirement from developers to get a thread dump of an applications that run in the background as a Windows Service.
The third improvement is the "-l" option to print information about java.util.concurrent.locks. More specifically, it instructs the utility to look for ownable synchronizers in the heap. This should be useful for applications that make use of the concurrency APIs added in J2SE 5.0. Without the "-l" option the thread dump only includes information on monitors. One word of warning though, this option can be expensive if the heap is large.
Posted at 10:00AM Oct 14, 2005 by alanb in Archive | Comments[13]
Monday October 03, 2005
One password to rule them all!
A few weeks ago I talked about how easy it is to get started with jconsole. The focus of that discussion was local monitoring and management where jconsole connects to applications running as the same user on the same machine. It is a simple scenario with simple configuration and jconsole doesn't need to prompt for username and password.
Now let us move onto the more complicated (and arguably more realistic) scenario where an application is deployed over a number of machines. In these cases the configuration of the JMX agent gets more complicated as it involves setting up SSL, a password file, and choosing a port number for the agent. This is all described on the Monitoring and Management with JMX page. One bugaboo with all this is that the password and access files create yet another place for user administration and yet another password to remember. If the application environment is distributed across the globe then it means sharing files in a secure manner or maybe a password file per machine. SSL client certificates provide a better alternative but in many environments they are a missing piece in the overall security infrastructure. Assuming you aren't using SSL client certs then another alternative to password authentication is LDAP. In many companies there is already directory server infrastructure and many of your applications may be using LDAP already. So today I want to talk about configuring the JMX agent to use LDAP instead of the file-based authentication.
Let's start by talking about the
JMXAuthenticator implementation in the JMX agent. It is based on
Java Authentication and Authorization Service
(JAAS). Authentication is performed by passing the user credentials to a JAAS
LoginModule. By default it uses a LoginModule that authenticates using the
password and access files. An alternative LoginModule (and hence an alternative
authentication mechanism), is specified using the
com.sun.management.jmxremote.login.config property. The property is set to the name
of a JAAS login configuration entry. For LDAP that means we need to set it to the entry
name for an LDAP-based LoginModule.
J2SETM 5.0 didn't ship with an LDAP based LoginModule
but there is one in a Mustang (Java SE 6.0)
thanks to Vincent Ryan. The LoginModule is
com.sun.security.auth.module.LdapLoginModule.
To use it we need to create a JAAS configuration entry. I've created the
configuration file ldap.config and configured the entry to work within Sun. Here's
how it looks:
SunConfig {
com.sun.security.auth.module.LdapLoginModule REQUIRED
userProvider="ldap://sun-ds/ou=people,dc=sun,dc=com"
userFilter="(&(uid={USERNAME})(objectClass=inetOrgPerson))"
authzIdentity=monitorRole
useSSL=false;
};
|
If you aren't familar with the syntax of the configuration file then the Configuration class details the information needed for configuration, and there are examples available.
The specification for the LoginModule details all the options. In this example
I've named the entry "SunConfig". The flag "REQUIRED" means that authentication is required to succeed.
The other items are module options.
The userProvider option identifies the LDAP directory. It's a
LDAP URL (or a list of URLs). The
URL identifies the LDAP server to use and the position in the directory tree where
user entries are located.
The userFilter module option is another piece of LDAP configuration. It specifies
the search filter to use to locate a user entry in the LDAP directory.
The token "{USERNAME}" is replaced with the username
before the filter is used to search the directory. If all this looks like
gobbledegook then have a chat with your LDAP administrator to get the magic
settings for your environment.
The authzIdentity takes a bit of explaining and we'll come back to it shortly. The final module option in this confguration is useSSL which indictaes if the connection to the LDAP server uses SSL or not. The default is true but I've tried to keep this example simple and so it is disabled.
So now we have a JAAS configuration entry for the LDAP LoginModule. The next piece is to configure two system properties:
Here's a sample command line with all the properties set:
java -Dcom.sun.management.jmxremote.port=5000
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.login.config=SunConfig
-Djava.security.auth.login.config=ldap.config
-jar MyApplication.jar
|
I've snuck in two other properties here. The com.sun.management.jmxremote.port property configures the TCP port number, and com.sun.management.jmxremote.ssl specifies if SSL is enabled or disabled (I've chosen to disable it to keep the configuration simple but you'll want to enable it in production environments).
At this point we have our configuration so we start the application. The JMX agent starts with the application so we now try to connect using jconsole. For example I'll assume the application is on "myserver" and we're "John Doe" (username "jdoe"). To connect we start jconsole, switch to the Remote tab of the Connection Dialog, and enter the connection details:
When we press the Connect button then jconsole will connect to the JMX agent, and the JMX agent will attempt to authenticate "jdoe".
When you initially setup your configuration it can be useful to add the debug opton to the JAAS configuration entry. If you add debug=true then the LdapLoginModule will print trace information to standard output. Here's an example for when jdoe does a successful login:
[LdapLoginModule] search-first mode; SSL disabled [LdapLoginModule] user provider: ldap://sun-ds/ou=people,dc=sun,dc=com [LdapLoginModule] searching for entry belonging to user: jdoe [LdapLoginModule] found entry: cn=John Doe,ou=people,dc=sun,dc=com [LdapLoginModule] attempting to authenticate user: jdoe [LdapLoginModule] authentication succeeded [LdapLoginModule] added X500Principal "CN=John Doe,OU=people, DC=sun, DC=com" to Subject [LdapLoginModule] added UserPrincipal "jdoe" to Subject [LdapLoginModule] added UserPrincipal "monitorRole" to Subject |
This log is saying that the LoginModule searched for the user entry "jdoe". It was found and then the password was authenticated.
If the password was entered incorrectly then you'll see something like this:
[LdapLoginModule] search-first mode; SSL disabled [LdapLoginModule] user provider: ldap://sun-ds/ou=people,dc=sun,dc=com [LdapLoginModule] searching for entry belonging to user: jdoe [LdapLoginModule] found entry: cn=John Doe,ou=people,dc=sun,dc=com [LdapLoginModule] attempting to authenticate user: jdoe [LdapLoginModule] authentication failed [LdapLoginModule] aborted authentication |
Now let's get back to the authzIdentity module option that I skipped over earilier.
In the example I used authzIdentity=monitorRole which means that all authenticated
users get read-only access to the managed VM. In technical terms the
Principle named monitorRole is added to each authenticated user
(or
Subject). The name monitorRole corresponds to an entry in the
JMX access file. The JMX access file is usually
${JRE_HOME}/lib/management/jmxremote.access but you can use the
com.sun.management.jmxremote.access.file property to specify an alternative file
if you wish. By default the file contains two roles, namely monitorRole with
readonly access, and controlRole with readwrite access.
In some environments it might make sense to allow all users access to the managed
VM but more realistically there will only be a small number of technical
staff that will be monitoring and managing the applications. In that case
we need to update the configuration as follows:
So, assuming we want our "John Doe" to have read-write access then we create an
entry in the JMX access file as follows:
jdoe readwrite |
So what does this mean? When John Doe connects he will be authenticated using his normal LDAP password. Once authenticated he has readwrite access to the managed application (by virtue of the entry in the access file).
In summary, I think you will agree that the ability for the JMX agent to authenticate users using LDAP is very nice. It eliminates the need to manage additional password files and for those managing applications it means there is only one password to remember. There is some configuration required and specific users still need to be setup in the access file but overall it is a whole lot better than having to mantain password files.
Posted at 12:07PM Oct 03, 2005 by alanb in Archive | Comments[9]