/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// JAAS
// JGSS
/**
* Implements the GSSAPI SASL server mechanism for Kerberos V5.
* (<A HREF="http://www.ietf.org/rfc/rfc2222.txt">RFC 2222</A>,
* <a HREF="http://www.ietf.org/internet-drafts/draft-ietf-cat-sasl-gssapi-00.txt">draft-ietf-cat-sasl-gssapi-00.txt</a>).
*
* Expects thread's Subject to contain server's Kerberos credentials
* - If not, underlying KRB5 mech will attempt to acquire Kerberos creds
* by logging into Kerberos (via default TextCallbackHandler).
* - These creds will be used for exchange with client.
*
* Required callbacks:
* - AuthorizeCallback
* authorized ID to be the canonicalized authzid (if applicable).
*
* Environment properties that affect behavior of implementation:
*
* javax.security.sasl.qop
* - quality of protection; list of auth, auth-int, auth-conf; default is "auth"
* javax.security.sasl.maxbuf
* - max receive buffer size; default is 65536
* javax.security.sasl.sendmaxbuffer
* - max send buffer size; default is 65536; (min with client max recv size)
*
* @author Rosanna Lee
*/
/**
* Creates a SASL mechanism with server credentials that it needs
* with the client.
*/
super(props, MY_CLASS_NAME);
try {
// Create the name for the requested service entity for Krb5 mech
// Create a context using the server's credentials
// Might need integrity
secCtx.requestInteg(true);
}
// Might need privacy
secCtx.requestConf(true);
}
} catch (GSSException e) {
throw new SaslException("Failure to initialize security context", e);
}
}
/**
* Processes the response data.
*
* The client sends response data to which the server must
* process using GSS_accept_sec_context.
* As per RFC 2222, the GSS authenication completes (GSS_S_COMPLETE)
* we do an extra hand shake to determine the negotiated security protection
* and buffer sizes.
*
* @param responseData A non-null but possible empty byte array containing the
* response data from the client.
* @return A non-null byte array containing the challenge to be
* sent to the client, or null when no more data is to be sent.
*/
if (completed) {
throw new SaslException(
"SASL authentication already complete");
}
"KRB5SRV03:Response [raw]:", responseData);
}
switch (handshakeStage) {
case 1:
return doHandshake1(responseData);
case 2:
return doHandshake2(responseData);
default:
// Security context not established yet; continue with accept
try {
"KRB5SRV04:Challenge: [after acceptSecCtx]", gssOutToken);
}
if (secCtx.isEstablished()) {
handshakeStage = 1;
if (gssOutToken == null) {
return doHandshake1(EMPTY);
}
}
return gssOutToken;
} catch (GSSException e) {
throw new SaslException("GSS initiate failed", e);
}
}
}
try {
// Security context already established. responseData
// should contain no data
throw new SaslException(
"Handshake expecting no response data from server");
}
// Construct 4 octets of data:
// First octet contains bitmask specifying protections supported
// 2nd-4th octets contains max receive buffer of server
byte[] gssInToken = new byte[4];
"KRB5SRV06:Supported protections: {0}; recv max buf size: {1}",
new Integer(recvMaxBufSize)});
}
"KRB5SRV07:Challenge [raw]", gssInToken);
}
"KRB5SRV08:Challenge [after wrap]", gssOutToken);
}
return gssOutToken;
} catch (GSSException e) {
throw new SaslException("Problem wrapping handshake1", e);
}
}
try {
// Expecting 4 octets from client selected protection
// and client's receive buffer size
"KRB5SRV09:Response [after unwrap]", gssOutToken);
}
// First octet is a bit-mask specifying the selected protection
throw new SaslException("Client selected unsupported protection: "
+ selectedQop);
}
privacy = true;
integrity = true;
integrity = true;
}
// 2nd-4th octets specifies maximum buffer size expected by
// client (in network byte order). This is the server's send
// buffer maximum.
// Determine the max send buffer size based on what the
// client is able to receive and our specified max
// Update context to limit size of returned buffer
"KRB5SRV10:Selected protection: {0}; privacy: {1}; integrity: {2}",
"KRB5SRV11:Client max recv size: {0}; server max send size: {1}; rawSendSize: {2}",
new Integer(sendMaxBufSize),
new Integer(rawSendSize)});
}
// Get authorization identity, if any
try {
} catch (UnsupportedEncodingException uee) {
}
} else {
}
// In Kerberos, realm is embedded in peer name
if (acb.isAuthorized()) {
completed = true;
} else {
// Authorization failed
throw new SaslException(peer +
" is not authorized to connect as " + authzid);
}
return null;
} catch (GSSException e) {
throw new SaslException("Final handshake step failed", e);
} catch (IOException e) {
throw new SaslException("Problem with callback handler", e);
} catch (UnsupportedCallbackException e) {
throw new SaslException("Problem with callback handler", e);
}
}
if (completed) {
return authzid;
} else {
throw new IllegalStateException("Authentication incomplete");
}
}
}