14
votes

I'm trying to authenticate a signature that clients generate from their private key and send to the server.

The only authenticator I could find in the library that sounded appropriate was the PublickeyAuthenticator. Please correct me if this is the wrong class to do this.

I currently have:

this.sshServer.setPublickeyAuthenticator(new PublickeyAuthenticator() {
                @Override
                public boolean authenticate(String username, PublicKey key, ServerSession session) {
                    if (username.equals("client")) {
                         //if signature == valid??
                         return true;
                    }
                }
            });

Does anyone know if mina supports signature verification and if so, how can it be implemented?

My understanding is that I'd first have to assign/add the user public key to the server. If the client has provided a id_rsa.pub file, how can I go about adding this file to the server as the public key?

1

1 Answers

6
votes

Mina SSH has a few implementations of PublickeyAuthenticator.
Look at org.apache.sshd.server.config.keys.AuthorizedKeysAuthenticator and org.apache.sshd.server.auth.pubkey.KeySetPublickeyAuthenticator.
Implementations of PublickeyAuthenticator only check that the given public key is associated with the user.
The actual verification of the signature is handled internally to MINA SSH after the authentication.
The AuthorizedKeysAuthenticator only supports one user(it doesnt check the username), but you could for example just point it at your id_rsa.pub file and it should work.

this.sshServer.setPublickeyAuthenticator(
    new AuthorizedKeysAuthenticator(new File("id_rsa.pub"));

You could write your own PublicKeyAuthenticator that checks the keys against a map of users like so:

public class UserKeySetPublickeyAuthenticator implements PublickeyAuthenticator {
    private final Map<String, Collection<? extends PublicKey>> userToKeySet;

    public UserKeySetPublickeyAuthenticator(Map<String, Collection<? extends PublicKey>> userToKeySet) {
        this.userToKeySet = userToKeySet;
    }

    @Override
    public boolean authenticate(String username, PublicKey key, ServerSession session) {
        return KeyUtils.findMatchingKey(key, userToKeySet.getOrDefault(username, Collections.emptyList())) != null;
    }

}

You need to write some code to populate the map with your key data. AuthorizedKeyEntry has utility methods for doing this from files, inputstreams or strings.
An example of reading from user named authorized key files:

Map<String, List<PublicKey>> userKeysMap = new HashMap<>();
List<String> users = Arrays.asList("Jim", "Sally", "Bob");
for(String user : users){
    List<PublicKey> usersKeys = new ArrayList<>();
    for(AuthorizedKeyEntry ake : AuthorizedKeyEntry.readAuthorizedKeys(new File(user + "_authorized_keys"))){
        PublicKey publicKey = ake.resolvePublicKey(PublicKeyEntryResolver.IGNORING);
        if(publicKey != null){
            usersKeys.add(publicKey);
        }
    }
    userKeysMap.put(user, usersKeys);
}