Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3bd84de9 authored by cketti's avatar cketti Committed by GitHub
Browse files

Merge pull request #2144 from k9mail/GH-2134_authentication_failure_handling

Handle connection closing after authentication failure
parents 219b6272 f34abe36
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -465,6 +465,10 @@ class ImapConnection {
        try {
            saslAuthPlain();
        } catch (AuthenticationFailedException e) {
            if (!isConnected()) {
                throw e;
            }
            
            login();
        }
    }
@@ -486,6 +490,10 @@ class ImapConnection {
        try {
            extractCapabilities(responseParser.readStatusResponse(tag, command, getLogId(), null));
        } catch (NegativeImapResponseException e) {
            if (e.wasByeResponseReceived()) {
                close();
            }
            
            throw new AuthenticationFailedException(e.getMessage());
        }
    }
+1 −2
Original line number Diff line number Diff line
@@ -118,8 +118,7 @@ class ImapResponseParser {

        if (response.size() < 1 || !equalsIgnoreCase(response.get(0), Responses.OK)) {
            String message = "Command: " + commandToLog + "; response: " + response.toString();
            String alertText = AlertResponse.getAlertText(response);
            throw new NegativeImapResponseException(message, alertText);
            throw new NegativeImapResponseException(message, responses);
        }

        return responses;
+24 −3
Original line number Diff line number Diff line
package com.fsck.k9.mail.store.imap;

import java.util.List;

import com.fsck.k9.mail.MessagingException;

import static com.fsck.k9.mail.store.imap.ImapResponseParser.equalsIgnoreCase;


class NegativeImapResponseException extends MessagingException {
    private static final long serialVersionUID = 3725007182205882394L;

    private final String alertText;
    private final List<ImapResponse> responses;
    private String alertText;

    public NegativeImapResponseException(String message, String alertText) {
    public NegativeImapResponseException(String message, List<ImapResponse> responses) {
        super(message, true);
        this.alertText = alertText;
        this.responses = responses;
    }

    public String getAlertText() {
        if (alertText == null) {
            ImapResponse lastResponse = responses.get(responses.size() - 1);
            alertText = AlertResponse.getAlertText(lastResponse);
        }
        
        return alertText;
    }
    
    public boolean wasByeResponseReceived() {
        for (ImapResponse response : responses) {
            if (response.getTag() == null && response.size() >= 1 && equalsIgnoreCase(response.get(0), Responses.BYE)) {
                return true;
            }
        }
        
        return false;
    }
}
+26 −0
Original line number Diff line number Diff line
@@ -199,6 +199,32 @@ public class ImapConnectionTest {
        server.verifyInteractionCompleted();
    }

    @Test
    public void open_authPlainWithByeResponseAndConnectionClose_shouldThrowAuthenticationFailedException()
            throws Exception {
        settings.setAuthType(AuthType.PLAIN);
        MockImapServer server = new MockImapServer();
        preAuthenticationDialog(server, "AUTH=PLAIN");
        server.expect("2 AUTHENTICATE PLAIN");
        server.output("+");
        server.expect(ByteString.encodeUtf8("\000" + USERNAME + "\000" + PASSWORD).base64());
        server.output("* BYE Go away");
        server.output("2 NO Login Failure");
        server.closeConnection();
        ImapConnection imapConnection = startServerAndCreateImapConnection(server);

        try {
            imapConnection.open();
            fail("Expected exception");
        } catch (AuthenticationFailedException e) {
            //FIXME: improve exception message
            assertThat(e.getMessage(), containsString("Login Failure"));
        }

        server.verifyConnectionClosed();
        server.verifyInteractionCompleted();
    }

    @Test
    public void open_authPlainWithoutAuthPlainCapability_shouldUseLoginMethod() throws Exception {
        settings.setAuthType(AuthType.PLAIN);