All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sshtools.client.KeyboardInteractiveAuthenticator Maven / Gradle / Ivy

package com.sshtools.client;

/*-
 * #%L
 * Client API
 * %%
 * Copyright (C) 2002 - 2024 JADAPTIVE Limited
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.io.IOException;
import java.nio.ByteBuffer;

import com.sshtools.common.logger.Log;
import com.sshtools.common.util.ByteArrayReader;
import com.sshtools.common.util.ByteArrayWriter;
import com.sshtools.synergy.ssh.ByteArrayMessage;
import com.sshtools.synergy.ssh.ConnectionTaskWrapper;
import com.sshtools.synergy.ssh.TransportProtocol;

/**
 * Implements the keyboard-interactive authentication method.
 */
public class KeyboardInteractiveAuthenticator extends SimpleClientAuthenticator implements ClientAuthenticator {

	
	final static int SSH_MSG_USERAUTH_INFO_REQUEST = 60;
	final static int SSH_MSG_USERAUTH_INFO_RESPONSE = 61;
	
	KeyboardInteractiveCallback callback;
	TransportProtocolClient transport;
	String username;
	boolean completeFutureOnFailure = true;
	
	public KeyboardInteractiveAuthenticator(KeyboardInteractiveCallback callback) {
		this.callback = callback;
	}
	
	@Override
	public void authenticate(TransportProtocolClient transport, String username) {
		
		this.transport = transport;
		this.username = username;
		
		callback.init(transport.getConnection());
		
		transport.postMessage(new AuthenticationMessage(username, "ssh-connection", "keyboard-interactive") {

			@Override
			public boolean writeMessageIntoBuffer(ByteBuffer buf) {
				super.writeMessageIntoBuffer(buf);
				buf.putInt(0);
				buf.putInt(0);
				
				return true;
			}
			
		});
	}
	
	@Override
	public boolean processMessage(ByteArrayReader msg) throws IOException {
		
		switch(msg.read()) {
		case SSH_MSG_USERAUTH_INFO_REQUEST:
			
			if(Log.isDebugEnabled()) {
				Log.debug("SSH_MSG_USERAUTH_INFO_REQUEST received");
			}
			
			final String name = msg.readString();
			final String instruction = msg.readString();
			@SuppressWarnings("unused")
			String langtag = msg.readString();

			int num = (int) msg.readInt();
			String prompt;
			boolean echo;
			final KeyboardInteractivePrompt[] prompts = new KeyboardInteractivePrompt[num];
			for (int i = 0; i < num; i++) {
				prompt = msg.readString();
				echo = (msg.read() == 1);
				prompts[i] = new KeyboardInteractivePrompt(prompt, echo);
			}

			transport.addTask(TransportProtocol.CALLBACKS, new ConnectionTaskWrapper(transport.getConnection(), new Runnable() {
				public void run() {
					callback.showPrompts(name, instruction, prompts, new KeyboardInteractivePromptCompletor() {
						@Override
						public void complete() {
							
							ByteArrayWriter baw = new ByteArrayWriter();
							
							try {
								
								baw.write(SSH_MSG_USERAUTH_INFO_RESPONSE);
								baw.writeInt(prompts.length);

								for (int i = 0; i < prompts.length; i++) {
									baw.writeString(prompts[i].getResponse());
								}
								
								transport.postMessage(new ByteArrayMessage(baw.toByteArray()) {
									@Override
									public void messageSent(Long sequenceNo) {
										if(Log.isDebugEnabled()) {
											Log.debug("SSH_MSG_USERAUTH_INFO_RESPONSE sent");
										}
									}
									
								});
							} catch (IOException e) {
								Log.error("Error during showPrompts", e);
								failure();
								transport.disconnect(TransportProtocol.AUTH_CANCELLED_BY_USER, "User cancelled auth.");
							} finally {
								try {
									baw.close();
								} catch (IOException e) {
								}
							}
						}
						
						@Override
						public void cancel() {
							KeyboardInteractiveAuthenticator.this.cancel();
							failure();
							transport.disconnect(TransportProtocol.AUTH_CANCELLED_BY_USER, "User cancelled auth.");
						}
						
					});
				}
			}));
			

			return true;
		}
		return false;
	}

	@Override
	public String getName() {
		return "keyboard-interactive";
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy