/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.sshd.server.auth.keyboard;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.sshd.common.RuntimeSshException;
import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.server.auth.AbstractUserAuth;
import org.apache.sshd.server.session.ServerSession;
/**
* Issue a "keyboard-interactive" command according to <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class UserAuthKeyboardInteractive extends AbstractUserAuth {
public static final String NAME = UserAuthKeyboardInteractiveFactory.NAME;
public UserAuthKeyboardInteractive() {
super(NAME);
}
@Override
protected Boolean doAuth(Buffer buffer, boolean init) throws Exception {
ServerSession session = getServerSession();
String username = getUsername();
KeyboardInteractiveAuthenticator auth = session.getKeyboardInteractiveAuthenticator();
if (init) {
String lang = buffer.getString();
String subMethods = buffer.getString();
if (auth == null) {
if (log.isDebugEnabled()) {
log.debug("doAuth({}@{})[methods={}, lang={}] - no interactive authenticator to generate challenge",
username, session, subMethods, lang);
}
return false;
}
InteractiveChallenge challenge;
try {
challenge = auth.generateChallenge(session, username, lang, subMethods);
} catch (Error e) {
log.warn("doAuth({}@{}) failed ({}) to generate authenticator challenge: {}",
username, session, e.getClass().getSimpleName(), e.getMessage());
if (log.isDebugEnabled()) {
log.debug("doAuth(" + username + "@" + session + ") authenticator challenge failure details", e);
}
throw new RuntimeSshException(e);
}
if (challenge == null) {
if (log.isDebugEnabled()) {
log.debug("doAuth({}@{})[methods={}, lang={}] - no interactive challenge generated",
username, session, subMethods, lang);
}
return false;
}
if (log.isDebugEnabled()) {
log.debug("doAuth({}@{})[methods={}, lang={}] challenge name={}, instruction={}, lang={}, num. prompts={}",
username, session, subMethods, lang,
challenge.getInteractionName(), challenge.getInteractionInstruction(),
challenge.getLanguageTag(), GenericUtils.size(challenge.getPrompts()));
}
// Prompt for password
buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST);
challenge.append(buffer);
session.writePacket(buffer);
return null;
} else {
int cmd = buffer.getUByte();
if (cmd != SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE) {
throw new SshException("Received unexpected message: " + SshConstants.getCommandMessageName(cmd));
}
int num = buffer.getInt();
List<String> responses = (num <= 0) ? Collections.emptyList() : new ArrayList<>(num);
for (int index = 0; index < num; index++) {
String value = buffer.getString();
if (log.isTraceEnabled()) {
log.trace("doAuth({}@{}) response #{}: {}", username, session, index + 1, value);
}
responses.add(value);
}
if (auth == null) {
if (log.isDebugEnabled()) {
log.debug("doAuth({}@{}) no interactive authenticator to validate {} responses",
username, session, num);
}
return false;
}
boolean authed;
try {
authed = auth.authenticate(session, username, responses);
} catch (Error e) {
log.warn("doAuth({}@{}) failed ({}) to consult authenticator: {}",
username, session, e.getClass().getSimpleName(), e.getMessage());
if (log.isDebugEnabled()) {
log.debug("doAuth(" + username + "@" + session + ") authenticator consultation failure details", e);
}
throw new RuntimeSshException(e);
}
if (log.isDebugEnabled()) {
log.debug("doAuth({}@{}) authenticate {} responses result: {}",
username, session, num, authed);
}
return authed;
}
}
}