This part shows you how to build applications that perform
secure communications. The Java SE 6 platform provides three
standard APIs that allow applications to perform secure
communications: The Java Generic Security Service (GSS), the Java
SASL API, and the Java Secure Socket Extension (JSSE). When
building an application, which of these APIs should you use? The
answer depends on many factors, including requirements of the
protocol or service, deployment infrastructure, and integration
with other security services. For example, if you are building an
LDAP client library, you would need to use the Java SASL API
because use of SASL is part of LDAP's protocol definition. As an
other example, if the service supports SSL, then the client
application attempting to access the service would need to use
JSSE.
Exercise 3: Using
the Java Generic Security Service (GSS) API
Goal of this exercise:
The goal of this exercise is to learn how to use the Java GSS API
to perform secure authentication and communication.
Background for this exercise:
The Generic Security Service API provides a uniform C-language
interface to access various security services, such as
authentication, message integrity, and message confidentiality. The
Java GSS API provides the corresponding interface for Java
applications. It allows applications to perform
authentication and establish secure communication with the peer.
One of the most common security service accessed via the GSS-API
and Java GSS-API is Kerberos.
Resources for this Exercise:
-
The JAAS and Java GSS-API Tutorials
- Generic Security
Service API Version 2: Java Bindings (RFC 2853)
- Java GSS javadocs:
org.ietf.jgss.
Overview of this Exercise:
This
exercise is a client-server application that demonstrates how to
communicate securely using the Java GSS API. The client and server
parts first authenticate to Kerberos, as shown in Exercise 1. This stores the credentials in
the subject. The application then executes an action that performs
Java GSS operations (with Kerberos as the underlying GSS mechanism)
inside of a Subject.doAs using the subject. The Java GSS
Kerberos mechanism, because it is executing inside the
doAs, obtains the Kerberos credentials from the subject,
and uses them to authenticate with the peer and to exchange
messages securely.
Steps to
follow:
- Read the
following code. This is located in
src/GssServer.java.
This code fragment defines the action to execute after the service
principal has authenticated to the KDC. It replaces the
MyAction of line 11 of Exercise
1. Note the highlighted lines. The code first creates an
instance of GSSManager
[line 8], which it uses
to obtain its own credentials [line 10-11] and to create an
instance of GSSContext
[line 18]. It uses this
context to perform authentication [the loop between lines 22-34].
Upon completing authentication, it accepts encrypted input from the
client and uses the established security context to decrypt the
data [line 45]. It then uses the security context to encrypt a
reply containing the original input and the date [line 49], and
then sends it back to the client.
Code
listing for GssServer.java
.
static class GssServerAction implements
PrivilegedExceptionAction {
...
public Object run() throws Exception
{
// Create server socket for
accepting connections
ServerSocket ss = new
ServerSocket(localPort);
// Get own Kerberos credentials
for accepting connection
GSSManager manager =
GSSManager.getInstance();
Oid krb5Oid = new
Oid("1.2.840.113554.1.2.2");
GSSCredential serverCreds =
manager.createCredential(null,
-
GSSCredential.DEFAULT_LIFETIME,
krb5Oid, GSSCredential.ACCEPT_ONLY);
while (true) {
Socket socket =
ss.accept();
DataInputStream
inStream = new
DataInputStream(socket.getInputStream());
DataOutputStream
outStream = new
DataOutputStream(socket.getOutputStream());
GSSContext
context =
manager.createContext((GSSCredential)serverCreds);
// Do the context
establishment loop
byte[] token =
null;
while
(!context.isEstablished()) {
// Read
token
token =
new byte[inStream.readInt()];
-
inStream.readFully(token);
//
Process token
-
token
= context.acceptSecContext(token, 0,
token.length);
// Send a
token to the peer if one was generated by
acceptSecContext
-
outStream.writeInt(token.length);
-
outStream.write(token);
-
outStream.flush();
}
// Context
established!
// Create MessageProp
for use with unwrap (will be set upon return from
unwrap)
MessageProp prop =
new MessageProp(0, false);
// Read token from
client
token = new
byte[inStream.readInt()];
-
inStream.readFully(token);
// Unwrap (decrypt)
token sent by client
byte[] input
= context.unwrap(token, 0, token.length,
prop);
...
// Create new token
and send to client
byte[] reply =
...;
token =
context.wrap(reply, 0, reply.length, prop);
-
outStream.writeInt(token.length);
-
outStream.write(token);
-
outStream.flush();
-
context.dispose();
-
socket.close();
}
}
}
|
- Compile
the sample code.
% javac
GssServer.java
- Read the
following code. This is located in
src/GssClient.java.
This code fragment defines the action to execute after the client
principal has authenticated to the KDC. It replaces the
MyAction of line 11 of Exercise
1. Note the highlighted lines. The code first creates an
instance of GSSManager
[line 10], which it uses
to obtain a principal name for the service that it is going to
communicate with [line 12]. It then creates an instance of
GSSContext
[line 15,16] to perform
authentication [the loop between lines 22-33] with the service.
Upon completing authentication, it uses the established security
context to encrypt a message [line 42] and sends it to the server.
It then reads an encrypted message from the server and decodes it
using the established security context [line 53].
Code listing
for GssClient.java
.
static class GssClientAction implements
PrivilegedExceptionAction {
...
public Object run() throws Exception
{
// Create socket to
server
Socket socket = new
Socket(hostName, port);
DataInputStream inStream = new
DataInputStream(socket.getInputStream());
DataOutputStream outStream = new
DataOutputStream(socket.getOutputStream());
// Get service's principal
name
GSSManager manager =
GSSManager.getInstance();
Oid krb5Oid = new
Oid("1.2.840.113554.1.2.2");
GSSName serverName =
manager.createName(serverPrinc,
GSSName.NT_HOSTBASED_SERVICE);
// Get the context for
authentication
GSSContext context =
manager.createContext(serverName, krb5Oid,
null,
GSSContext.DEFAULT_LIFETIME);
context.requestMutualAuth(true);
// Request mutual authentication
context.requestConf(true); //
Request confidentiality
// Do the context establishment
loop
byte[] token = new
byte[0];
while
(!context.isEstablished()) {
token =
context.initSecContext(token, 0, token.length);
-
outStream.writeInt(token.length);
-
outStream.write(token);
-
outStream.flush();
// Check if we're
done
if
(!context.isEstablished()) {
token =
new byte[inStream.readInt()];
-
inStream.readFully(token);
}
}
// Context
established!
// Create MessageProp for use
with unwrap (true means request confidentiality)
MessageProp prop = new
MessageProp(0, true);
// Create encrypted message and
send to server
byte[] reply = ...;
token =
context.wrap(reply, 0, reply.length, prop);
-
outStream.writeInt(token.length);
-
outStream.write(token);
outStream.flush();
// Read token from
server
token = new
byte[inStream.readInt()];
-
inStream.readFully(token);
// Unwrap (decrypt) token sent by
server
byte[] input =
context.unwrap(token, 0, token.length, prop);
...
-
context.dispose();
socket.close();
return null;
}
}
|
- Compile
the sample code.
% javac GssClient.java
- Launch a
new window and start the server.
% xterm &
% java -Djava.security.auth.login.config=jaas-krb5.conf \
GssServer
- Run the
client application. GssClient takes two parameters: the
service name and the name of the server that the service is running
on. For example, if the service is
host
running
on the machine j1hol-001
, you would enter the
following. When prompted for the password, enter
changeit.
% java -Djava.security.auth.login.config=jaas-krb5.conf \
GssClient host j1hol-001
- Observe
the following output in the client and server applications'
windows.
Output
for running GssServer example.
Authenticated principal:
[host/j1hol-001@J1LABS.EXAMPLE.COM]
Waiting for incoming connections...
Got connection from client /129.145.128.102
Context Established!
Client principal is test@J1LABS.EXAMPLE.COM
Server principal is
host/j1hol-001@J1LABS.EXAMPLE.COM
Mutual authentication took place!
Received data "Hello There!" of length 12
Confidentiality applied: true
Sending: Hello There! Thu May 06 12:11:15 PDT
2005
|
Output
for running GssClient example.
Kerberos password for test: changeit
Authenticated principal:
[test@J1LABS.EXAMPLE.COM]
Connected to address
j1hol-001/129.145.128.102
Context Established!
Client principal is test@J1LABS.EXAMPLE.COM
Server principal is host@j1hol-001
Mutual authentication took place!
Sending message: Hello There!
Will read token of size 93
Received message: Hello There! Thu May 06 12:11:15 PDT
2005
|
Summary:
In this exercise, you learned
how to write a client-server application that uses the Java GSS API
to authenticate and communicate securely with each
other.
Next Steps
- Proceed to Exercise 4 to learn how to write a client/server
application that uses the Java SASL API to authenticate and
communicate securely with each other.
- Proceed to Exercise 5 to learn how to write a client/server
application that uses the JSSE to authenticate and communicate
securely with each other.
- Proceed to Exercise 6 to learn how to configure the
sample programs that you have just used to achieve single sign-on
in a Kerberos environment.
Exercise 4: Using the Java SASL API
Goal of this
exercise:
The goal of this exercise is
to learn how to use the Java SASL API to perform secure
authentication and communication.
Background for this
exercise:
Simple Authentication and
Security Layer (SASL) specifies a challenge-response protocol in
which data is exchanged between the client and the server for the
purposes of authentication and (optional) establishment of a
security layer on which to carry on subsequent communications. SASL
allows different mechanisms to be used; each such
mechanism is identified by a profile that defines the data to be
exchanged and a name. SASL is used with connection-based protocols
such as LDAPv3 and IMAPv4. SASL is described in RFC 4422.
The Java SASL API defines an
API for applications to use SASL in a mechanism-independent way.
For example, if you are writing a library for a networking protocol
that uses SASL, you can use the Java SASL API to generate the data
to be exchanged with the peer. When the library is deployed, you
can dynamically configure the mechanisms to use with the
library.
In addition to
authentication, you can use SASL to negotiate a security layer to
be used after authentication. But unlike the GSS-API, the
properties of the security layer (such as whether you want
integrity or confidentiality) is decided at negotiation time. (the
GSS-API allows confidentiality to be turned on or off per
message).
Resources for this
exercise:
-
The Java SASL API Programming and Deployment Guide
-
The Java SASL API javadocs
- Simple Authentication and
Security Layer (SASL) (RFC 4422)
Overview of this
exercise:
This exercise is a
client-server application that demonstrates how to communicate
securely using the Java SASL API. The client and server parts first
authenticate to Kerberos using Exercise
1. This stores the credentials in the subject. The application
then executes an action that performs Java SASL API operations
(with Kerberos as the underlying SASL mechanism) inside of a
Subject.doAs using the subject. The SASL/Kerberos
mechanism, because it is executing inside the doAs,
obtains the Kerberos credentials from the subject, and uses them to
authenticate with the peer and to exchange messages
securely.
This example uses a simple
protocol implemented by the AppConnection
class. This
protocol exchanges authentication commands and data commands. Each
command consists of a type (e.g., AppConnection.AUTH_CMD),
the length of the data to follow, and the data itself. The data is
a SASL buffer if it is for authentication or
encrypted/integrity-protected application data; it is plain
application data otherwise.
Steps to follow:
- Read the following code. This is located in
src/SaslTestServer.java.
This code fragment defines the action to execute after the service
principal has authenticated to the KDC. It replaces the
MyAction of line 11 of Exercise
1. Note the highlighted lines. The server specifies the
quality-of-protections that it will support [line 9] and then
creates an instance of SaslServer to perform the
authentication [line 21]. The challenge-response protocol of SASL
is performed in the while loop [lines 33-49], with the server
sending challenges to the client and processing the responses from
the client. After authentication, the identity of the authenticated
client can be obtained via a call to
getAuthorizedID() [line 61]. If a security layer
was negotiated, the server can exchange data securely with the
client [lines 66,70].
Code listing for SaslTestServer.java
.
static class SaslServerAction implements
PrivilegedExceptionAction {
...
public Object run() throws Exception
{
// Create server socket for
accepting connections
ServerSocket ss = new
ServerSocket(localPort);
// Support all
quality-of-protection options
HashMap<String,Object>
props = new HashMap<String,Object>();
props.put(Sasl.QOP,
"auth-conf,auth-int,auth");
while (true) {
// Create
application-level connection to handle request
Socket socket =
ss.accept();
AppConnection conn =
new AppConnection(socket);
// Normally, the
application protocol will negotiate which
// SASL mechanism to
use. In this simplified example, we
// will always use
"GSSAPI" (the name of the mechanism that does Kerberos via
GSS-API)
// Create SaslServer
to perform authentication
SaslServer
srv = Sasl.createSaslServer("GSSAPI", service, serviceName, props,
cbh);
if (srv == null)
{
// ...
handle error
}
// Read the initial
response from client
byte[]
response =
conn.receive(AppConnection.AUTH_CMD);
-
AppConnection.AppReply
clientMsg;
boolean auth =
false;
// Perform
authentication
while
(!srv.isComplete()) {
-
try
-
//
Generate challenge based on response
-
byte[]
challenge = srv.evaluateResponse(response);
-
if
(srv.isComplete()) {
-
conn.send(AppConnection.SUCCESS,
challenge);
-
auth
= true;
-
}
else {
-
clientMsg
= conn.send(AppConnection.AUTH_IN_PROGRESS,
challenge);
-
response
= clientMsg.getBytes();
-
}
} catch
(SaslException e) {
-
//
Send failure notification to client
-
conn.send(AppConnection.FAILURE,
null);
-
break;
-
}
}
// Authentication
completed!
// Check status of
authentication
if
(srv.isCompleted() && auth) {
-
System.out.println("authorized
client is: " +
srv.getAuthorizationID());
} else {
// Report
failure ...
}
// Find out whether
security layer was negotiated
String qop = (String)
srv.getNegotiatedProperty(Sasl.QOP);
boolean sl =
(qop.equals("auth-conf") || qop.equals("auth-int"));
// Read and decrypt
message from client
byte[] msg =
conn.receive(AppConnection.DATA_CMD);
byte[] realMsg = (sl
? srv.unwrap(msg, 0, msg.length) :
msg);
...
// Create and encrypt
message to send to client
byte[] reply =
...;
byte[] realReply =
(sl ? srv.wrap(reply, 0, reply.length) :
reply);
-
conn.send(AppConnection.SUCCESS,
realReply);
}
}
}
|
- Compile the sample code.
% javac SaslTestServer.java
- Read the following code. This is located in
src/SaslTestClient.java.
This code fragment defines the action to execute after the client
principal has authenticated to the KDC. It replaces the
MyAction of line 11 of Exercise
1. Note the highlighted lines. The program first specifies the
quality of protection that it wants (in this case, confidentiality)
[line 8] and then creates an instance of SaslClient
to use for authentication [lines 11-12]. It then checks whether the
mechanism has an initial response and if so, gets the response by
invoking evaluateChallenge() with an empty byte
array [line 20]. It then sends the response to the server to begin
the authentication. The challenge-response protocol of SASL is
performed in the while loop [lines 24-39], with the client
evaluating the challenges that it gets from the server and sending
the server the corresponding responses to the challenges. After
authentication, the client can proceed to communicate with the
server using the negotiated security layer [lines 48,55].
Code listing for SaslTestClient.java
.
static class SaslClientAction implements
PrivilegedExceptionAction {
...
public Object run() throws Exception
{
// Create application-level
connection
AppConnection conn = new
AppConnection(serverName, port);
HashMap<String,Object>
props = new HashMap<String,Object>();
props.put(Sasl.QOP,
"auth-conf"); // Request confidentiality
// Create SaslClient to perform
authentication
SaslClient clnt =
Sasl.createSaslClient(
new
String[]{"GSSAPI"}, null, service, serverName, props,
cbh);
if (clnt == null) {
// ... handle
error
}
byte[] challenge;
// Get initial response for
authentication
byte[] response =
clnt.hasInitialResponse() ? clnt.evaluateChallenge(EMPTY) :
EMPTY;
AppConnection.AppReply reply =
conn.send(AppConnection.AUTH_CMD, response);
// Repeat until authentication
terminates
while
(!clnt.isComplete() &&
(reply.getStatus() ==
AppConnection.AUTH_INPROGRESS ||
-
reply.getStatus()
== AppConnection.SUCCESS))
// Evaluate challenge
to generate response
-
challenge
= reply.getBytes()
response =
clnt.evaluateChallenge(challenge)
if (reply.getStatus()
== AppConnection.SUCCESS) {
if
(response != null) {
-
throw
new Exception("Protocol error")
-
}
-
break;
}
// Send response to
server and read server's next challenge
reply =
conn.send(AppConnection.AUTH_CMD,
response);
}
// Authentication
completed!
// Find out whether security
layer was negotiated
String qop = (String)
srv.getNegotiatedProperty(Sasl.QOP);
boolean sl =
(qop.equals("auth-conf") || qop.equals("auth-int"));
byte[] msg = ...;
// Create and send encrypted data
to server
byte[] encrypted = (sl ?
clnt.wrap(msg, 0, msg.length) : msg);
reply =
conn.send(AppConnection.DATA_CMD, encrypted);) {
...
// Read and decrypt data from
server
byte[] encryptedReply =
reply.getBytes();
byte[] clearReply = (sl ?
clnt.unwrap(encryptedReply, 0,
encryptedReply.length)
:
encryptedReply);
conn.close();
return null;
}
}
|
- Compile the sample code.
% javac SaslTestClient.java
- Launch a new window and start the server.
SaslTestServer takes two parameters: the service name and
the name of the server that the service is running on. For example,
if the service is
host
running on the machine
j1hol-001
, you would enter the following.
% xterm &
% java
-Djava.security.auth.login.config=jaas-krb5.conf \
SaslTestServer host j1hol-001
- Run the client application. SaslTestClient takes two
parameters: the service name and the name of the server that the
service is running on. For example, if the service is
host
running on the machine
j1hol-001
, you would enter the following. When
prompted for the password, enter changeit.
% java -Djava.security.auth.login.config=jaas-krb5.conf \
SaslTestClient host j1hol-001
- Observe the following output in the client and server
applications' windows.
Output for running the SaslTestServer
example.
Authenticated principal:
[host/j1hol-001@J1LABS.EXAMPLE.COM]
Waiting for incoming connections...
Got connection from client /129.145.128.102
Client authenticated; authorized client is:
test@J1LABS.EXAMPLE.COM
Negotiated QOP: auth-conf
Received: Hello There!
Sending: Hello There! Fri May 07 15:32:37 PDT
2005
Received data "Hello There!" of length 12
|
Output for running the SaslTestClient
example.
Kerberos password for test: changeit
Authenticated principal:
[test@J1LABS.EXAMPLE.COM]
Connected to address
j1hol-001/129.145.128.102
Client authenticated.
Negotiated QOP: auth-conf
Sending: Hello There!
Received: Hello There! Fri May 07 15:32:37 PDT
2005
|
- To try the program using different quality-of-protection,
change line 8 in
SaslTestClient
. For example, replace
line 8 with the following line to use integrity protection on (no
confidentiality).
props.put(Sasl.QOP, "auth-int");
Summary:
In this exercise, you learned how to write a client-server
application that uses the Java SASL API to authenticate and
communicate securely with each other.
Next Steps
- Proceed to Exercise 5 to learn how to write
a client/server application that uses the JSSE to authenticate and
communicate securely with each other.
- Proceed to Exercise 6 to learn how
to configure the sample programs that you have just used to achieve
single sign-on in a Kerberos environment.
Exercise 5: Using the Java Secure
Socket Extension with Kerberos
Goal of this exercise:
The goal of this exercise is to learn how to use the JSSE API
to perform secure authentication and communication using
Kerberos cipher suites.
Background for this exercise:
Secure Socket Layer (SSL) and Transport Layer Security (TLS) are
the most widely used protocols for implementing cryptography on the
Internet. TLS is the Internet standard evolved from SSL. SSL/TLS
provides application-level protocols (such as HTTP and LDAP) with
secure authentication and communication. For example, HTTPS is the
resulting protocol of using HTTP over SSL/TLS. SSL/TLS is used not
only for standard protocols such as HTTP, it is also widely used
when building custom applications using custom protocols that need
to communicate securely.
SSL/TLS traditionally used certificate-based authentication and
is commonly used for server-authentication. For example, when a Web
client such as a browser accesses a secure Web site (server) on
behalf of a user, the server sends its certificate to the browser
so that the browser can verify the identity of the server. This
ensures that the user does not divulge confidential information
(such as credit card information) to a bogus server. Recently, a
new standard allows the use of Kerberos with TLS. This means
instead of using certificate-based authentication, an application
can use Kerberos credentials and take advantage of the Kerberos
infrastructure in the deployment environment. Using Kerberos cipher
suites also provides automatic support for mutual authentication in
which the client is also authenticated in addition to the
server.
The decision of whether to use Java GSS, Java SASL, or JSSE for
a particular application often depends upon several factors,
including (the protocols being used by) the services with which the
application interacts, the deployment environment (PKI or
Kerberos-based), and the application's security requirements. JSSE
provides a secure end-to-end channel that takes care of the I/O and
transport, while Java GSS and Java SASL provide encryption and
integrity-protection on the data, but the application is
responsible for transporting the secured data to its peer. Some
details about factors for deciding when to use JSSE versus Java GSS
are presented in the document,
When to use Java GSS vs. JSSE.
Resources for this exercise:
-
Java Secure Socket Extension (JSSE) Reference Guide
- The JSSE javadocs:
javax.net and
javax.net.ssl
- The SSL
Protocol version 3.0
- The TLS Protocol
Version 1.0 (RFC 2246)
- Addition of
Kerberos Cipher Suites to Transport Layer Security TLS (RFC
2712)
-
When to use Java GSS vs. JSSE
Overview of this exercise:
This exercise is a client-server application that demonstrates
how to communicate securely using the JSSE and Kerberos cipher
suites. The client and server parts first authenticate to Kerberos
using Exercise 1. This stores the
credentials in the subject. The application then executes an action
that performs JSSE operations (using a Kerberos cipher suite)
inside of a Subject.doAs using the subject. The Kerberos
cipher suite implementation, because it is executing inside the
doAs, obtains the Kerberos credentials from the subject,
and uses them to authenticate with the peer and to exchange
messages securely. This example sends newline-terminated messages,
encrypted using the negotiated cipher suite and
integrity-protected, back and forth between client and server.
According to the standard (RFC 2712) all Kerberos-enabled TLS
applications use the same service name, namely, "host". That
is why in this exercise, you do not need to explicitly supply the
Kerberos service name.
Steps to follow:
- Read the following code. This is located in
src/JsseServer.java
This code fragment defines the action to execute after the service
principal has authenticated to the KDC. It replaces the
MyAction of line 11 of Exercise
1. Note the highlighted lines. The server first creates an
SSLServerSocket [lines 5-8]. This is
analogous to an application creating a plain ServerSocket
except an SSLServerSocket will provide automatic
authentication, encryption and decryption, as needed. The server
then sets the cipher suites that it wants to use [lines 11-12]. The
server then runs in a loop, accepting connections from SSL clients
[line 17], and reads and writes from the SSL socket [lines 23, 28].
The server can find out the identities of the owners of socket by
invoking the getLocalPrincipal() and
getPeerPrincipal() methods [lines
32-33].
Code listing for JsseServer.java
.
static class JsseServerAction implements
PrivilegedExceptionAction {
...
public Object run() throws Exception
{
// Create TLS socket for
accepting connections
SSLServerSocketFactory
sslssf =
-
(SSLServerSocketFactory)
SSLServerSocketFactory.getDefault();
SSLServerSocket
sslServerSocket =
-
(SSLServerSocket)
sslssf.createServerSocket(localPort);
// Enable only a Kerberos cipher
suite
String enabledSuites[] = {
"TLS_KRB5_WITH_3DES_EDE_CBC_SHA" };
-
sslServerSocket.setEnabledCipherSuites(enabledSuites);
// Should handle exception if
enabledSuites is not supported
while (true) {
// Create socket to
handle request
SSLSocket
sslSocket = (SSLSocket)
sslServerSocket.accept();
BufferedReader in =
new BufferedReader(new InputStreamReader(
-
sslSocket.getInputStream()));
BufferedWriter out =
new BufferedWriter(new OutputStreamWriter(
-
sslSocket.getOutputStream()));
String inStr =
in.readLine();
// ... use
inStr
// Compose and send
reply
String outStr = inStr
+ " " + new Date().toString() + "\n";
-
out.write(outStr);
-
out.flush();
// Get names of
principal at both ends of secure connection
Principal
self =
sslSocket.getSession().getLocalPrincipal();
Principal
peer =
sslSocket.getSession().getPeerPrincipal();
-
sslSocket.close();
}
}
}
|
- Compile the sample code.
% javac JsseServer.java
- Read the following code. This is located in
src/JsseClient.java
. This
code fragment defines the action to execute after the client
principal has authenticated to the KDC. It replaces the
MyAction of line 11 of Exercise 1.
Note the highlighted lines. The client first creates an
SSLSocket. The client then sets the
cipher suites that it wants to use [lines 11-12]. The client then
exchanges messages with the server using the SSLSocket by
reading and writing to the socket's input/output streams. The
client can find out the identities of the owners of socket by
invoking the getLocalPrincipal() and
getPeerPrincipal() methods [lines
26-27].
Code listing for JsseClient.java
static class JsseClientAction implements
PrivilegedExceptionAction {
...
public Object run() throws Exception
{
// Create SSL
connection
SSLSocketFactory sslsf =
(SSLSocketFactory)
SSLSocketFactory.getDefault();
SSLSocket sslSocket =
(SSLSocket) sslsf.createSocket(server, port);
// Enable only a Kerberos cipher
suite
String enabledSuites[] = {
"TLS_KRB5_WITH_3DES_EDE_CBC_SHA" };
-
sslSocket.setEnabledCipherSuites(enabledSuites);
// Should handle exception if
enabledSuites is not supported
BufferedReader in = new
BufferedReader(new InputStreamReader(
-
sslSocket.getInputStream()));
BufferedWriter out = new
BufferedWriter(new OutputStreamWriter(
-
sslSocket.getOutputStream()));
String outStr = ...;
-
out.write(outStr);
out.flush();
String inStr =
in.readLine();
// ... use inStr
// Get names of principal at both
ends of secure connection
Principal self =
sslSocket.getSession().getLocalPrincipal();
Principal peer =
sslSocket.getSession().getPeerPrincipal();
-
sslSocket.close();
return null;
}
}
|
- Compile the sample code.
% javac JsseClient.java
- Launch a new window and start the server. JsseServer
takes one parameter: the name of the server that the JSSE service
is running on. For example, if it is running on the machine
j1hol-001
, you would enter the following.
% xterm &
% java
-Djava.security.auth.login.config=jaas-krb5.conf \
JsseServer j1hol-001
- Run the client application. JsseClient takes one
parameter: the name of the server that the JSSE service is running
on. For example, if the service is running on the machine
j1hol-001
, you would enter the following. When
prompted for a password, enter changeit.
% java -Djava.security.auth.login.config=jaas-krb5.conf \
JsseClient j1hol-001
- Observe the following output in the client and server
applications' windows.
Output for running the JsseServer
example.
Authenticated principal:
[host/j1hol-001@J1LABS.EXAMPLE.COM]
Waiting for incoming connections...
Got connection from client /129.145.128.102
Received: Hello There!
Sending: Hello There! Fri May 07 15:32:37 PDT
2005
Cipher suite in use:
TLS_KRB5_WITH_3DES_EDE_CBC_SHA
I am: host/j1hol-001@J1LABS.EXAMPLE.COM
Client is: test@J1LABS.EXAMPLE.COM
|
Output for running the JsseClient
example.
Kerberos password for test: changeit
Authenticated principal:
[test@J1LABS.EXAMPLE.COM]
Sending: Hello There!
Received: Hello There! Fri May 07 15:32:37 PDT
2005
Cipher suite in use:
TLS_KRB5_WITH_3DES_EDE_CBC_SHA
I am: test@J1LABS.EXAMPLE.COM
Server is: host/j1hol-001@J1LABS.EXAMPLE.COM
|
Summary:
In this exercise, you learned how to write a client-server
application that uses JSSE to authenticate and communicate securely
with each other, using Kerberos as the underlying authentication
system.
Next Steps
- Proceed to Exercise 6 to learn how
to configure the sample programs in Exercises 3, 4, and 5 to
achieve single sign-on in a Kerberos environment.
Copyright © 1993, 2010, Oracle and/or its affiliates. All rights reserved. Please send comments using this Feedback page. |
Java Technology |