class SFTPPublicKeyAuthentication implements AuthenticationProvider<Boolean> {

    @Override
    public Boolean authenticate(final Host bookmark, final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
        final Credentials credentials = bookmark.getCredentials();
        if(credentials.isPublicKeyAuthentication()) {
            if(log.isDebugEnabled()) {
                log.debug(String.format("Login using public key authentication with credentials %s", credentials));
            }
            final Local identity = credentials.getIdentity();
            final FileKeyProvider provider;
            final AtomicBoolean canceled = new AtomicBoolean();
            try {
                final KeyFormat format = KeyProviderUtil.detectKeyFileFormat(
                    new InputStreamReader(identity.getInputStream(), StandardCharsets.UTF_8), true);
                if(log.isInfoEnabled()) {
                    log.info(String.format("Reading private key %s with key format %s", identity, format));
                }
                switch(format) {
                    case PKCS5:
                        provider = new PKCS5KeyFile.Factory().create();
                        break;
                    case PKCS8:
                        provider = new PKCS8KeyFile.Factory().create();
                        break;
                    case OpenSSH:
                        provider = new OpenSSHKeyFile.Factory().create();
                        break;
                    case OpenSSHv1:
                        provider = new OpenSSHKeyV1KeyFile.Factory().create();
                        break;
                    case PuTTY:
                        provider = new PuTTYKeyFile.Factory().create();
                        break;
                    default:
                        throw new InteroperabilityException(String.format("Unknown key format for file %s", identity.getName()));
                }
                provider.init(new InputStreamReader(identity.getInputStream(), StandardCharsets.UTF_8), new PasswordFinder() {
                    @Override
                    public char[] reqPassword(Resource<?> resource) {
                        if(StringUtils.isEmpty(credentials.getIdentityPassphrase())) {
                            try {
                                // Use password prompt
                                final Credentials input = prompt.prompt(bookmark,
                                    LocaleFactory.localizedString("Private key password protected", "Credentials"),
                                    String.format("%s (%s)",
                                        LocaleFactory.localizedString("Enter the passphrase for the private key file", "Credentials"),
                                        identity.getAbbreviatedPath()),
                                    new LoginOptions()
                                        .icon(bookmark.getProtocol().disk())
                                        .user(false).password(true)
                                );
                                credentials.setSaved(input.isSaved());
                                credentials.setIdentityPassphrase(input.getPassword());
                            }
                            catch(LoginCanceledException e) {
                                canceled.set(true);
                                // Return null if user cancels
                                return StringUtils.EMPTY.toCharArray();
                            }
                        }
                        return credentials.getIdentityPassphrase().toCharArray();
                    }

                    @Override
                    public boolean shouldRetry(Resource<?> resource) {
                        return false;
                    }
                });
                session.getClient().auth(credentials.getUsername(), new AuthPublickey(provider));
                return session.getClient().isAuthenticated();
            }
            catch(IOException e) {
                if(canceled.get()) {
                    throw new LoginCanceledException();
                }
                throw new SFTPExceptionMappingService().map(e);
            }
        }
        return false;
    }

    public  SFTPPublicKeyAuthentication(final SFTPSession session);

}