feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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.
*/
package com.sun.security.sasl.gsskerb;
import javax.security.sasl.*;
import com.sun.security.sasl.util.PolicyUtils;
import java.util.Map;
import javax.security.auth.callback.CallbackHandler;
/**
* Client/server factory for GSSAPI (Kerberos V5) SASL client/server mechs.
* See GssKrb5Client/GssKrb5Server for input requirements.
*
* @author Rosanna Lee
*/
public final class FactoryImpl implements SaslClientFactory, SaslServerFactory {
private static final String myMechs[] = {
"GSSAPI"};
private static final int mechPolicies[] = {
PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS|PolicyUtils.NOACTIVE
};
private static final int GSS_KERB_V5 = 0;
public FactoryImpl() {
}
public SaslClient createSaslClient(String[] mechs,
String authorizationId,
String protocol,
String serverName,
Map<String,?> props,
CallbackHandler cbh) throws SaslException {
for (int i = 0; i < mechs.length; i++) {
if (mechs[i].equals(myMechs[GSS_KERB_V5])
&& PolicyUtils.checkPolicy(mechPolicies[GSS_KERB_V5], props)) {
return new GssKrb5Client(
authorizationId,
protocol,
serverName,
props,
cbh);
}
}
return null;
};
public SaslServer createSaslServer(String mech,
String protocol,
String serverName,
Map<String,?> props,
CallbackHandler cbh) throws SaslException {
if (mech.equals(myMechs[GSS_KERB_V5])
&& PolicyUtils.checkPolicy(mechPolicies[GSS_KERB_V5], props)) {
if (cbh == null) {
throw new SaslException(
"Callback handler with support for AuthorizeCallback required");
}
return new GssKrb5Server(
protocol,
serverName,
props,
cbh);
}
return null;
};
public String[] getMechanismNames(Map<String,?> props) {
return PolicyUtils.filterMechs(myMechs, mechPolicies, props);
}
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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.
*/
package com.sun.security.sasl.gsskerb;
import java.util.Map;
import java.util.logging.Level;
import javax.security.sasl.*;
import com.sun.security.sasl.util.AbstractSaslImpl;
import org.ietf.jgss.*;
abstract class GssKrb5Base extends AbstractSaslImpl {
private static final String KRB5_OID_STR = "1.2.840.113554.1.2.2";
protected static Oid KRB5_OID;
protected static final byte[] EMPTY = new byte[0];
static {
try {
KRB5_OID = new Oid(KRB5_OID_STR);
} catch (GSSException ignore) {}
}
protected GSSContext secCtx = null;
protected static final int JGSS_QOP = 0; // unrelated to SASL QOP mask
protected GssKrb5Base(Map<String, ?> props, String className)
throws SaslException {
super(props, className);
}
/**
* Retrieves this mechanism's name.
*
* @return The string "GSSAPI".
*/
public String getMechanismName() {
return "GSSAPI";
}
public byte[] unwrap(byte[] incoming, int start, int len)
throws SaslException {
if (!completed) {
throw new IllegalStateException("GSSAPI authentication not completed");
}
// integrity will be true if either privacy or integrity negotiated
if (!integrity) {
throw new IllegalStateException("No security layer negotiated");
}
try {
MessageProp msgProp = new MessageProp(JGSS_QOP, false);
byte[] answer = secCtx.unwrap(incoming, start, len, msgProp);
if (privacy && !msgProp.getPrivacy()) {
throw new SaslException("Privacy not protected");
}
checkMessageProp("", msgProp);
if (logger.isLoggable(Level.FINEST)) {
traceOutput(myClassName, "KRB501:Unwrap", "incoming: ",
incoming, start, len);
traceOutput(myClassName, "KRB502:Unwrap", "unwrapped: ",
answer, 0, answer.length);
}
return answer;
} catch (GSSException e) {
throw new SaslException("Problems unwrapping SASL buffer", e);
}
}
public byte[] wrap(byte[] outgoing, int start, int len) throws SaslException {
if (!completed) {
throw new IllegalStateException("GSSAPI authentication not completed");
}
// integrity will be true if either privacy or integrity negotiated
if (!integrity) {
throw new IllegalStateException("No security layer negotiated");
}
// Generate GSS token
try {
MessageProp msgProp = new MessageProp(JGSS_QOP, privacy);
byte[] answer = secCtx.wrap(outgoing, start, len, msgProp);
if (logger.isLoggable(Level.FINEST)) {
traceOutput(myClassName, "KRB503:Wrap", "outgoing: ",
outgoing, start, len);
traceOutput(myClassName, "KRB504:Wrap", "wrapped: ",
answer, 0, answer.length);
}
return answer;
} catch (GSSException e) {
throw new SaslException("Problem performing GSS wrap", e);
}
}
public void dispose() throws SaslException {
if (secCtx != null) {
try {
secCtx.dispose();
} catch (GSSException e) {
throw new SaslException("Problem disposing GSS context", e);
}
secCtx = null;
}
}
protected void finalize() throws Throwable {
dispose();
}
void checkMessageProp(String label, MessageProp msgProp)
throws SaslException {
if (msgProp.isDuplicateToken()) {
throw new SaslException(label + "Duplicate token");
}
if (msgProp.isGapToken()) {
throw new SaslException(label + "Gap token");
}
if (msgProp.isOldToken()) {
throw new SaslException(label + "Old token");
}
if (msgProp.isUnseqToken()) {
throw new SaslException(label + "Token not in sequence");
}
}
}

View File

@@ -0,0 +1,331 @@
/*
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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.
*/
package com.sun.security.sasl.gsskerb;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Level;
import javax.security.sasl.*;
// JAAS
import javax.security.auth.callback.CallbackHandler;
// JGSS
import org.ietf.jgss.*;
/**
* Implements the GSSAPI SASL client 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-04.txt">draft-ietf-cat-sasl-gssapi-04.txt</a>).
* It uses the Java Bindings for GSSAPI
* (<A HREF="http://www.ietf.org/rfc/rfc2853.txt">RFC 2853</A>)
* for getting GSSAPI/Kerberos V5 support.
*
* The client/server interactions are:
* C0: bind (GSSAPI, initial response)
* S0: sasl-bind-in-progress, challenge 1 (output of accept_sec_context or [])
* C1: bind (GSSAPI, response 1 (output of init_sec_context or []))
* S1: sasl-bind-in-progress challenge 2 (security layer, server max recv size)
* C2: bind (GSSAPI, response 2 (security layer, client max recv size, authzid))
* S2: bind success response
*
* Expects the client's credentials to be supplied from the
* javax.security.sasl.credentials property or from the thread's Subject.
* Otherwise the underlying KRB5 mech will attempt to acquire Kerberos creds
* by logging into Kerberos (via default TextCallbackHandler).
* These creds will be used for exchange with server.
*
* Required callbacks: none.
*
* 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 server max recv size)
*
* javax.security.sasl.server.authentication
* - "true" means require mutual authentication; default is "false"
*
* javax.security.sasl.credentials
* - an {@link org.ietf.jgss.GSSCredential} used for delegated authentication.
*
* @author Rosanna Lee
*/
final class GssKrb5Client extends GssKrb5Base implements SaslClient {
// ---------------- Constants -----------------
private static final String MY_CLASS_NAME = GssKrb5Client.class.getName();
private boolean finalHandshake = false;
private boolean mutual = false; // default false
private byte[] authzID;
/**
* Creates a SASL mechanism with client credentials that it needs
* to participate in GSS-API/Kerberos v5 authentication exchange
* with the server.
*/
GssKrb5Client(String authzID, String protocol, String serverName,
Map<String, ?> props, CallbackHandler cbh) throws SaslException {
super(props, MY_CLASS_NAME);
String service = protocol + "@" + serverName;
logger.log(Level.FINE, "KRB5CLNT01:Requesting service name: {0}",
service);
try {
GSSManager mgr = GSSManager.getInstance();
// Create the name for the requested service entity for Krb5 mech
GSSName acceptorName = mgr.createName(service,
GSSName.NT_HOSTBASED_SERVICE, KRB5_OID);
// Parse properties to check for supplied credentials
GSSCredential credentials = null;
if (props != null) {
Object prop = props.get(Sasl.CREDENTIALS);
if (prop != null && prop instanceof GSSCredential) {
credentials = (GSSCredential) prop;
logger.log(Level.FINE,
"KRB5CLNT01:Using the credentials supplied in " +
"javax.security.sasl.credentials");
}
}
// Create a context using credentials for Krb5 mech
secCtx = mgr.createContext(acceptorName,
KRB5_OID, /* mechanism */
credentials, /* credentials */
GSSContext.INDEFINITE_LIFETIME);
// Request credential delegation when credentials have been supplied
if (credentials != null) {
secCtx.requestCredDeleg(true);
}
// Parse properties to set desired context options
if (props != null) {
// Mutual authentication
String prop = (String)props.get(Sasl.SERVER_AUTH);
if (prop != null) {
mutual = "true".equalsIgnoreCase(prop);
}
}
secCtx.requestMutualAuth(mutual);
// Always specify potential need for integrity and confidentiality
// Decision will be made during final handshake
secCtx.requestConf(true);
secCtx.requestInteg(true);
} catch (GSSException e) {
throw new SaslException("Failure to initialize security context", e);
}
if (authzID != null && authzID.length() > 0) {
try {
this.authzID = authzID.getBytes("UTF8");
} catch (IOException e) {
throw new SaslException("Cannot encode authorization ID", e);
}
}
}
public boolean hasInitialResponse() {
return true;
}
/**
* Processes the challenge data.
*
* The server sends a challenge data using which the client must
* process using GSS_Init_sec_context.
* As per RFC 2222, when GSS_S_COMPLETE is returned, we do
* an extra handshake to determine the negotiated security protection
* and buffer sizes.
*
* @param challengeData A non-null byte array containing the
* challenge data from the server.
* @return A non-null byte array containing the response to be
* sent to the server.
*/
public byte[] evaluateChallenge(byte[] challengeData) throws SaslException {
if (completed) {
throw new IllegalStateException(
"GSSAPI authentication already complete");
}
if (finalHandshake) {
return doFinalHandshake(challengeData);
} else {
// Security context not established yet; continue with init
try {
byte[] gssOutToken = secCtx.initSecContext(challengeData,
0, challengeData.length);
if (logger.isLoggable(Level.FINER)) {
traceOutput(MY_CLASS_NAME, "evaluteChallenge",
"KRB5CLNT02:Challenge: [raw]", challengeData);
traceOutput(MY_CLASS_NAME, "evaluateChallenge",
"KRB5CLNT03:Response: [after initSecCtx]", gssOutToken);
}
if (secCtx.isEstablished()) {
finalHandshake = true;
if (gssOutToken == null) {
// RFC 2222 7.2.1: Client responds with no data
return EMPTY;
}
}
return gssOutToken;
} catch (GSSException e) {
throw new SaslException("GSS initiate failed", e);
}
}
}
private byte[] doFinalHandshake(byte[] challengeData) throws SaslException {
try {
// Security context already established. challengeData
// should contain security layers and server's maximum buffer size
if (logger.isLoggable(Level.FINER)) {
traceOutput(MY_CLASS_NAME, "doFinalHandshake",
"KRB5CLNT04:Challenge [raw]:", challengeData);
}
if (challengeData.length == 0) {
// Received S0, should return []
return EMPTY;
}
// Received S1 (security layer, server max recv size)
MessageProp msgProp = new MessageProp(false);
byte[] gssOutToken = secCtx.unwrap(challengeData, 0,
challengeData.length, msgProp);
checkMessageProp("Handshake failure: ", msgProp);
// First octet is a bit-mask specifying the protections
// supported by the server
if (logger.isLoggable(Level.FINE)) {
if (logger.isLoggable(Level.FINER)) {
traceOutput(MY_CLASS_NAME, "doFinalHandshake",
"KRB5CLNT05:Challenge [unwrapped]:", gssOutToken);
}
logger.log(Level.FINE, "KRB5CLNT06:Server protections: {0}",
new Byte(gssOutToken[0]));
}
// Client selects preferred protection
// qop is ordered list of qop values
byte selectedQop = findPreferredMask(gssOutToken[0], qop);
if (selectedQop == 0) {
throw new SaslException(
"No common protection layer between client and server");
}
if ((selectedQop&PRIVACY_PROTECTION) != 0) {
privacy = true;
integrity = true;
} else if ((selectedQop&INTEGRITY_ONLY_PROTECTION) != 0) {
integrity = true;
}
// 2nd-4th octets specifies maximum buffer size expected by
// server (in network byte order)
int srvMaxBufSize = networkByteOrderToInt(gssOutToken, 1, 3);
// Determine the max send buffer size based on what the
// server is able to receive and our specified max
sendMaxBufSize = (sendMaxBufSize == 0) ? srvMaxBufSize :
Math.min(sendMaxBufSize, srvMaxBufSize);
// Update context to limit size of returned buffer
rawSendSize = secCtx.getWrapSizeLimit(JGSS_QOP, privacy,
sendMaxBufSize);
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"KRB5CLNT07:Client max recv size: {0}; server max recv size: {1}; rawSendSize: {2}",
new Object[] {new Integer(recvMaxBufSize),
new Integer(srvMaxBufSize),
new Integer(rawSendSize)});
}
// Construct negotiated security layers and client's max
// receive buffer size and authzID
int len = 4;
if (authzID != null) {
len += authzID.length;
}
byte[] gssInToken = new byte[len];
gssInToken[0] = selectedQop;
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"KRB5CLNT08:Selected protection: {0}; privacy: {1}; integrity: {2}",
new Object[]{new Byte(selectedQop),
Boolean.valueOf(privacy),
Boolean.valueOf(integrity)});
}
intToNetworkByteOrder(recvMaxBufSize, gssInToken, 1, 3);
if (authzID != null) {
// copy authorization id
System.arraycopy(authzID, 0, gssInToken, 4, authzID.length);
logger.log(Level.FINE, "KRB5CLNT09:Authzid: {0}", authzID);
}
if (logger.isLoggable(Level.FINER)) {
traceOutput(MY_CLASS_NAME, "doFinalHandshake",
"KRB5CLNT10:Response [raw]", gssInToken);
}
gssOutToken = secCtx.wrap(gssInToken,
0, gssInToken.length,
new MessageProp(0 /* qop */, false /* privacy */));
if (logger.isLoggable(Level.FINER)) {
traceOutput(MY_CLASS_NAME, "doFinalHandshake",
"KRB5CLNT11:Response [after wrap]", gssOutToken);
}
completed = true; // server authenticated
return gssOutToken;
} catch (GSSException e) {
throw new SaslException("Final handshake failed", e);
}
}
}

View File

@@ -0,0 +1,367 @@
/*
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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.
*/
package com.sun.security.sasl.gsskerb;
import javax.security.sasl.*;
import java.io.*;
import java.util.Map;
import java.util.logging.Level;
// JAAS
import javax.security.auth.callback.*;
// JGSS
import org.ietf.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
* handler must verify that authid/authzids are allowed and set
* 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
*/
final class GssKrb5Server extends GssKrb5Base implements SaslServer {
private static final String MY_CLASS_NAME = GssKrb5Server.class.getName();
private int handshakeStage = 0;
private String peer;
private String me;
private String authzid;
private CallbackHandler cbh;
// When serverName is null, the server will be unbound. We need to save and
// check the protocol name after the context is established. This value
// will be null if serverName is not null.
private final String protocolSaved;
/**
* Creates a SASL mechanism with server credentials that it needs
* to participate in GSS-API/Kerberos v5 authentication exchange
* with the client.
*/
GssKrb5Server(String protocol, String serverName,
Map<String, ?> props, CallbackHandler cbh) throws SaslException {
super(props, MY_CLASS_NAME);
this.cbh = cbh;
String service;
if (serverName == null) {
protocolSaved = protocol;
service = null;
} else {
protocolSaved = null;
service = protocol + "@" + serverName;
}
logger.log(Level.FINE, "KRB5SRV01:Using service name: {0}", service);
try {
GSSManager mgr = GSSManager.getInstance();
// Create the name for the requested service entity for Krb5 mech
GSSName serviceName = service == null ? null:
mgr.createName(service, GSSName.NT_HOSTBASED_SERVICE, KRB5_OID);
GSSCredential cred = mgr.createCredential(serviceName,
GSSCredential.INDEFINITE_LIFETIME,
KRB5_OID, GSSCredential.ACCEPT_ONLY);
// Create a context using the server's credentials
secCtx = mgr.createContext(cred);
if ((allQop&INTEGRITY_ONLY_PROTECTION) != 0) {
// Might need integrity
secCtx.requestInteg(true);
}
if ((allQop&PRIVACY_PROTECTION) != 0) {
// Might need privacy
secCtx.requestConf(true);
}
} catch (GSSException e) {
throw new SaslException("Failure to initialize security context", e);
}
logger.log(Level.FINE, "KRB5SRV02:Initialization complete");
}
/**
* 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.
*/
public byte[] evaluateResponse(byte[] responseData) throws SaslException {
if (completed) {
throw new SaslException(
"SASL authentication already complete");
}
if (logger.isLoggable(Level.FINER)) {
traceOutput(MY_CLASS_NAME, "evaluateResponse",
"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 {
byte[] gssOutToken = secCtx.acceptSecContext(responseData,
0, responseData.length);
if (logger.isLoggable(Level.FINER)) {
traceOutput(MY_CLASS_NAME, "evaluateResponse",
"KRB5SRV04:Challenge: [after acceptSecCtx]", gssOutToken);
}
if (secCtx.isEstablished()) {
handshakeStage = 1;
peer = secCtx.getSrcName().toString();
me = secCtx.getTargName().toString();
logger.log(Level.FINE,
"KRB5SRV05:Peer name is : {0}, my name is : {1}",
new Object[]{peer, me});
// me might take the form of proto@host or proto/host
if (protocolSaved != null &&
!protocolSaved.equalsIgnoreCase(me.split("[/@]")[0])) {
throw new SaslException(
"GSS context targ name protocol error: " + me);
}
if (gssOutToken == null) {
return doHandshake1(EMPTY);
}
}
return gssOutToken;
} catch (GSSException e) {
throw new SaslException("GSS initiate failed", e);
}
}
}
private byte[] doHandshake1(byte[] responseData) throws SaslException {
try {
// Security context already established. responseData
// should contain no data
if (responseData != null && responseData.length > 0) {
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];
gssInToken[0] = allQop;
intToNetworkByteOrder(recvMaxBufSize, gssInToken, 1, 3);
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"KRB5SRV06:Supported protections: {0}; recv max buf size: {1}",
new Object[]{new Byte(allQop),
new Integer(recvMaxBufSize)});
}
handshakeStage = 2; // progress to next stage
if (logger.isLoggable(Level.FINER)) {
traceOutput(MY_CLASS_NAME, "doHandshake1",
"KRB5SRV07:Challenge [raw]", gssInToken);
}
byte[] gssOutToken = secCtx.wrap(gssInToken, 0, gssInToken.length,
new MessageProp(0 /* gop */, false /* privacy */));
if (logger.isLoggable(Level.FINER)) {
traceOutput(MY_CLASS_NAME, "doHandshake1",
"KRB5SRV08:Challenge [after wrap]", gssOutToken);
}
return gssOutToken;
} catch (GSSException e) {
throw new SaslException("Problem wrapping handshake1", e);
}
}
private byte[] doHandshake2(byte[] responseData) throws SaslException {
try {
// Expecting 4 octets from client selected protection
// and client's receive buffer size
MessageProp msgProp = new MessageProp(false);
byte[] gssOutToken = secCtx.unwrap(responseData, 0,
responseData.length, msgProp);
checkMessageProp("Handshake failure: ", msgProp);
if (logger.isLoggable(Level.FINER)) {
traceOutput(MY_CLASS_NAME, "doHandshake2",
"KRB5SRV09:Response [after unwrap]", gssOutToken);
}
// First octet is a bit-mask specifying the selected protection
byte selectedQop = gssOutToken[0];
if ((selectedQop&allQop) == 0) {
throw new SaslException("Client selected unsupported protection: "
+ selectedQop);
}
if ((selectedQop&PRIVACY_PROTECTION) != 0) {
privacy = true;
integrity = true;
} else if ((selectedQop&INTEGRITY_ONLY_PROTECTION) != 0) {
integrity = true;
}
// 2nd-4th octets specifies maximum buffer size expected by
// client (in network byte order). This is the server's send
// buffer maximum.
int clntMaxBufSize = networkByteOrderToInt(gssOutToken, 1, 3);
// Determine the max send buffer size based on what the
// client is able to receive and our specified max
sendMaxBufSize = (sendMaxBufSize == 0) ? clntMaxBufSize :
Math.min(sendMaxBufSize, clntMaxBufSize);
// Update context to limit size of returned buffer
rawSendSize = secCtx.getWrapSizeLimit(JGSS_QOP, privacy,
sendMaxBufSize);
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"KRB5SRV10:Selected protection: {0}; privacy: {1}; integrity: {2}",
new Object[]{new Byte(selectedQop),
Boolean.valueOf(privacy),
Boolean.valueOf(integrity)});
logger.log(Level.FINE,
"KRB5SRV11:Client max recv size: {0}; server max send size: {1}; rawSendSize: {2}",
new Object[] {new Integer(clntMaxBufSize),
new Integer(sendMaxBufSize),
new Integer(rawSendSize)});
}
// Get authorization identity, if any
if (gssOutToken.length > 4) {
try {
authzid = new String(gssOutToken, 4,
gssOutToken.length - 4, "UTF-8");
} catch (UnsupportedEncodingException uee) {
throw new SaslException ("Cannot decode authzid", uee);
}
} else {
authzid = peer;
}
logger.log(Level.FINE, "KRB5SRV12:Authzid: {0}", authzid);
AuthorizeCallback acb = new AuthorizeCallback(peer, authzid);
// In Kerberos, realm is embedded in peer name
cbh.handle(new Callback[] {acb});
if (acb.isAuthorized()) {
authzid = acb.getAuthorizedID();
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);
}
}
public String getAuthorizationID() {
if (completed) {
return authzid;
} else {
throw new IllegalStateException("Authentication incomplete");
}
}
public Object getNegotiatedProperty(String propName) {
if (!completed) {
throw new IllegalStateException("Authentication incomplete");
}
Object result;
switch (propName) {
case Sasl.BOUND_SERVER_NAME:
try {
// me might take the form of proto@host or proto/host
result = me.split("[/@]")[1];
} catch (Exception e) {
result = null;
}
break;
default:
result = super.getNegotiatedProperty(propName);
}
return result;
}
}