mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 15:20:54 +03:00
userauth/ reformat
This commit is contained in:
@@ -41,15 +41,11 @@ import net.schmizz.sshj.userauth.method.AuthMethod;
|
||||
|
||||
import java.util.Deque;
|
||||
|
||||
/**
|
||||
* User authentication API
|
||||
*
|
||||
* @see rfc4252
|
||||
*/
|
||||
/** User authentication API. See RFC 4252. */
|
||||
public interface UserAuth {
|
||||
|
||||
/**
|
||||
* Attempt to authenticate {@code username} using each of {@link methods} in order. {@code nextService} is the
|
||||
* Attempt to authenticate {@code username} using each of {@code methods} in order. {@code nextService} is the
|
||||
* {@link net.schmizz.sshj.Service} that will be enabled on successful authentication.
|
||||
* <p/>
|
||||
* Authentication fails if there are no method available, i.e. if all the method failed or there were method
|
||||
@@ -66,8 +62,8 @@ public interface UserAuth {
|
||||
* @throws UserAuthException in case of authentication failure
|
||||
* @throws TransportException if there was a transport-layer error
|
||||
*/
|
||||
void authenticate(String username, Service nextService, Iterable<AuthMethod> methods) throws UserAuthException,
|
||||
TransportException;
|
||||
void authenticate(String username, Service nextService, Iterable<AuthMethod> methods)
|
||||
throws UserAuthException, TransportException;
|
||||
|
||||
/**
|
||||
* Returns the authentication banner (if any). In some cases this is available even before the first authentication
|
||||
@@ -77,15 +73,15 @@ public interface UserAuth {
|
||||
*/
|
||||
String getBanner();
|
||||
|
||||
/** Returns saved exceptions that might have been ignored because there were more authentication method available. */
|
||||
/** @return Saved exceptions that might have been ignored because there were more authentication method available. */
|
||||
Deque<UserAuthException> getSavedExceptions();
|
||||
|
||||
/** Returns the {@code timeout} for a method to successfully authenticate before it is abandoned. */
|
||||
/** @return The {@code timeout} for a method to successfully authenticate before it is abandoned. */
|
||||
int getTimeout();
|
||||
|
||||
/**
|
||||
* Returns whether authentication was partially successful. Some server's may be configured to require multiple
|
||||
* authentications; and this value will be {@code true} if at least one of the method supplied succeeded.
|
||||
* @return Whether authentication was partially successful. Some server's may be configured to require multiple
|
||||
* authentications; and this value will be {@code true} if at least one of the method supplied succeeded.
|
||||
*/
|
||||
boolean hadPartialSuccess();
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ import net.schmizz.sshj.common.DisconnectReason;
|
||||
import net.schmizz.sshj.common.SSHException;
|
||||
|
||||
/** User authentication exception */
|
||||
public class UserAuthException extends SSHException {
|
||||
public class UserAuthException
|
||||
extends SSHException {
|
||||
|
||||
public static final ExceptionChainer<UserAuthException> chainer = new ExceptionChainer<UserAuthException>() {
|
||||
|
||||
|
||||
@@ -12,26 +12,6 @@
|
||||
* 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.
|
||||
*
|
||||
* This file may incorporate work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* 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 net.schmizz.sshj.userauth;
|
||||
|
||||
@@ -54,14 +34,16 @@ import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/** {@link UserAuth} implementation. */
|
||||
public class UserAuthImpl extends AbstractService implements UserAuth, AuthParams {
|
||||
public class UserAuthImpl
|
||||
extends AbstractService
|
||||
implements UserAuth, AuthParams {
|
||||
|
||||
private final Set<String> allowed = new HashSet<String>();
|
||||
|
||||
private final Deque<UserAuthException> savedEx = new ArrayDeque<UserAuthException>();
|
||||
|
||||
private final Event<UserAuthException> result = new Event<UserAuthException>("userauth result",
|
||||
UserAuthException.chainer);
|
||||
UserAuthException.chainer);
|
||||
|
||||
private String username;
|
||||
private AuthMethod currentMethod;
|
||||
@@ -158,7 +140,8 @@ public class UserAuthImpl extends AbstractService implements UserAuth, AuthParam
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Message msg, SSHPacket buf) throws SSHException {
|
||||
public void handle(Message msg, SSHPacket buf)
|
||||
throws SSHException {
|
||||
if (!msg.in(50, 80)) // ssh-userauth packets have message numbers between 50-80
|
||||
throw new TransportException(DisconnectReason.PROTOCOL_ERROR);
|
||||
|
||||
@@ -198,7 +181,8 @@ public class UserAuthImpl extends AbstractService implements UserAuth, AuthParam
|
||||
banner = buf.readString();
|
||||
}
|
||||
|
||||
private void gotFailure(SSHPacket buf) throws UserAuthException, TransportException {
|
||||
private void gotFailure(SSHPacket buf)
|
||||
throws UserAuthException, TransportException {
|
||||
allowed.clear();
|
||||
allowed.addAll(Arrays.<String>asList(buf.readString().split(",")));
|
||||
partialSuccess |= buf.readBoolean();
|
||||
@@ -216,7 +200,8 @@ public class UserAuthImpl extends AbstractService implements UserAuth, AuthParam
|
||||
result.set(true);
|
||||
}
|
||||
|
||||
private void gotUnknown(Message msg, SSHPacket buf) throws SSHException {
|
||||
private void gotUnknown(Message msg, SSHPacket buf)
|
||||
throws SSHException {
|
||||
if (currentMethod == null || result == null) {
|
||||
trans.sendUnimplemented();
|
||||
return;
|
||||
@@ -239,7 +224,8 @@ public class UserAuthImpl extends AbstractService implements UserAuth, AuthParam
|
||||
savedEx.push(e);
|
||||
}
|
||||
|
||||
private boolean tryWith(AuthMethod meth) throws UserAuthException, TransportException {
|
||||
private boolean tryWith(AuthMethod meth)
|
||||
throws UserAuthException, TransportException {
|
||||
currentMethod = meth;
|
||||
result.clear();
|
||||
meth.init(this);
|
||||
|
||||
@@ -40,10 +40,13 @@ import net.schmizz.sshj.userauth.password.PasswordFinder;
|
||||
import java.io.File;
|
||||
|
||||
/** A file key provider is initialized with a location of */
|
||||
public interface FileKeyProvider extends KeyProvider {
|
||||
public interface FileKeyProvider
|
||||
extends KeyProvider {
|
||||
|
||||
enum Format {
|
||||
PKCS8, OpenSSH, Unknown
|
||||
PKCS8,
|
||||
OpenSSH,
|
||||
Unknown
|
||||
}
|
||||
|
||||
void init(File location);
|
||||
|
||||
@@ -42,7 +42,8 @@ import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
/** A {@link KeyProvider} wrapper around {@link java.security.KeyPair} */
|
||||
public class KeyPairWrapper implements KeyProvider {
|
||||
public class KeyPairWrapper
|
||||
implements KeyProvider {
|
||||
|
||||
private final KeyPair kp;
|
||||
private final KeyType type;
|
||||
|
||||
@@ -45,12 +45,15 @@ import java.security.PublicKey;
|
||||
public interface KeyProvider {
|
||||
|
||||
/** Returns the private key. */
|
||||
PrivateKey getPrivate() throws IOException;
|
||||
PrivateKey getPrivate()
|
||||
throws IOException;
|
||||
|
||||
/** Returns the public key. */
|
||||
PublicKey getPublic() throws IOException;
|
||||
PublicKey getPublic()
|
||||
throws IOException;
|
||||
|
||||
/** Returns the {@link KeyType}. */
|
||||
KeyType getType() throws IOException;
|
||||
KeyType getType()
|
||||
throws IOException;
|
||||
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@ public class KeyProviderUtil {
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public static FileKeyProvider.Format detectKeyFileFormat(File location) throws IOException {
|
||||
public static FileKeyProvider.Format detectKeyFileFormat(File location)
|
||||
throws IOException {
|
||||
BufferedReader br = new BufferedReader(new FileReader(location));
|
||||
String firstLine = br.readLine();
|
||||
IOUtils.closeQuietly(br);
|
||||
@@ -51,7 +52,7 @@ public class KeyProviderUtil {
|
||||
/*
|
||||
* TODO: Tectia, PuTTY (.ppk) ...
|
||||
*/
|
||||
return FileKeyProvider.Format.OpenSSH;
|
||||
return FileKeyProvider.Format.Unknown;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,9 +52,11 @@ import java.security.PublicKey;
|
||||
*
|
||||
* @see PKCS8KeyFile
|
||||
*/
|
||||
public class OpenSSHKeyFile extends PKCS8KeyFile {
|
||||
public class OpenSSHKeyFile
|
||||
extends PKCS8KeyFile {
|
||||
|
||||
public static class Factory implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
||||
public static class Factory
|
||||
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
||||
|
||||
public FileKeyProvider create() {
|
||||
return new OpenSSHKeyFile();
|
||||
@@ -68,7 +70,8 @@ public class OpenSSHKeyFile extends PKCS8KeyFile {
|
||||
private PublicKey pubKey;
|
||||
|
||||
@Override
|
||||
public PublicKey getPublic() throws IOException {
|
||||
public PublicKey getPublic()
|
||||
throws IOException {
|
||||
return pubKey != null ? pubKey : super.getPublic();
|
||||
}
|
||||
|
||||
|
||||
@@ -55,9 +55,11 @@ import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
/** Represents a PKCS8-encoded key file. This is the format used by OpenSSH and OpenSSL. */
|
||||
public class PKCS8KeyFile implements FileKeyProvider {
|
||||
public class PKCS8KeyFile
|
||||
implements FileKeyProvider {
|
||||
|
||||
public static class Factory implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
||||
public static class Factory
|
||||
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
||||
public FileKeyProvider create() {
|
||||
return new PKCS8KeyFile();
|
||||
}
|
||||
@@ -77,15 +79,18 @@ public class PKCS8KeyFile implements FileKeyProvider {
|
||||
|
||||
protected char[] passphrase; // for blanking out
|
||||
|
||||
public PrivateKey getPrivate() throws IOException {
|
||||
public PrivateKey getPrivate()
|
||||
throws IOException {
|
||||
return kp != null ? kp.getPrivate() : (kp = readKeyPair()).getPrivate();
|
||||
}
|
||||
|
||||
public PublicKey getPublic() throws IOException {
|
||||
public PublicKey getPublic()
|
||||
throws IOException {
|
||||
return kp != null ? kp.getPublic() : (kp = readKeyPair()).getPublic();
|
||||
}
|
||||
|
||||
public KeyType getType() throws IOException {
|
||||
public KeyType getType()
|
||||
throws IOException {
|
||||
return type != null ? type : (type = KeyType.fromKey(getPublic()));
|
||||
}
|
||||
|
||||
@@ -111,7 +116,8 @@ public class PKCS8KeyFile implements FileKeyProvider {
|
||||
};
|
||||
}
|
||||
|
||||
protected KeyPair readKeyPair() throws IOException {
|
||||
protected KeyPair readKeyPair()
|
||||
throws IOException {
|
||||
KeyPair kp = null;
|
||||
org.bouncycastle.openssl.PasswordFinder pFinder = makeBouncyPasswordFinder();
|
||||
PEMReader r = null;
|
||||
|
||||
@@ -44,14 +44,15 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/** This abstract class for {@link AuthMethod} implements common or default functionality. */
|
||||
public abstract class AbstractAuthMethod implements AuthMethod {
|
||||
public abstract class AbstractAuthMethod
|
||||
implements AuthMethod {
|
||||
|
||||
/** Logger */
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final String name;
|
||||
|
||||
/** {@link net.schmizz.sshj.userauth.AuthParams} useful for building request. */
|
||||
/** {@link AuthParams} useful for building request. */
|
||||
protected AuthParams params;
|
||||
|
||||
/** Create with the {@code name} of this authentication method. */
|
||||
@@ -63,7 +64,8 @@ public abstract class AbstractAuthMethod implements AuthMethod {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void handle(Message msg, SSHPacket buf) throws UserAuthException, TransportException {
|
||||
public void handle(Message msg, SSHPacket buf)
|
||||
throws UserAuthException, TransportException {
|
||||
throw new UserAuthException("Unknown packet received during " + getName() + " auth: " + msg);
|
||||
}
|
||||
|
||||
@@ -71,7 +73,8 @@ public abstract class AbstractAuthMethod implements AuthMethod {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public void request() throws UserAuthException, TransportException {
|
||||
public void request()
|
||||
throws UserAuthException, TransportException {
|
||||
params.getTransport().write(buildReq());
|
||||
}
|
||||
|
||||
@@ -80,10 +83,11 @@ public abstract class AbstractAuthMethod implements AuthMethod {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link net.schmizz.sshj.common.SSHPacket} containing the fields common to all authentication method.
|
||||
* Method-specific fields can further be put into this buffer.
|
||||
* Builds a {@link SSHPacket} containing the fields common to all authentication method. Method-specific fields can
|
||||
* further be put into this buffer.
|
||||
*/
|
||||
protected SSHPacket buildReq() throws UserAuthException {
|
||||
protected SSHPacket buildReq()
|
||||
throws UserAuthException {
|
||||
return new SSHPacket(Message.USERAUTH_REQUEST) // SSH_MSG_USERAUTH_REQUEST
|
||||
.putString(params.getUsername()) // username goes first
|
||||
.putString(params.getNextServiceName()) // the service that we'd like on success
|
||||
|
||||
@@ -42,7 +42,8 @@ import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
|
||||
// TODO check if this even works...!
|
||||
|
||||
/** Implements the {@code hostbased} SSH authentication method. */
|
||||
public class AuthHostbased extends KeyedAuthMethod {
|
||||
public class AuthHostbased
|
||||
extends KeyedAuthMethod {
|
||||
|
||||
protected final String hostname;
|
||||
protected final String hostuser;
|
||||
@@ -59,7 +60,8 @@ public class AuthHostbased extends KeyedAuthMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SSHPacket buildReq() throws UserAuthException {
|
||||
protected SSHPacket buildReq()
|
||||
throws UserAuthException {
|
||||
SSHPacket req = putPubKey(super.buildReq());
|
||||
req.putString(hostname == null ? params.getTransport().getRemoteHost() : hostname) //
|
||||
.putString(hostuser);
|
||||
|
||||
@@ -45,7 +45,8 @@ import net.schmizz.sshj.userauth.UserAuthException;
|
||||
*
|
||||
* @see net.schmizz.sshj.userauth.UserAuth
|
||||
*/
|
||||
public interface AuthMethod extends SSHPacketHandler {
|
||||
public interface AuthMethod
|
||||
extends SSHPacketHandler {
|
||||
|
||||
/** Returns assigned name of this authentication method */
|
||||
String getName();
|
||||
@@ -61,7 +62,8 @@ public interface AuthMethod extends SSHPacketHandler {
|
||||
*
|
||||
* @throws TransportException
|
||||
*/
|
||||
void request() throws UserAuthException, TransportException;
|
||||
void request()
|
||||
throws UserAuthException, TransportException;
|
||||
|
||||
/** Returns whether authentication should be reattempted if it failed. */
|
||||
boolean shouldRetry();
|
||||
|
||||
@@ -40,7 +40,8 @@ package net.schmizz.sshj.userauth.method;
|
||||
* service requested. This method generally fails and is typically used to find out the method allowed by an SSH server
|
||||
* (sent as part of the {@code SSH_MSG_USERAUTH_FAILURE} packet)
|
||||
*/
|
||||
public class AuthNone extends AbstractAuthMethod {
|
||||
public class AuthNone
|
||||
extends AbstractAuthMethod {
|
||||
|
||||
AuthNone() {
|
||||
super("none");
|
||||
|
||||
@@ -45,7 +45,8 @@ import net.schmizz.sshj.userauth.password.PasswordFinder;
|
||||
import net.schmizz.sshj.userauth.password.Resource;
|
||||
|
||||
/** Implements the {@code password} authentication method. Password-change request handling is not currently supported. */
|
||||
public class AuthPassword extends AbstractAuthMethod {
|
||||
public class AuthPassword
|
||||
extends AbstractAuthMethod {
|
||||
|
||||
private final PasswordFinder pwdf;
|
||||
private Resource resource;
|
||||
@@ -63,7 +64,8 @@ public class AuthPassword extends AbstractAuthMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSHPacket buildReq() throws UserAuthException {
|
||||
public SSHPacket buildReq()
|
||||
throws UserAuthException {
|
||||
log.info("Requesting password for " + resource);
|
||||
char[] password = pwdf.reqPassword(resource);
|
||||
if (password == null)
|
||||
@@ -75,7 +77,8 @@ public class AuthPassword extends AbstractAuthMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Message cmd, SSHPacket buf) throws UserAuthException, TransportException {
|
||||
public void handle(Message cmd, SSHPacket buf)
|
||||
throws UserAuthException, TransportException {
|
||||
if (cmd == Message.USERAUTH_60)
|
||||
throw new UserAuthException("Password change request received; unsupported operation");
|
||||
else
|
||||
|
||||
@@ -51,7 +51,8 @@ import java.io.IOException;
|
||||
* request signed with the private key. Therefore, private keys are not requested from the associated {@link
|
||||
* KeyProvider} unless needed.
|
||||
*/
|
||||
public class AuthPublickey extends KeyedAuthMethod {
|
||||
public class AuthPublickey
|
||||
extends KeyedAuthMethod {
|
||||
|
||||
/** Initialize this method with the provider for public and private key. */
|
||||
public AuthPublickey(KeyProvider kProv) {
|
||||
@@ -60,7 +61,8 @@ public class AuthPublickey extends KeyedAuthMethod {
|
||||
|
||||
/** Internal use. */
|
||||
@Override
|
||||
public void handle(Message cmd, SSHPacket buf) throws UserAuthException, TransportException {
|
||||
public void handle(Message cmd, SSHPacket buf)
|
||||
throws UserAuthException, TransportException {
|
||||
if (cmd == Message.USERAUTH_60)
|
||||
sendSignedReq();
|
||||
else
|
||||
@@ -76,7 +78,8 @@ public class AuthPublickey extends KeyedAuthMethod {
|
||||
*
|
||||
* @throws UserAuthException
|
||||
*/
|
||||
private SSHPacket buildReq(boolean signed) throws UserAuthException {
|
||||
private SSHPacket buildReq(boolean signed)
|
||||
throws UserAuthException {
|
||||
try {
|
||||
kProv.getPublic();
|
||||
} catch (IOException ioe) {
|
||||
@@ -91,14 +94,16 @@ public class AuthPublickey extends KeyedAuthMethod {
|
||||
* @throws UserAuthException
|
||||
* @throws TransportException
|
||||
*/
|
||||
private void sendSignedReq() throws UserAuthException, TransportException {
|
||||
private void sendSignedReq()
|
||||
throws UserAuthException, TransportException {
|
||||
log.debug("Sending signed request");
|
||||
params.getTransport().write(putSig(buildReq(true)));
|
||||
}
|
||||
|
||||
/** Builds a feeler request (sans signature). */
|
||||
@Override
|
||||
protected SSHPacket buildReq() throws UserAuthException {
|
||||
protected SSHPacket buildReq()
|
||||
throws UserAuthException {
|
||||
return buildReq(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ import java.io.IOException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
public abstract class KeyedAuthMethod extends AbstractAuthMethod {
|
||||
public abstract class KeyedAuthMethod
|
||||
extends AbstractAuthMethod {
|
||||
protected KeyProvider kProv;
|
||||
|
||||
public KeyedAuthMethod(String name, KeyProvider kProv) {
|
||||
@@ -55,7 +56,8 @@ public abstract class KeyedAuthMethod extends AbstractAuthMethod {
|
||||
this.kProv = kProv;
|
||||
}
|
||||
|
||||
protected SSHPacket putPubKey(SSHPacket reqBuf) throws UserAuthException {
|
||||
protected SSHPacket putPubKey(SSHPacket reqBuf)
|
||||
throws UserAuthException {
|
||||
PublicKey key;
|
||||
try {
|
||||
key = kProv.getPublic();
|
||||
@@ -70,7 +72,8 @@ public abstract class KeyedAuthMethod extends AbstractAuthMethod {
|
||||
return reqBuf;
|
||||
}
|
||||
|
||||
protected SSHPacket putSig(SSHPacket reqBuf) throws UserAuthException {
|
||||
protected SSHPacket putSig(SSHPacket reqBuf)
|
||||
throws UserAuthException {
|
||||
PrivateKey key;
|
||||
try {
|
||||
key = kProv.getPrivate();
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
package net.schmizz.sshj.userauth.password;
|
||||
|
||||
public class AccountResource extends Resource<String> {
|
||||
public class AccountResource
|
||||
extends Resource<String> {
|
||||
|
||||
public AccountResource(String user, String host) {
|
||||
super(user + "@" + host);
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
package net.schmizz.sshj.userauth.password;
|
||||
|
||||
public class PrivateKeyFileResource extends Resource<String> {
|
||||
public class PrivateKeyFileResource
|
||||
extends Resource<String> {
|
||||
|
||||
public PrivateKeyFileResource(String path) {
|
||||
super(path);
|
||||
|
||||
Reference in New Issue
Block a user