Skip to content

Commit 6b61443

Browse files
committed
test(managesieve): test authentication of managesieve server
1 parent cbefbaa commit 6b61443

File tree

9 files changed

+1130
-1
lines changed

9 files changed

+1130
-1
lines changed

server/protocols/jwt/src/test/java/org/apache/james/jwt/OidcTokenFixture.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public class OidcTokenFixture {
107107
"}";
108108

109109
public static final String CLAIM = "email_address";
110-
// "email_address": "[email protected]"
110+
public static final String USER_EMAIL_ADDRESS = "[email protected]";
111111
public static final String VALID_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Inc4MFBzNUlhc24tYUdXbXcyVHJ4RGlOY2FocEgyc1h6NXBxZGhBbDlIWGMifQ.eyJleHAiOjM5Mzk1MDYxNjcsImlhdCI6MTYzOTUwNTg2NywiYXV0aF90aW1lIjozNjM5NTA1ODQxLCJqdGkiOiJjMjQ5ZTBkNi1jY2JiLTRmZDAtODI5Yi04OTM1MjczN2YzZGIiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvcmVhbG0xIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjIwNDUyNzFiLWMxYmItNDJiOC1hMTkwLThlYWI1MmYzYmEwOSIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQtY29uc29sZSIsIm5vbmNlIjoiNWUyOGJjNTAtODE5NS00NjM3LThmMWEtYWUzNWFlYTk0NTc1Iiwic2Vzc2lvbl9zdGF0ZSI6ImMxYzI3MmYwLWMwMjAtNGZmMC1hMzYwLTQ3MGJlYWVlNWUwMCIsImFjciI6IjAiLCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSIsInNpZCI6ImMxYzI3MmYwLWMwMjAtNGZmMC1hMzYwLTQ3MGJlYWVlNWUwMCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoiamFtZXMiLCJlbWFpbF9hZGRyZXNzIjoidXNlckBkb21haW4ub3JnIn0.bqHsX3yngXwXyVW7LenKzHbdqZy1AmCjE3QWrp7Y1sd_zcQEu5WABwLIOAzrXiNFeGwyww8taGJBdYa0KTBCY6MYkAHAEa1vyyO1LfJgr3cIfQT6WCf3g2BJqHRjUsqNgT_Sit9druMRke01m1V0EmzqIdLLHp8Vl-u4R3JSDx1bsQ1w3WCRlcgr_k3EJ7jNiuNnklCH8_o59y4c7Rzdpl-Y8tcA07nGjeJ_7qPgNZX6lgwvr0EhpQpbVDHXwQlp2NDzkWwBLJR0-V50Q0a-L0QD69wqeEaqi1xaRAfx2Gwn2FgCgMUWzKeW_qkEBP0tnN-pzl7j31EOnmKhshlOtw";
112112
public static final String VALID_TOKEN_HAS_NOT_KID = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjM5Mzk1MDYxNjcsImlhdCI6MTYzOTUwNTg2NywiYXV0aF90aW1lIjozNjM5NTA1ODQxLCJqdGkiOiJjMjQ5ZTBkNi1jY2JiLTRmZDAtODI5Yi04OTM1MjczN2YzZGIiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvcmVhbG0xIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjIwNDUyNzFiLWMxYmItNDJiOC1hMTkwLThlYWI1MmYzYmEwOSIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQtY29uc29sZSIsIm5vbmNlIjoiNWUyOGJjNTAtODE5NS00NjM3LThmMWEtYWUzNWFlYTk0NTc1Iiwic2Vzc2lvbl9zdGF0ZSI6ImMxYzI3MmYwLWMwMjAtNGZmMC1hMzYwLTQ3MGJlYWVlNWUwMCIsImFjciI6IjAiLCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSIsInNpZCI6ImMxYzI3MmYwLWMwMjAtNGZmMC1hMzYwLTQ3MGJlYWVlNWUwMCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoiamFtZXMiLCJlbWFpbF9hZGRyZXNzIjoidXNlckBkb21haW4ub3JnIn0.GR0Xi0de9_G_PyX4f3oj-_VWAIiae0UAOvFJZT3Jy3hqh2gFxC83PmCNKYXMVg8VXfdEHJRqjF4-swqVRGJGGlrz7C-0-sBh4geoh5HIPw4nSfQsdr2NS9IBPFurJjBJqf2u0VM9lZdvRnameFGZasSv0Ob6tnm4oLcL3MfFK5AO9NQslrV7RUCPgjF6B7FFoimvXp1dPYfL_6L_yQeyscroIWxmkcheXSA-yRf5jdmn3MTFfpvrBi-VT8HEueJSkk5HjU7PlMUesaZG07B98Q4eN8CmsKhQNDf__DMCRuVhUstcNbWXk0z_loEHARjnBDTl74cm6yVLI2mMYtrHkg";
113113
public static final String VALID_TOKEN_HAS_NOT_FOUND_KID = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im5vdEZvdW5kIn0.eyJleHAiOjM5Mzk1MDYxNjcsImlhdCI6MTYzOTUwNTg2NywiYXV0aF90aW1lIjozNjM5NTA1ODQxLCJqdGkiOiJjMjQ5ZTBkNi1jY2JiLTRmZDAtODI5Yi04OTM1MjczN2YzZGIiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvcmVhbG0xIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjIwNDUyNzFiLWMxYmItNDJiOC1hMTkwLThlYWI1MmYzYmEwOSIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQtY29uc29sZSIsIm5vbmNlIjoiNWUyOGJjNTAtODE5NS00NjM3LThmMWEtYWUzNWFlYTk0NTc1Iiwic2Vzc2lvbl9zdGF0ZSI6ImMxYzI3MmYwLWMwMjAtNGZmMC1hMzYwLTQ3MGJlYWVlNWUwMCIsImFjciI6IjAiLCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSIsInNpZCI6ImMxYzI3MmYwLWMwMjAtNGZmMC1hMzYwLTQ3MGJlYWVlNWUwMCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoiamFtZXMiLCJlbWFpbF9hZGRyZXNzIjoidXNlckBkb21haW4ub3JnIn0.dgcqfAhyUxw1nLgqojWjrFzxjJaJX-xGpb2kMPe_3fbTBauXndI5y1CMyxvG9yA3BevijqdUOZ5s6oLAJc_1qQ45KYf7Oh3jiNpw3CcDk4cLnap5NbdsiDHM10HrJl7qbaUVa1-YljloGMk6qbYRjM_UKYyfRDHbqkPnMhyGQuG_4oSjuQMOXhCDvXUSfjpP20efQxFoZA7A5MDPd0YXs2UxGR1Hg6POW9zNZkH4XQms0SXfxY87tnt7ETN11t9xB3i1XrYOjts7rwRfnu3eXTcFQQhWd14hm9b-_DwMisfvPNrIAHIrY_dCvmOe87ekHL-5VYMaB8x5g_gjQUaUsw";

server/protocols/protocols-managesieve/pom.xml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,42 @@
1313
<name>Apache James :: Server :: ManageSieve</name>
1414

1515
<dependencies>
16+
<dependency>
17+
<groupId>${james.groupId}</groupId>
18+
<artifactId>james-server-data-file</artifactId>
19+
<scope>test</scope>
20+
</dependency>
21+
<dependency>
22+
<groupId>${james.groupId}</groupId>
23+
<artifactId>james-server-data-memory</artifactId>
24+
<scope>test</scope>
25+
</dependency>
26+
<dependency>
27+
<groupId>${james.groupId}</groupId>
28+
<artifactId>james-server-filesystem-api</artifactId>
29+
</dependency>
1630
<dependency>
1731
<groupId>${james.groupId}</groupId>
1832
<artifactId>james-server-filesystem-api</artifactId>
33+
<type>test-jar</type>
34+
<scope>test</scope>
35+
</dependency>
36+
<dependency>
37+
<groupId>${james.groupId}</groupId>
38+
<artifactId>james-server-jwt</artifactId>
39+
<type>test-jar</type>
40+
<scope>test</scope>
1941
</dependency>
2042
<dependency>
2143
<groupId>${james.groupId}</groupId>
2244
<artifactId>james-server-protocols-library</artifactId>
2345
</dependency>
46+
<dependency>
47+
<groupId>${james.groupId}</groupId>
48+
<artifactId>james-server-protocols-library</artifactId>
49+
<type>test-jar</type>
50+
<scope>test</scope>
51+
</dependency>
2452
<dependency>
2553
<groupId>${james.groupId}</groupId>
2654
<artifactId>james-server-util</artifactId>
@@ -30,6 +58,16 @@
3058
<artifactId>testing-base</artifactId>
3159
<scope>test</scope>
3260
</dependency>
61+
<dependency>
62+
<groupId>${james.protocols.groupId}</groupId>
63+
<artifactId>protocols-api</artifactId>
64+
</dependency>
65+
<dependency>
66+
<groupId>${james.protocols.groupId}</groupId>
67+
<artifactId>protocols-api</artifactId>
68+
<type>test-jar</type>
69+
<scope>test</scope>
70+
</dependency>
3371
<dependency>
3472
<groupId>${james.protocols.groupId}</groupId>
3573
<artifactId>protocols-managesieve</artifactId>
@@ -38,6 +76,11 @@
3876
<groupId>${james.protocols.groupId}</groupId>
3977
<artifactId>protocols-netty</artifactId>
4078
</dependency>
79+
<dependency>
80+
<groupId>commons-net</groupId>
81+
<artifactId>commons-net</artifactId>
82+
<scope>test</scope>
83+
</dependency>
4184
<dependency>
4285
<groupId>io.netty</groupId>
4386
<artifactId>netty-handler</artifactId>
@@ -54,6 +97,16 @@
5497
<groupId>org.apache.commons</groupId>
5598
<artifactId>commons-configuration2</artifactId>
5699
</dependency>
100+
<dependency>
101+
<groupId>org.apache.commons</groupId>
102+
<artifactId>commons-lang3</artifactId>
103+
<scope>test</scope>
104+
</dependency>
105+
<dependency>
106+
<groupId>org.mock-server</groupId>
107+
<artifactId>mockserver-netty</artifactId>
108+
<scope>test</scope>
109+
</dependency>
57110
<dependency>
58111
<groupId>org.slf4j</groupId>
59112
<artifactId>jcl-over-slf4j</artifactId>
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/****************************************************************
2+
* Licensed to the Apache Software Foundation (ASF) under one *
3+
* or more contributor license agreements. See the NOTICE file *
4+
* distributed with this work for additional information *
5+
* regarding copyright ownership. The ASF licenses this file *
6+
* to you under the Apache License, Version 2.0 (the *
7+
* "License"); you may not use this file except in compliance *
8+
* with the License. You may obtain a copy of the License at *
9+
* *
10+
* http://www.apache.org/licenses/LICENSE-2.0 *
11+
* *
12+
* Unless required by applicable law or agreed to in writing, *
13+
* software distributed under the License is distributed on an *
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15+
* KIND, either express or implied. See the License for the *
16+
* specific language governing permissions and limitations *
17+
* under the License. *
18+
****************************************************************/
19+
20+
package org.apache.james.managesieveserver;
21+
22+
import java.io.IOException;
23+
import java.nio.charset.StandardCharsets;
24+
import java.util.Base64;
25+
26+
import org.assertj.core.api.Assertions;
27+
import org.junit.jupiter.api.AfterEach;
28+
import org.junit.jupiter.api.BeforeEach;
29+
import org.junit.jupiter.api.Disabled;
30+
import org.junit.jupiter.api.Test;
31+
32+
public class AuthenticateTest {
33+
private ManageSieveClient client;
34+
private final ManageSieveServerTestSystem testSystem;
35+
36+
public AuthenticateTest() throws Exception {
37+
this.testSystem = new ManageSieveServerTestSystem();
38+
}
39+
40+
@BeforeEach
41+
void setUp() throws Exception {
42+
this.testSystem.setUp();
43+
this.client = new ManageSieveClient();
44+
this.client.connect(this.testSystem.getBindedIP(), this.testSystem.getBindedPort());
45+
this.client.readResponse();
46+
}
47+
48+
@AfterEach
49+
void tearDown() {
50+
this.testSystem.manageSieveServer.destroy();
51+
}
52+
53+
@Test
54+
void plainLoginWithCorrectCredentialsShouldSucceed() throws IOException {
55+
this.authenticatePlain();
56+
}
57+
58+
@Test
59+
void plainLoginWithWrongPasswordShouldNotSucceed() throws IOException {
60+
String initialClientResponse = ("\0" + ManageSieveServerTestSystem.USERNAME.asString() + "\0" + ManageSieveServerTestSystem.PASSWORD + "wrong");
61+
this.client.sendCommand("AUTHENTICATE \"PLAIN\" \"" + Base64.getEncoder().encodeToString(initialClientResponse.getBytes(StandardCharsets.UTF_8)) + "\"");
62+
ManageSieveClient.ServerResponse authenticationResponse = this.client.readResponse();
63+
Assertions.assertThat(authenticationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.NO);
64+
}
65+
66+
@Test
67+
void plainLoginWithNotExistingUserShouldNotSucceed() throws IOException {
68+
String initialClientResponse = ("\0" + ManageSieveServerTestSystem.USERNAME.asString() + "not-existing" + "\0" + "pwd");
69+
this.client.sendCommand("AUTHENTICATE \"PLAIN\" \"" + Base64.getEncoder().encodeToString(initialClientResponse.getBytes(StandardCharsets.UTF_8)) + "\"");
70+
ManageSieveClient.ServerResponse authenticationResponse = this.client.readResponse();
71+
Assertions.assertThat(authenticationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.NO);
72+
}
73+
74+
@Test
75+
void plainLoginWithoutPasswordShouldNotSucceed() throws IOException {
76+
String initialClientResponse = ("\0" + ManageSieveServerTestSystem.USERNAME.asString() + "\0");
77+
this.client.sendCommand("AUTHENTICATE \"PLAIN\" \"" + Base64.getEncoder().encodeToString(initialClientResponse.getBytes(StandardCharsets.UTF_8)) + "\"");
78+
ManageSieveClient.ServerResponse authenticationResponse = this.client.readResponse();
79+
Assertions.assertThat(authenticationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.NO);
80+
}
81+
82+
// The SASL PLAIN standard (https://datatracker.ietf.org/doc/html/rfc4616) defines the following message:
83+
// message = [authzid] UTF8NUL authcid UTF8NUL passwd
84+
// The current code is more lenient.
85+
@Disabled
86+
@Test
87+
void plainLoginWithMalformedMessageShouldNotSucceed() throws IOException {
88+
String initialClientResponse = (ManageSieveServerTestSystem.USERNAME.asString() + "\0" + ManageSieveServerTestSystem.PASSWORD);
89+
this.client.sendCommand("AUTHENTICATE \"PLAIN\" \"" + Base64.getEncoder().encodeToString(initialClientResponse.getBytes(StandardCharsets.UTF_8)) + "\"");
90+
ManageSieveClient.ServerResponse authenticationResponse = this.client.readResponse();
91+
Assertions.assertThat(authenticationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.NO);
92+
}
93+
94+
@Test
95+
void plainLoginWithoutMechanismQuotesShouldNotSucceed() throws IOException {
96+
String initialClientResponse = ("\0" + ManageSieveServerTestSystem.USERNAME.asString() + "\0" + ManageSieveServerTestSystem.PASSWORD);
97+
this.client.sendCommand("AUTHENTICATE PLAIN \"" + Base64.getEncoder().encodeToString(initialClientResponse.getBytes(StandardCharsets.UTF_8)) + "\"");
98+
ManageSieveClient.ServerResponse authenticationResponse = this.client.readResponse();
99+
Assertions.assertThat(authenticationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.NO);
100+
}
101+
102+
@Test
103+
void plainLoginWithoutInitialResponseQuotesShouldNotSucceed() throws IOException {
104+
String initialClientResponse = ("\0" + ManageSieveServerTestSystem.USERNAME.asString() + "\0" + ManageSieveServerTestSystem.PASSWORD);
105+
this.client.sendCommand("AUTHENTICATE \"PLAIN\" " + Base64.getEncoder().encodeToString(initialClientResponse.getBytes(StandardCharsets.UTF_8)));
106+
ManageSieveClient.ServerResponse authenticationResponse = this.client.readResponse();
107+
Assertions.assertThat(authenticationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.NO);
108+
}
109+
110+
@Test
111+
void plainLoginWithContinuationShouldSucceed() throws IOException {
112+
this.client.sendCommand("AUTHENTICATE \"PLAIN\"");
113+
ManageSieveClient.ServerResponse continuationResponse = this.client.readResponse();
114+
Assertions.assertThat(continuationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.OK);
115+
Assertions.assertThat(continuationResponse.responseLines()).containsExactly("\"\"");
116+
117+
String initialClientResponse = ("\0" + ManageSieveServerTestSystem.USERNAME.asString() + "\0" + ManageSieveServerTestSystem.PASSWORD);
118+
this.client.sendCommand("\"" + Base64.getEncoder().encodeToString(initialClientResponse.getBytes(StandardCharsets.UTF_8)) + "\"");
119+
ManageSieveClient.ServerResponse authenticationResponse = this.client.readResponse();
120+
Assertions.assertThat(authenticationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.OK);
121+
}
122+
123+
@Test
124+
void plainLoginWithContinuationCanBeAborted() throws IOException {
125+
this.client.sendCommand("AUTHENTICATE \"PLAIN\"");
126+
ManageSieveClient.ServerResponse continuationResponse = this.client.readResponse();
127+
Assertions.assertThat(continuationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.OK);
128+
Assertions.assertThat(continuationResponse.responseLines()).containsExactly("\"\"");
129+
130+
this.client.sendCommand("\"*\"");
131+
ManageSieveClient.ServerResponse authenticationResponse = this.client.readResponse();
132+
Assertions.assertThat(authenticationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.NO);
133+
Assertions.assertThat(authenticationResponse.explanation()).get().isEqualTo("authentication aborted");
134+
}
135+
136+
@Test
137+
void doubleAuthenticationShouldFail() throws IOException {
138+
String initialClientResponse = ("\0" + ManageSieveServerTestSystem.USERNAME.asString() + "\0" + ManageSieveServerTestSystem.PASSWORD);
139+
String command = "AUTHENTICATE \"PLAIN\" \"" + Base64.getEncoder().encodeToString(initialClientResponse.getBytes(StandardCharsets.UTF_8)) + "\"";
140+
141+
this.client.sendCommand(command);
142+
ManageSieveClient.ServerResponse firstAuthenticationResponse = this.client.readResponse();
143+
Assertions.assertThat(firstAuthenticationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.OK);
144+
145+
this.client.sendCommand(command);
146+
ManageSieveClient.ServerResponse secondAuthenticationResponse = this.client.readResponse();
147+
Assertions.assertThat(secondAuthenticationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.NO);
148+
Assertions.assertThat(secondAuthenticationResponse.explanation()).get().isEqualTo("already authenticated");
149+
}
150+
151+
@Test
152+
void unauthenticateInUnauthenticatedStateShouldFail() throws IOException {
153+
this.client.sendCommand("UNAUTHENTICATE");
154+
ManageSieveClient.ServerResponse response = this.client.readResponse();
155+
Assertions.assertThat(response.responseType()).isEqualTo(ManageSieveClient.ResponseType.NO);
156+
}
157+
158+
@Test
159+
void unauthenticateInAuthenticatedStateShouldSucceed() throws IOException {
160+
this.authenticatePlain();
161+
162+
this.client.sendCommand("UNAUTHENTICATE");
163+
ManageSieveClient.ServerResponse response = this.client.readResponse();
164+
Assertions.assertThat(response.responseType()).isEqualTo(ManageSieveClient.ResponseType.OK);
165+
}
166+
167+
@Test
168+
void authenticatedStateUnlocksNewCommands() throws IOException {
169+
this.client.sendCommand("LISTSCRIPTS");
170+
ManageSieveClient.ServerResponse unauthenticatedResponse = this.client.readResponse();
171+
Assertions.assertThat(unauthenticatedResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.NO);
172+
173+
this.authenticatePlain();
174+
175+
this.client.sendCommand("LISTSCRIPTS");
176+
ManageSieveClient.ServerResponse authenticatedResponse = this.client.readResponse();
177+
Assertions.assertThat(authenticatedResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.OK);
178+
179+
this.client.sendCommand("UNAUTHENTICATE");
180+
ManageSieveClient.ServerResponse response = this.client.readResponse();
181+
Assertions.assertThat(response.responseType()).isEqualTo(ManageSieveClient.ResponseType.OK);
182+
183+
this.client.sendCommand("LISTSCRIPTS");
184+
ManageSieveClient.ServerResponse loggedOutResponse = this.client.readResponse();
185+
Assertions.assertThat(loggedOutResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.NO);
186+
}
187+
188+
@Test
189+
void logoutShouldWorkInUnauthenticatedState() throws IOException, InterruptedException {
190+
this.client.sendCommand("LOGOUT");
191+
ManageSieveClient.ServerResponse response = this.client.readResponse();
192+
Assertions.assertThat(response.responseType()).isEqualTo(ManageSieveClient.ResponseType.OK);
193+
Assertions.assertThat(this.client.isConnected()).isFalse();
194+
}
195+
196+
@Test
197+
void logoutShouldWorkInAuthenticatedState() throws IOException, InterruptedException {
198+
this.authenticatePlain();
199+
200+
this.client.sendCommand("LOGOUT");
201+
ManageSieveClient.ServerResponse response = this.client.readResponse();
202+
Assertions.assertThat(response.responseType()).isEqualTo(ManageSieveClient.ResponseType.OK);
203+
Assertions.assertThat(this.client.isConnected()).isFalse();
204+
}
205+
206+
void authenticatePlain() throws IOException {
207+
String initialClientResponse = ("\0" + ManageSieveServerTestSystem.USERNAME.asString() + "\0" + ManageSieveServerTestSystem.PASSWORD);
208+
this.client.sendCommand("AUTHENTICATE \"PLAIN\" \"" + Base64.getEncoder().encodeToString(initialClientResponse.getBytes(StandardCharsets.UTF_8)) + "\"");
209+
ManageSieveClient.ServerResponse authenticationResponse = this.client.readResponse();
210+
Assertions.assertThat(authenticationResponse.responseType()).isEqualTo(ManageSieveClient.ResponseType.OK);
211+
}
212+
}

0 commit comments

Comments
 (0)