This tutorial presents two sample applications to demonstrate the use of the Java GSS-API. This API permits secure exchanges of messages between communicating applications. Here are the sample client and server applications you'll need for this tutorial:
Contents:
SampleServer
ProgramsAs with all tutorials in this series, the underlying technology used to support authentication and secure communication for the applications in this tutorial is Kerberos. See Kerberos Requirements.
The applications for this tutorial are named
SampleClient
and SampleServer
.
Each is invoked by executing the Login utility supplied with
this tutorial and passing it as arguments the name of the
application (SampleClient
or
SampleServer
), followed by the arguments needed by
the application. The Login utility uses a JAAS LoginContext to
authenticate the user using Kerberos. Finally, the Login utility
invokes the main
method of the application class, in
our case either SampleClient
or
SampleServer
, and passes the application its
arguments.
Here is a summary of execution of the
SampleClient
and SampleServer
applications:
SampleServer
application by running the
Login utility and passing it as arguments the name
"SampleServer
" followed by the arguments for the
SampleServer
program. The Login utility prompts you
for the password for the principal that SampleServer
should run as. (See Kerberos User and
Service Principal Names.) After authentication is complete,
SampleServer
is run it:
SampleClient
application (possibly on a
different machine), by running the Login utility and passing it
as arguments the name "SampleClient
" followed by the
arguments for the SampleClient
program. The Login
utility prompts you for your Kerberos name and password. After
authentication is complete, SampleClient
is run. It
SampleServer
. (See Kerberos User and Service Principal Names.), (2)
the name of the host (machine) on which SampleServer
is running, and (3) the port number on which
SampleServer
listens for client connections.SampleServer
, using the host and port it was passed
as arguments.SampleServer
and both applications initialize a
DataInputStream and a DataOutputStream from the socket input and
output streams, to be used for future data exchanges.SampleClient
and SampleServer
each
instantiate a GSSContext and establish a shared context that will
enable subsequent secure data exchanges.SampleClient
and SampleServer
can
now securely exchange messages.SampleClient
and SampleServer
are done exchanging messages, they perform clean-up
operations.SampleClient
and
SampleServer
Code" section of the Use of Java GSS-API for Secure Message
Exchanges Without JAAS Programming tutorial for a full
discussion of the code used in this tutorial.
Since the underlying authentication and secure communication technology used by this tutorial is Kerberos V5, we use Kerberos-style principal names wherever a user or service is called for.
For example, when you run SampleClient
you are
asked to provide your user name. Your Kerberos-style user
name is simply the user name you were assigned for Kerberos
authentication. It consists of a base user name (like "mjones")
followed by an "@" and your realm (like
"mjones@KRBNT-OPERATIONS.EXAMPLE.COM").
A server program like SampleServer
is typically
considered to offer a "service" and to be run on behalf of a
particular "service principal." A service principal name
for SampleServer
is needed in several places:
SampleServer
you must log in as the
appropriate service principal. The login configuration file for
this tutorial actually specifies the service principal name (as
an option to the Krb5LoginModule), so the JAAS authentication
(done by the Login utility) just asks you to specify the password
for that service principal. If you specify the correct password,
the authentication is successful, a Subject is created containing
a Principal with the service principal name, and that Subject is
associated with a new access control context. The
subsequently-executed code (the SampleServer
code)
is considered to be executed on behalf of the specified
principal.SampleClient
, one of the arguments
is the service principal name. This is needed so
SampleClient
can initiate establishment of a
security context with the appropriate service.Throughout this document, and in the accompanying login configuration file and policy files,
service_principal@your_realmis used as a placeholder to be replaced by the actual name to be used in your environment. Any Kerberos principal can actually be used for the service principal name. So for the purposes of trying out this tutorial, you could use your user name as both the client user name and the service principal name.
In a production environment, system administrators typically like servers to be run as specific principals only and may assign a particular name to be used. Often the Kerberos-style service principal name assigned is of the form
service_name/machine_name@realm;
For example, an nfs service run on a machine named "raven" in the realm named "KRBNT-OPERATIONS.EXAMPLE.COM" could have the service principal name
nfs/raven@KRBNT-OPERATIONS.EXAMPLE.COM
Such multi-component names are not required, however.
Single-component names, just like those of user principals, can
be used. For example, an installation might use the same ftp
service principal ftp@realm
for all ftp servers in
that realm, while another installation might have different ftp
principals for different ftp servers, such as
ftp/host1@realm
and ftp/host2@realm
on
machines host1
and host2
,
respectively.
If the realm of a user or service principal name is the
default realm (see Kerberos
Requirements), you can leave off the realm when you are
logging into Kerberos (that is, when you are prompted for your
username). Thus, for example, if your user name is
"mjones@KRBNT-OPERATIONS.EXAMPLE.COM", and you run
SampleClient
, when it requests your user name you
could just specify "mjones", leaving off the realm. The name is
interpreted in the context of being a Kerberos principal name and
the default realm is appended, as needed.
You can also leave off the realm if a principal name will be
converted to a GSSName by a GSSManager createName
method. For example, when you run SampleClient
, one
of the arguments is the server service principal name. You can
specify the name without including the realm, because
SampleClient
passes the name to such a
createName
method, which appends the default realm
as needed.
It is recommended that you always include realms when principal names are used in login configuration files and policy files, because the behavior of the parsers for such files may be implementation-dependent; they may or may not append the default realm before such names are utilized and subsequent actions may fail if there is no realm in the name.
Whenever JAAS is used, a login configuration is required to
specify the desired authentication technology. (See JAAS Login Configuration File for more
information about what a login configuration file is.) Both
SampleClient
and SampleServer
can use
the same login configuration file, if that file contains two
entries, one entry for the client side and one for the server
side.
The csLogin.conf login configuration file used for this tutorial is the following:
SampleClient { com.sun.security.auth.module.Krb5LoginModule required; }; SampleServer { com.sun.security.auth.module.Krb5LoginModule required storeKey=true principal="service_principal@your_realm"; };
Note that the name for each entry matches the respective class
names for our two top-level applications,
SampleClient
and SampleServer
. Recall
that this is also the name that is passed to the Login utility
that performs JAAS operations for the application. That utility
expects the name of the entry to be looked up in your login
configuration file to be the same as the name it is passed.
Both entries specify that Sun's Kerberos V5 LoginModule must
be used to successfully authenticate the user. The
Krb5LoginModule succeeds only if the attempt to log in to the
Kerberos KDC as a specified entity is successful. In the case of
SampleClient
, the user will be prompted for their
name and password. In the case of SampleServer
, a
name is already supplied in this login configuration file (the
specified principal, as described below) and the user running
SampleServer
is just asked for the password for the
entity specified by that name. They must specify the correct
password in order for authentication to succeed.
The SampleServer
entry
storeKey=true
indicates that a secret key
should be calculated from the password provided during login and
it should be stored in the private credentials of the Subject
created as a result of login. This key is subsequently utilized
during mutual authentication when establishing a security context
between SampleClient
and
SampleServer
.
The Krb5LoginModule has a principal
option
that can be used to specify that only the specified principal
(entity/user) should be logged in for the given program. Here,
the SampleClient
entry does not specify a principal
(although it could, if desired), so the user is prompted for a
user name and password and anyone with a valid user name and
password can run SampleClient
.
SampleServer
, on the other hand, indicates a
particular principal because system administrators usually like
servers to be run as specific principals only. In this case, the
user running SampleServer
is prompted for that
principal's password and must supply the correct one in order for
authentication to succeed.
Note that you must replace "service_principal@your_realm" with
the name of the service principal that represents
SampleServer
. (See Kerberos
User and Service Principal Names.)
For information about all the possible options that can be passed to Krb5LoginModule, see the Krb5LoginModule documentation.
The policy file used when running SampleClient
is
client.policy, and the policy file
used when running SampleServer
is server.policy. Their contents are described
below.
A number of permissions are required by the classes in
Login.java
(Login and MyAction). As recommended in
the previous tutorial on the use
of Login, we create a Login.jar
JAR file containing
the Login.class
and MyAction.class
files and in the client.policy
policy file we grant
Login.jar AllPermission
:
grant codebase "file:./Login.jar" { permission java.security.AllPermission; };
SampleClient
The SampleClient
code does two types of
operations for which permissions are required. It
SampleServer
application.SampleServer
.The permission required to open a socket connection is
permission java.net.SocketPermission "*", "connect";
You may replace the "*" with the hostname or IP address of the
machine that SampleServer
will be running on.
The permission(s) required to initiate establishment of a
security context will depend on the underlying mechanism. This
tutorial uses Kerberos as the underlying mechanism, and for that
two javax.security.auth.kerberos.ServicePermission
s
are required. A ServicePermission contains a service principal
name and an action (or list of actions). To initiate
establishment of a security context, you need two
ServicePermissions with action "initiate", whose names
specify:
SampleServer
. (See Kerberos
User and Service Principal Names.) Granting this permission
allows you to interact with the service,
SampleServer
, using Kerberos.We want to grant the permissions to a specific authenticated
user executing SampleClient
, so we specify both the
SampleClient
code location (in
SampleClient.jar
) and a Principal designation
indicating the user name and realm for the user (you, the person
who will run SampleClient
). (See How Do You Make Principal-Based
Policy File Statements? in the second tutorial of this series
for information on policy file grant
statements that
include Principal designations.)
Here is the basic form for the grant
statement:
grant CodeBase "file:./SampleClient.jar", Principal javax.security.auth.kerberos.KerberosPrincipal "your_user_name@your_realm" { permission java.net.SocketPermission "*", "connect"; permission javax.security.auth.kerberos.ServicePermission "krbtgt/your_realm@your_realm", "initiate"; permission javax.security.auth.kerberos.ServicePermission "service_principal@your_realm", "initiate"; };
You must substitute your Kerberos user name (complete with "@"
and realm) for "your_user_name@your_realm
". For
example, if your user name is "mjones" and your realm is
"KRBNT-OPERATIONS.EXAMPLE.COM", you would use
"mjones@KRBNT-OPERATIONS.EXAMPLE.COM" (complete with the
quotes).
You must also substitute your realm in
"krbtgt/your_realm@your_realm" and the
service principal name for the service principal representing the
server for "service_principal@your_realm
".
Suppose the former is
"krbtgt/KRBNT-OPERATIONS.EXAMPLE.COM@KRBNT-OPERATIONS.EXAMPLE.COM"
and the latter is
"sample/raven.example.com@KRBNT-OPERATIONS.EXAMPLE.COM", and your
user name is as specified in the previous paragraph. Then the
grant
statement would be
grant CodeBase "file:./SampleClient.jar", Principal javax.security.auth.kerberos.KerberosPrincipal "mjones@KRBNT-OPERATIONS.EXAMPLE.COM" { permission java.net.SocketPermission "*", "connect"; permission javax.security.auth.kerberos.ServicePermission "krbtgt/KRBNT-OPERATIONS.EXAMPLE.COM@KRBNT-OPERATIONS.EXAMPLE.COM", "initiate"; permission javax.security.auth.kerberos.ServicePermission "sample/raven.example.com@KRBNT-OPERATIONS.EXAMPLE.COM", "initiate"; };
The grant
statement in the server policy file for
the Login classes is exactly the same as the one in the client
policy file, as described in Permissions
Required by the Login Utility Classes:
grant codebase "file:./Login.jar" { permission java.security.AllPermission; };
SampleServer
The SampleServer
code does two types of
operations for which permissions are required. It
The permission required to accept socket connections is
permission java.net.SocketPermission "*", "accept";
You may replace the "*" with the hostname or IP address of the
machine that SampleClient
will be running on.
The permission required to accept establishment of a security context is
permission javax.security.auth.kerberos.ServicePermission "service_principal@your_realm", "accept";where "service_principal@your_realm" is the Kerberos name of the service principal that represents
SampleServer
.
We want to grant the permissions to a specific authenticated
user executing SampleServer
(the service principal
considered to represent SampleServer
), so we specify
both the SampleServer
code location (in
SampleServer.jar
) and a Principal designation
indicating the service principal. Suppose this name is
"sample/raven.example.com@KRBNT-OPERATIONS.EXAMPLE.COM". Then the
grant
statement would be
grant CodeBase "file:./SampleServer.jar" Principal javax.security.auth.kerberos.KerberosPrincipal "sample/raven.example.com@KRBNT-OPERATIONS.EXAMPLE.COM" { permission java.net.SocketPermission "*", "accept"; permission javax.security.auth.kerberos.ServicePermission "sample/raven.example.com@KRBNT-OPERATIONS.EXAMPLE.COM", "accept"; };
SampleClient
and
SampleServer
ProgramsTo execute the SampleClient
and
SampleServer
programs, do the following:
SampleServer
for
ExecutionSampleClient
for
ExecutionSampleServer
SampleClient
SampleServer
for ExecutionTo prepare SampleServer
for execution, do the
following:
SampleServer
:
csLogin.conf
with the name of
the service principal representing
SampleServer
.server.policy
with
the Kerberos name of the service principal that represents
SampleServer
. (The same name as that used in the
login configuration file.)Login.java
and
SampleServer.java
:
javac Login.java SampleServer.java
Note that Login.java
contains two classes and
thus compiling Login.java
creates
Login.class
and MyAction.class
.
Login.jar
containing
Login.class and MyAction.class
:
jar -cvf Login.jar Login.class MyAction.class
SampleServer.jar
containing SampleServer.class
:
jar -cvf SampleServer.jar SampleServer.class
SampleClient
for ExecutionTo prepare SampleClient
for execution, do the
following:
SampleClient
:
client.policy
:
your_realm
in
"krbtgt/your_realm@your_realm" with your realm.SampleServer
.Login.java
and
SampleClient.java
:
javac Login.java SampleClient.java
Login.jar
containing
Login.class and MyAction.class
:
jar -cvf Login.jar Login.class MyAction.class
SampleClient.jar
containing SampleClient.class
:
jar -cvf SampleClient.jar SampleClient.class
SampleServer
It is important to execute SampleServer
before
SampleClient
because SampleClient
will
try to make a socket connection to SampleServer
and
that will fail if SampleServer
is not yet running
and accepting socket connections.
To execute SampleServer
, be sure to run it on the
machine it is expected to be run on. This machine name (host
name) is specified as an argument to SampleClient
.
The service principal name appears in several places, including
the login configuration file and the policy files.
Go to the directory in which you have prepared
SampleServer
for execution. Execute the
Login
class, specifying
-classpath
clause that classes
should be searched for in the Login.jar
and
SampleServer.jar
JAR files,-Djava.security.manager
that a security
manager should be installed,-Djava.security.krb5.realm=<your_realm>
that your Kerberos realm is the one specified. For example, if
your realm is "KRBNT-OPERATIONS.EXAMPLE.COM" you'd put
-Djava.security.krb5.realm=KRBNT-OPERATIONS.EXAMPLE.COM
.-Djava.security.krb5.kdc=<your_kdc>
that your Kerberos KDC is the one specified. For example, if your
KDC is "samplekdc.example.com" you'd put
-Djava.security.krb5.kdc=samplekdc.example.com
.-Djava.security.policy=server.policy
that the
policy file to be used is server.policy
, and-Djava.security.auth.login.config=csLogin.conf
that
the login configuration file to be used is
csLogin.conf
.You pass the name of your application (in this case,
"SampleServer
") as an argument to Login. You then
add as arguments any arguments required by your application,
which in the case of SampleServer
is a single
argument specifying the port number to be used for listening for
client connections. Choose a high port number unlikely to be used
for anything else. An example would be something like 4444.
Below are the full commands to use for both Microsoft Windows and Unix systems. The only difference is that on Microsoft Windows systems you use semicolons to separate classpath items, while you use colons for that purpose on Unix systems.
Important: In these commands, you must replace
<port_number>
with an appropriate port number,
<your_realm>
with your Kerberos realm, and
<your_kdc>
with your Kerberos KDC.
Here is the command for Microsoft Windows systems:
java -classpath Login.jar;SampleServer.jar -Djava.security.manager -Djava.security.krb5.realm=<your_realm> -Djava.security.krb5.kdc=<your_kdc> -Djava.security.policy=server.policy -Djava.security.auth.login.config=csLogin.conf Login SampleServer <port_number>
Here is the command for UNIX systems:
java -classpath Login.jar:SampleServer.jar -Djava.security.manager -Djava.security.krb5.realm=<your_realm> -Djava.security.krb5.kdc=<your_kdc> -Djava.security.policy=server.policy -Djava.security.auth.login.config=csLogin.conf Login SampleServer <port_number>
Type the full command on one line. Multiple lines are used here for legibility. If the command is too long for your system, you may need to place it in a .bat file (for Microsoft Windows) or a .sh file (for UNIX) and then run that file to execute the command.
You will be prompted for the Kerberos password for the service
principal. The underlying Kerberos authentication mechanism
specified in the login configuration file will log the service
principal into Kerberos. Once authentication is successfully
completed, the SampleServer
code will be executed on
behalf of the service principal. It will listen for socket
connections on the specified port.
For login troubleshooting suggestions, see Troubleshooting.
SampleClient
To execute SampleClient
, go to the directory in
which you have prepared SampleClient
for execution.
Then execute the Login
class, specifying
-classpath
clause that classes
should be searched for in the Login.jar
and
SampleClient.jar
JAR files,-Djava.security.manager
that a security
manager should be installed,-Djava.security.krb5.realm=<your_realm>
that your Kerberos realm is the one specified.-Djava.security.krb5.kdc=<your_kdc>
that your Kerberos KDC is the one specified.-Djava.security.policy=client.policy
that the
policy file to be used is client.policy
, and-Djava.security.auth.login.config=csLogin.conf
that
the login configuration file to be used is
csLogin.conf
.Pass to Login the name of your application
("SampleClient
") followed by the arguments required
by SampleClient
. The SampleClient
arguments are (1) the Kerberos name of the
service principal that represents SampleServer
,
(2) the name of the host (machine) on which
SampleServer
is running, and (3) the port number on
which SampleServer
is listening for client
connections.
Below are the full commands to use for both Microsoft Windows and Unix systems.
Important: In these commands, you must replace
<service_principal>
,
<host>
, <port_number>
,
<your_realm>
, and
<your_kdc>
with appropriate values (and
note that the port number must be the same as the port number
passed as an argument to SampleServer
). These values
need not be placed in quotes.
Here is the command for Microsoft Windows systems:
java -classpath Login.jar;SampleClient.jar -Djava.security.manager -Djava.security.krb5.realm=<your_realm> -Djava.security.krb5.kdc=<your_kdc> -Djava.security.policy=client.policy -Djava.security.auth.login.config=csLogin.conf Login SampleClient <service_principal> <host> <port_number>
Here is the command for UNIX systems:
java -classpath Login.jar:SampleClient.jar -Djava.security.manager -Djava.security.krb5.realm=<your_realm> -Djava.security.krb5.kdc=<your_kdc> -Djava.security.policy=client.policy -Djava.security.auth.login.config=csLogin.conf Login SampleClient <service_principal> <host> <port_number>
Type the full command on one line. Multiple lines are used
here for legibility. As with the command for executing
SampleServer
, if the command is too long to type
directly into your command window, place it in a .bat file
(Microsoft Windows) or a .sh file (UNIX) and then execute that
file.
When prompted, type your Kerberos user name and password. The
underlying Kerberos authentication mechanism specified in the
login configuration file will log you into Kerberos. Once
authentication is successfully completed, the
SampleClient
code will be executed on behalf of you.
It will request a socket connection with
SampleServer
. Once SampleServer
accepts
the connection, SampleClient
and
SampleServer
establish a shared context and then
exchange messages as described in this tutorial.
For login troubleshooting suggestions, see Troubleshooting.