in sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java [67:193]
protected Boolean doAuth(Buffer buffer, boolean initial) throws Exception {
ServerSession session = getServerSession();
GSSAuthenticator auth = Objects.requireNonNull(session.getGSSAuthenticator(), "No GSSAuthenticator configured");
String user = getUsername();
boolean debugEnabled = log.isDebugEnabled();
if (initial) {
// Get mechanism count from buffer and look for Kerberos 5.
int num = buffer.getInt();
// Protect against malicious or corrupted packets
if ((num < 0) || (num > SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT)) {
log.error("doAuth({}@{}) Illogical OID entries count: {}", user, session, num);
throw new IndexOutOfBoundsException("Illogical OID entries count: " + num);
}
boolean traceEnabled = log.isTraceEnabled();
for (int i = 1; i <= num; i++) {
Oid oid = new Oid(buffer.getBytes());
if (!oid.equals(KRB5_MECH)) {
if (traceEnabled) {
log.trace("doAuth({}@{}) skip OID {}/{}: {}", user, session, i, num, oid);
}
continue;
}
if (debugEnabled) {
log.debug("doAuth({}@{}) found Kerberos 5 after {}/{} OID(s)", user, session, i, num);
}
// Validate initial user before proceeding
if (!auth.validateInitialUser(session, user)) {
return Boolean.FALSE;
}
GSSManager mgr = auth.getGSSManager();
GSSCredential creds = auth.getGSSCredential(mgr);
if (creds == null) {
return Boolean.FALSE;
}
context = mgr.createContext(creds);
// Send the matching mechanism back to the client
byte[] out = oid.getDER();
Buffer b = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST, out.length + Integer.SIZE);
b.putBytes(out);
session.writePacket(b);
return null;
}
// No matching mechanism found
return Boolean.FALSE;
} else {
int msg = buffer.getUByte();
if (!((msg == SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE)
|| ((msg == SshConstants.SSH_MSG_USERAUTH_GSSAPI_MIC) && context.isEstablished()))) {
throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR,
"Packet not supported by user authentication method: " + SshConstants.getCommandMessageName(msg));
}
if (debugEnabled) {
log.debug("doAuth({}@{}) In krb5.next: msg = {}", user, session, SshConstants.getCommandMessageName(msg));
}
// If the context is established, this must be a MIC message
if (context.isEstablished()) {
if (msg != SshConstants.SSH_MSG_USERAUTH_GSSAPI_MIC) {
return Boolean.FALSE;
}
// Make the MIC message so the token can be verified
Buffer msgbuf = new ByteArrayBuffer();
msgbuf.putBytes(ValidateUtils.checkNotNullAndNotEmpty(session.getSessionId(), "No current session ID"));
msgbuf.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
msgbuf.putString(getUsername());
msgbuf.putString(getService());
msgbuf.putString(getName());
byte[] msgbytes = msgbuf.getCompactData();
byte[] inmic = buffer.getBytes();
try {
context.verifyMIC(inmic, 0, inmic.length, msgbytes, 0, msgbytes.length, new MessageProp(false));
if (debugEnabled) {
log.debug("doAuth({}@{}) MIC verified", getUsername(), session);
}
return Boolean.TRUE;
} catch (GSSException e) {
if (debugEnabled) {
log.debug("doAuth({}@{}) GSS verification {} error: {}",
user, session, e.getClass().getSimpleName(), e.getMessage());
}
return Boolean.FALSE;
}
} else {
// Not established - new token to process
byte[] tok = buffer.getBytes();
byte[] out = context.acceptSecContext(tok, 0, tok.length);
boolean established = context.isEstablished();
// Validate identity if context is now established
if (established && (identity == null)) {
GSSName srcName = context.getSrcName();
identity = srcName.toString();
if (debugEnabled) {
log.debug("doAuth({}@{}) GSS identity is {}", user, session, identity);
}
if (!auth.validateIdentity(session, identity)) {
return Boolean.FALSE;
}
}
// Send return token if necessary
if (NumberUtils.length(out) > 0) {
Buffer b = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE, out.length + Integer.SIZE);
b.putBytes(out);
session.writePacket(b);
return null;
} else {
return established;
}
}
}
}