@Override
    public boolean authenticate(final ProxyFinder proxy, final Session session, final ProgressListener listener,
                                final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
        final Host bookmark = session.getHost();
        final Credentials credentials = bookmark.getCredentials();
        listener.message(MessageFormat.format(LocaleFactory.localizedString("Authenticating as {0}", "Status"),
                StringUtils.isNotBlank(credentials.getUsername()) ? credentials.getUsername() : LocaleFactory.localizedString("Unknown")));
        try {
            if(log.isDebugEnabled()) {
                log.debug(String.format("Attempt authentication for %s", session));
            }
            session.login(prompt, cancel);
            if(log.isDebugEnabled()) {
                log.debug(String.format("Login successful for %s", session));
            }
            listener.message(LocaleFactory.localizedString("Login successful", "Credentials"));
            this.save(bookmark);
            return true;
        }
        catch(LoginFailureException e) {
            if(log.isDebugEnabled()) {
                log.debug(String.format("Login failed for %s", session));
            }
            listener.message(LocaleFactory.localizedString("Login failed", "Credentials"));
            credentials.setPassed(false);
            final LoginOptions options = new LoginOptions(bookmark.getProtocol());
            if(this.prompt(bookmark, e.getDetail(), prompt, options)) {
                // Retry
                return false;
            }
            if(log.isDebugEnabled()) {
                log.debug(String.format("Reset credentials for %s", bookmark));
            }
            // No updated credentials. Nullify input
            switch(session.getHost().getProtocol().getStatefulness()) {
                case stateless:
                    credentials.reset();
            }
            throw e;
        }
    }
@Test(expected = LoginCanceledException.class)
    public void testMessages() throws Exception {
        final Host host = new Host(new TestProtocol(), "test.cyberduck.ch", new Credentials(
            PreferencesFactory.get().getProperty("connection.login.anon.name"), null
        ));
        host.setDefaultPath("/dav/basic");
        final Session session = new NullSession(host) {
            @Override
            public void login(final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
                throw new LoginCanceledException();
            }
        };
        session.open(new DisabledProxyFinder(), new DisabledHostKeyCallback(), new DisabledLoginCallback(), new DisabledCancelCallback());
        LoginService l = new KeychainLoginService(new DisabledPasswordStore());
        l.authenticate(new DisabledProxyFinder(), session, new ProgressListener() {
            int i = 0;

            @Override
            public void message(final String message) {
                if(0 == i) {
                    assertEquals("Authenticating as anonymous", message);
                }
                else if(1 == i) {
                    assertEquals("Login failed", message);
                }
                else {
                    fail();
                }
                i++;
            }
        }, new DisabledLoginCallback(), new DisabledCancelCallback());
    }